From fd4026f27af5c688ac9e80bb3127068702f68ff9 Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Mon, 26 Aug 2024 21:43:25 +0530 Subject: [PATCH 001/275] [doc] Update information about lost password + recovery key --- docs/docs/photos/faq/security-and-privacy.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/docs/photos/faq/security-and-privacy.md b/docs/docs/photos/faq/security-and-privacy.md index 51839e0325..306f167483 100644 --- a/docs/docs/photos/faq/security-and-privacy.md +++ b/docs/docs/photos/faq/security-and-privacy.md @@ -57,11 +57,15 @@ in the unlikely event of a server breach, your data remains protected. ### What happens if I forget my password? -You can reset your password using your recovery key. This key is a randomly -generated string provided to you during account creation. Store it securely, as -it's your lifeline if you forget your password. If you lose both your password -and recovery key, we cannot recover your account or data due to our -zero-knowledge architecture. +You can reset your password using your recovery key that was provided to you +during account creation. Please store this key securely, as it's your lifeline +if you forget your password. + +If you lose both your password and recovery key, we cannot recover your account +or data due to our end-to-end encrypted architecture. + +If you wish to delete your account in such scenarios, please reach out to +support@ente.io and we will help you out. ### Can I change my password? From 8813b0cf1c0458c7f2c94f59c289964ffb4828c7 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Mon, 26 Aug 2024 21:50:04 +0530 Subject: [PATCH 002/275] [meta] Run PRs lint checks for pull requests from external forks Currently, for PRs opened by external contributors, the various lint checks don't run (sometimes causing code that fails basic lint checks to be committed to main). From my current understanding (I find the docs around this confusing), we need to instead use the "pull_request" target. Refs: * https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request * https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/ Note that even then, we will need a manual step to approve running the lints for first time contributors. Which is fine, at least we'll see the option, unlike right now where they just can't be run until the code hits main. --- .github/workflows/auth-lint.yml | 5 ++--- .github/workflows/desktop-lint.yml | 5 ++--- .github/workflows/docs-verify-build.yml | 5 ++--- .github/workflows/infra-lint-staff.yml | 5 ++--- .github/workflows/mobile-lint.yml | 5 ++--- .github/workflows/server-lint.yml | 5 ++--- .github/workflows/web-lint.yml | 5 ++--- 7 files changed, 14 insertions(+), 21 deletions(-) diff --git a/.github/workflows/auth-lint.yml b/.github/workflows/auth-lint.yml index b3b302a32e..4518c542da 100644 --- a/.github/workflows/auth-lint.yml +++ b/.github/workflows/auth-lint.yml @@ -1,9 +1,8 @@ name: "Lint (auth)" on: - # Run on every push to a branch other than main that changes auth/ - push: - branches-ignore: [main] + # Run on every pull request (open or push to it) that changes auth/ + pull_request: paths: - "auth/**" - ".github/workflows/auth-lint.yml" diff --git a/.github/workflows/desktop-lint.yml b/.github/workflows/desktop-lint.yml index d1cfda884d..0c24a081ff 100644 --- a/.github/workflows/desktop-lint.yml +++ b/.github/workflows/desktop-lint.yml @@ -1,9 +1,8 @@ name: "Lint (desktop)" on: - # Run on every push to a branch other than main that changes desktop/ - push: - branches-ignore: [main] + # Run on every pull request (open or push to it) that changes desktop/ + pull_request: paths: - "desktop/**" - ".github/workflows/desktop-lint.yml" diff --git a/.github/workflows/docs-verify-build.yml b/.github/workflows/docs-verify-build.yml index addb52a059..e07f9f973f 100644 --- a/.github/workflows/docs-verify-build.yml +++ b/.github/workflows/docs-verify-build.yml @@ -4,9 +4,8 @@ name: "Verify build (docs)" # succeeding before we merge the PR into main. on: - # Run on every push to a branch other than main that changes docs/ - push: - branches-ignore: [main] + # Run on every pull request (open or push to it) that changes docs/ + pull_request: paths: - "docs/**" - ".github/workflows/docs-verify-build.yml" diff --git a/.github/workflows/infra-lint-staff.yml b/.github/workflows/infra-lint-staff.yml index 5c2894281e..3f3612bd04 100644 --- a/.github/workflows/infra-lint-staff.yml +++ b/.github/workflows/infra-lint-staff.yml @@ -1,9 +1,8 @@ name: "Lint (staff)" on: - # Run on every push to a branch other than main that changes infra/staff/ - push: - branches-ignore: [main] + # Run on every pull request (open or push to it) that changes infra/staff/ + pull_request: paths: - "infra/staff/**" - ".github/workflows/infra-deploy-staff.yml" diff --git a/.github/workflows/mobile-lint.yml b/.github/workflows/mobile-lint.yml index 59bfcbbf67..0a57c0b30b 100644 --- a/.github/workflows/mobile-lint.yml +++ b/.github/workflows/mobile-lint.yml @@ -1,9 +1,8 @@ name: "Lint (mobile)" on: - # Run on every push to a branch other than main that changes mobile/ - push: - branches-ignore: [main, f-droid] + # Run on every pull request (open or push to it) that changes mobile/ + pull_request: paths: - "mobile/**" - ".github/workflows/mobile-lint.yml" diff --git a/.github/workflows/server-lint.yml b/.github/workflows/server-lint.yml index 3b0cbc855f..2f126899ff 100644 --- a/.github/workflows/server-lint.yml +++ b/.github/workflows/server-lint.yml @@ -1,9 +1,8 @@ name: "Lint (server)" on: - # Run on every push to a branch other than main that changes server/ - push: - branches-ignore: [main] + # Run on every pull request (open or push to it) that changes server/ + pull_request: paths: - "server/**" - ".github/workflows/server-lint.yml" diff --git a/.github/workflows/web-lint.yml b/.github/workflows/web-lint.yml index 7f5d270029..c64463384c 100644 --- a/.github/workflows/web-lint.yml +++ b/.github/workflows/web-lint.yml @@ -1,9 +1,8 @@ name: "Lint (web)" on: - # Run on every push to a branch other than main that changes web/ - push: - branches-ignore: [main] + # Run on every pull request (open or push to it) that changes web/ + pull_request: paths: - "web/**" - ".github/workflows/web-lint.yml" From 2f0cef6ab9d8593607fe1c4d594271ff99b7413e Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Mon, 26 Aug 2024 22:32:44 +0530 Subject: [PATCH 003/275] [docs] Add FAQ --- docs/docs/photos/faq/subscription.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/docs/photos/faq/subscription.md b/docs/docs/photos/faq/subscription.md index 56724fe3eb..99302437aa 100644 --- a/docs/docs/photos/faq/subscription.md +++ b/docs/docs/photos/faq/subscription.md @@ -137,6 +137,29 @@ upgrade to the 200 GB yearly plan, then The same applies to monthly plans. +## What happens when I downgrade my plan? + +Your new plan will go into effect immediately. Any extra amount you have paid +will be credited to your account. This credit will be discounted from your +future invoices. + +For example, if you are half way through the year on the 200 GB yearly plan, and +downgrade to the 50 GB yearly plan, then + +- The new 50 GB yearly plan will go into effect immediately. + +- We will calculate a credit by subtracting half the price of the 50 GB plan + from half the price of the 200 GB plan. This will be credited to your + account. + +- This credited amount will be discounted from your next invoice, which will + be due in half a year. + +The same applies to monthly plans. + +If you prefer to have this credit refunded to your original payment method, +please contact support@ente.io, and we'll assist you. + ## Is there an x GB plan? We have experimented quite a bit and have found it hard to design a single From 8f5f1a22ee1563c32a117d8b45491d198e35f80c Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Mon, 26 Aug 2024 20:28:42 +0530 Subject: [PATCH 004/275] [auth] Fix Aegis import without group --- auth/lib/ui/settings/data/import/aegis_import.dart | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/auth/lib/ui/settings/data/import/aegis_import.dart b/auth/lib/ui/settings/data/import/aegis_import.dart index 2360adb723..cf2567ebe4 100644 --- a/auth/lib/ui/settings/data/import/aegis_import.dart +++ b/auth/lib/ui/settings/data/import/aegis_import.dart @@ -129,8 +129,10 @@ Future _processAegisExportFile( } final Map groupIDToName = {}; try { - for (var item in aegisDB?['groups']) { - groupIDToName[item['uuid']] = item['name']; + if (aegisDB?['groups'] != null) { + for (var item in aegisDB?['groups']) { + groupIDToName[item['uuid']] = item['name']; + } } } catch (e) { Logger("AegisImport").warning("Failed to parse groups", e); @@ -149,9 +151,11 @@ Future _processAegisExportFile( var digits = item['info']['digits']; var counter = item['info']['counter']; - for (var group in item['groups']) { - if (groupIDToName.containsKey(group)) { - tags.add(groupIDToName[group]!); + if (item['groups'] != null) { + for (var group in item['groups']) { + if (groupIDToName.containsKey(group)) { + tags.add(groupIDToName[group]!); + } } } // Build the OTP URL From 248d8e09a9384fb4dafc599f58d98300023a0ade Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 09:46:53 +0530 Subject: [PATCH 005/275] [desktop] Create ffmpeg universal binaries for macOS Tested locally, still need to run it as a GitHub action to verify that it is working as intended. Refs: - https://www.npmjs.com/package/ffmpeg-static#electron--other-cross-platform-packaging-tools - https://github.com/eugeneware/ffmpeg-static/issues/35 - https://github.com/eugeneware/ffmpeg-static/issues/136 --- desktop/.github/workflows/desktop-release.yml | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/desktop/.github/workflows/desktop-release.yml b/desktop/.github/workflows/desktop-release.yml index c8fccdaf7f..02ab7c7e65 100644 --- a/desktop/.github/workflows/desktop-release.yml +++ b/desktop/.github/workflows/desktop-release.yml @@ -60,6 +60,31 @@ jobs: - name: Install dependencies run: yarn install + - name: Create universal ffmpeg binaries for macOS + if: startsWith(matrix.os, 'ubuntu') + # Currently, the ffmpeg-static binaries are not universal (Not + # their fault, we thank them for their useful package, the issue + # is that there don't seem to be well known upstream sources that + # provide a universal binary). + # + # As a workaround, we invoke ffmpeg-static twice to download both + # the Intel and ARM binaries, and combine them into a single + # universal binary using lipo. + # + # Note that the yarn install will run again, as part of the + # "build:ci" step, so we're relying on ffmpeg-static install.js's + # behaviour of not overwriting the existing file named `ffmpeg`. + run: | + rm -f node_modules/ffmpeg-static/ffmpeg + npm rebuild --arch=arm64 -f ffmpeg-static + mv node_modules/ffmpeg-static/ffmpeg node_modules/ffmpeg-static/ffmpeg-arm64 + npm rebuild --arch=x64 -f ffmpeg-static + mv node_modules/ffmpeg-static/ffmpeg node_modules/ffmpeg-static/ffmpeg-x64 + cd node_modules/ffmpeg-static/ + lipo -create ffmpeg-arm64 ffmpeg-x64 -output ffmpeg + rm ffmpeg-arm64 ffmpeg-x64 + file ffmpeg # print what we ended up with + - name: Install libarchive-tools for pacman build if: startsWith(matrix.os, 'ubuntu') # See: From 706bb122731c8aceab72882e1423086a667716cd Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 10:00:06 +0530 Subject: [PATCH 006/275] [server] Log slow replication --- server/pkg/controller/replication3.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/server/pkg/controller/replication3.go b/server/pkg/controller/replication3.go index bacb2b4f99..2154ed553d 100644 --- a/server/pkg/controller/replication3.go +++ b/server/pkg/controller/replication3.go @@ -26,6 +26,11 @@ import ( "github.com/spf13/viper" ) +const ( + slowUploadThreshold = 2 * time.Second + slowSpeedThreshold = 0.5 // MB/s +) + // ReplicationController3 oversees version 3 of our object replication. // // The user's encrypted data starts off in 1 hot storage (Backblaze "b2"). This @@ -423,6 +428,7 @@ type UploadInput struct { // Upload, verify and then update the DB to mark replication to dest. func (c *ReplicationController3) replicateFile(in *UploadInput, dest *UploadDestination, dbUpdateCopies func() error) error { + start := time.Now() logger := in.Logger.WithFields(log.Fields{ "destination": dest.Label, "bucket": *dest.Bucket, @@ -438,6 +444,19 @@ func (c *ReplicationController3) replicateFile(in *UploadInput, dest *UploadDest if err != nil { return failure(stacktrace.Propagate(err, "Failed to upload object")) } + // log if time taken is more than 2 seconds and speed is less than .5MB/s + if dest.Label == "wasabi" && time.Since(start) > slowUploadThreshold { + elapsed := time.Since(start) + uploadSpeedMBps := float64(in.ExpectedSize) / (elapsed.Seconds() * 1024 * 1024) + + if uploadSpeedMBps < slowSpeedThreshold { + logger.WithFields(log.Fields{ + "sizeBytes": in.ExpectedSize, + "speedMBps": uploadSpeedMBps, + "elapsedSecs": elapsed.Seconds(), + }).Infof("Slow replication upload to %s: %.2f seconds, speed: %.2f MB/s", dest.Label, elapsed.Seconds(), uploadSpeedMBps) + } + } err = c.verifyUploadedFileSize(in, dest) if err != nil { From c1327fd8aa313b571ec62b978976a371be972cda Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 10:02:45 +0530 Subject: [PATCH 007/275] [desktop] Fix action Fix for https://github.com/ente-io/ente/pull/2965 --- desktop/.github/workflows/desktop-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desktop/.github/workflows/desktop-release.yml b/desktop/.github/workflows/desktop-release.yml index 02ab7c7e65..61465ac5a9 100644 --- a/desktop/.github/workflows/desktop-release.yml +++ b/desktop/.github/workflows/desktop-release.yml @@ -61,7 +61,7 @@ jobs: run: yarn install - name: Create universal ffmpeg binaries for macOS - if: startsWith(matrix.os, 'ubuntu') + if: startsWith(matrix.os, 'macos') # Currently, the ffmpeg-static binaries are not universal (Not # their fault, we thank them for their useful package, the issue # is that there don't seem to be well known upstream sources that From 65497862eadddcd0c5e87c73532761864c667da7 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 10:48:56 +0530 Subject: [PATCH 008/275] [server] Remove unused endpoint --- server/cmd/museum/main.go | 1 - server/pkg/api/user.go | 14 +-------- server/pkg/controller/user/user_details.go | 35 ---------------------- 3 files changed, 1 insertion(+), 49 deletions(-) diff --git a/server/cmd/museum/main.go b/server/cmd/museum/main.go index 0536871755..3391b43ecc 100644 --- a/server/cmd/museum/main.go +++ b/server/cmd/museum/main.go @@ -483,7 +483,6 @@ func main() { privateAPI.GET("/users/payment-token", userHandler.GetPaymentToken) privateAPI.GET("/users/families-token", userHandler.GetFamiliesToken) privateAPI.GET("/users/accounts-token", userHandler.GetAccountsToken) - privateAPI.GET("/users/details", userHandler.GetDetails) privateAPI.GET("/users/details/v2", userHandler.GetDetailsV2) privateAPI.POST("/users/change-email", userHandler.ChangeEmail) privateAPI.GET("/users/sessions", userHandler.GetActiveSessions) diff --git a/server/pkg/api/user.go b/server/pkg/api/user.go index 51a3516975..c02fce36c7 100644 --- a/server/pkg/api/user.go +++ b/server/pkg/api/user.go @@ -54,18 +54,6 @@ func (h *UserHandler) Logout(c *gin.Context) { c.JSON(http.StatusOK, gin.H{}) } -// GetDetails returns details about the requesting user -func (h *UserHandler) GetDetails(c *gin.Context) { - details, err := h.UserController.GetDetails(c) - if err != nil { - handler.Error(c, stacktrace.Propagate(err, "")) - return - } - c.JSON(http.StatusOK, gin.H{ - "details": details, - }) -} - // GetDetailsV2 returns details about the requesting user func (h *UserHandler) GetDetailsV2(c *gin.Context) { userID := auth.GetUserID(c.Request.Header) @@ -188,7 +176,7 @@ func (h *UserHandler) GetSessionValidityV2(c *gin.Context) { keyAttributes, err := h.UserController.GetAttributes(userID) if err == nil { c.JSON(http.StatusOK, gin.H{ - "hasSetKeys": true, + "hasSetKeys": true, "keyAttributes": keyAttributes, }) } else { diff --git a/server/pkg/controller/user/user_details.go b/server/pkg/controller/user/user_details.go index 08d3ad016c..cce7ef1392 100644 --- a/server/pkg/controller/user/user_details.go +++ b/server/pkg/controller/user/user_details.go @@ -4,7 +4,6 @@ import ( "github.com/ente-io/museum/ente" "github.com/ente-io/museum/ente/details" bonus "github.com/ente-io/museum/ente/storagebonus" - "github.com/ente-io/museum/pkg/utils/auth" "github.com/ente-io/museum/pkg/utils/recover" "github.com/ente-io/museum/pkg/utils/time" "github.com/ente-io/stacktrace" @@ -12,40 +11,6 @@ import ( "golang.org/x/sync/errgroup" ) -func (c *UserController) GetDetails(ctx *gin.Context) (details.UserDetailsResponse, error) { - - enteApp := ctx.MustGet("app").(ente.App) - - userID := auth.GetUserID(ctx.Request.Header) - user, err := c.UserRepo.Get(userID) - if err != nil { - return details.UserDetailsResponse{}, stacktrace.Propagate(err, "") - } - usage, err := c.FileRepo.GetUsage(userID) - if err != nil { - return details.UserDetailsResponse{}, stacktrace.Propagate(err, "") - } - fileCount, err := c.FileRepo.GetFileCountForUser(userID, enteApp) - if err != nil { - return details.UserDetailsResponse{}, stacktrace.Propagate(err, "") - } - sharedCollectionsCount, err := c.CollectionRepo.GetSharedCollectionsCount(userID) - if err != nil { - return details.UserDetailsResponse{}, stacktrace.Propagate(err, "") - } - subscription, err := c.BillingController.GetSubscription(ctx, userID) - if err != nil { - return details.UserDetailsResponse{}, stacktrace.Propagate(err, "") - } - return details.UserDetailsResponse{ - Email: user.Email, - Usage: usage, - FileCount: &fileCount, - SharedCollectionsCount: &sharedCollectionsCount, - Subscription: subscription, - }, nil -} - func (c *UserController) getUserFileCountWithCache(userID int64, app ente.App) (int64, error) { // Check if the value is present in the cache if count, ok := c.UserCache.GetFileCount(userID, app); ok { From 7129b2822b7d829c35ac14c3f055cd26d73da3a4 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 10:40:18 +0530 Subject: [PATCH 009/275] [desktop] Fix macOS universal binaries The previous approach worked, but we ran into some other issues Uncaught Exception: Error: Cannot find module 'ajv/dist/compile/codegen' Require stack: - /Applications/ente.app/Contents/Resources/app.asar/node_modules/ajv-formats/dist/limit.js As an alternative, try to use the yarn equivalent(-ish). --- desktop/.github/workflows/desktop-release.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/desktop/.github/workflows/desktop-release.yml b/desktop/.github/workflows/desktop-release.yml index 61465ac5a9..5590083a20 100644 --- a/desktop/.github/workflows/desktop-release.yml +++ b/desktop/.github/workflows/desktop-release.yml @@ -76,14 +76,13 @@ jobs: # behaviour of not overwriting the existing file named `ffmpeg`. run: | rm -f node_modules/ffmpeg-static/ffmpeg - npm rebuild --arch=arm64 -f ffmpeg-static - mv node_modules/ffmpeg-static/ffmpeg node_modules/ffmpeg-static/ffmpeg-arm64 - npm rebuild --arch=x64 -f ffmpeg-static - mv node_modules/ffmpeg-static/ffmpeg node_modules/ffmpeg-static/ffmpeg-x64 - cd node_modules/ffmpeg-static/ - lipo -create ffmpeg-arm64 ffmpeg-x64 -output ffmpeg + npm_config_arch=arm64 yarn add --check-files ffmpeg-static + mv node_modules/ffmpeg-static/ffmpeg ffmpeg-arm64 + npm_config_arch=x64 yarn add --check-files ffmpeg-static + mv node_modules/ffmpeg-static/ffmpeg ffmpeg-x64 + lipo -create ffmpeg-arm64 ffmpeg-x64 -output node_modules/ffmpeg-static/ffmpeg rm ffmpeg-arm64 ffmpeg-x64 - file ffmpeg # print what we ended up with + file node_modules/ffmpeg-static/ffmpeg # print what we ended up with - name: Install libarchive-tools for pacman build if: startsWith(matrix.os, 'ubuntu') From f67516f696098eab6d89db2143a165d24176ee01 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 10:56:56 +0530 Subject: [PATCH 010/275] [server] Remove duplicate code --- server/pkg/controller/user/user_details.go | 23 +--------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/server/pkg/controller/user/user_details.go b/server/pkg/controller/user/user_details.go index cce7ef1392..703b8fb2f5 100644 --- a/server/pkg/controller/user/user_details.go +++ b/server/pkg/controller/user/user_details.go @@ -11,27 +11,6 @@ import ( "golang.org/x/sync/errgroup" ) -func (c *UserController) getUserFileCountWithCache(userID int64, app ente.App) (int64, error) { - // Check if the value is present in the cache - if count, ok := c.UserCache.GetFileCount(userID, app); ok { - // Cache hit, update the cache asynchronously - go func() { - _, _ = c.getUserCountAndUpdateCache(userID, app) - }() - return count, nil - } - return c.getUserCountAndUpdateCache(userID, app) -} - -func (c *UserController) getUserCountAndUpdateCache(userID int64, app ente.App) (int64, error) { - count, err := c.FileRepo.GetFileCountForUser(userID, app) - if err != nil { - return 0, stacktrace.Propagate(err, "") - } - c.UserCache.SetFileCount(userID, count, app) - return count, nil -} - func (c *UserController) GetDetailsV2(ctx *gin.Context, userID int64, fetchMemoryCount bool, app ente.App) (details.UserDetailsResponse, error) { g := new(errgroup.Group) @@ -86,7 +65,7 @@ func (c *UserController) GetDetailsV2(ctx *gin.Context, userID int64, fetchMemor if fetchMemoryCount { g.Go(func() error { - fCount, err := c.getUserFileCountWithCache(userID, app) + fCount, err := c.UserCacheController.GetUserFileCountWithCache(userID, app) if err == nil { fileCount = fCount } From 9334540e1ee4273c5af5296b0b80ade90a1c41a4 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 11:14:34 +0530 Subject: [PATCH 011/275] [server] Rename --- server/pkg/api/admin.go | 6 +++--- server/pkg/controller/offer/offer.go | 2 +- server/pkg/repo/storagebonus/bf_addon.go | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/server/pkg/api/admin.go b/server/pkg/api/admin.go index f1006a1d6b..82e550f5c1 100644 --- a/server/pkg/api/admin.go +++ b/server/pkg/api/admin.go @@ -473,11 +473,11 @@ func (h *AdminHandler) UpdateBFDeal(c *gin.Context) { var err error switch r.Action { case ente.ADD: - err = h.StorageBonusRepo.InsertBFBonus(c, r.UserID, validTill, storage) + err = h.StorageBonusRepo.InsertAddOnBonus(c, r.UserID, validTill, storage) case ente.UPDATE: - err = h.StorageBonusRepo.UpdateBFBonus(c, r.UserID, validTill, storage) + err = h.StorageBonusRepo.UpdateAddOnBonus(c, r.UserID, validTill, storage) case ente.REMOVE: - _, err = h.StorageBonusRepo.RemoveBFBonus(c, r.UserID) + _, err = h.StorageBonusRepo.RemoveAddOnBonus(c, r.UserID) } if err != nil { handler.Error(c, stacktrace.Propagate(err, "")) diff --git a/server/pkg/controller/offer/offer.go b/server/pkg/controller/offer/offer.go index 44f1bce587..81b78d206f 100644 --- a/server/pkg/controller/offer/offer.go +++ b/server/pkg/controller/offer/offer.go @@ -105,7 +105,7 @@ func (c *OfferController) ApplyOffer(email string, productID string) error { } } - err = c.StorageBonusRepo.InsertBFBonus(context.Background(), userID, validTill, offerToBeApplied.Storage) + err = c.StorageBonusRepo.InsertAddOnBonus(context.Background(), userID, validTill, offerToBeApplied.Storage) if err != nil { c.DiscordController.Notify("Error inserting bonus") return stacktrace.Propagate(err, "") diff --git a/server/pkg/repo/storagebonus/bf_addon.go b/server/pkg/repo/storagebonus/bf_addon.go index 876d4b0b63..25b69add09 100644 --- a/server/pkg/repo/storagebonus/bf_addon.go +++ b/server/pkg/repo/storagebonus/bf_addon.go @@ -6,7 +6,7 @@ import ( "github.com/ente-io/museum/ente/storagebonus" ) -func (r *Repository) InsertBFBonus(ctx context.Context, userID int64, validTill int64, storage int64) error { +func (r *Repository) InsertAddOnBonus(ctx context.Context, userID int64, validTill int64, storage int64) error { bonusID := fmt.Sprintf("%s-%d", storagebonus.AddOnBf2023, userID) _, err := r.DB.ExecContext(ctx, "INSERT INTO storage_bonus (bonus_id, user_id, storage, type, valid_till) VALUES ($1, $2, $3, $4, $5)", bonusID, userID, storage, storagebonus.AddOnBf2023, validTill) if err != nil { @@ -15,7 +15,7 @@ func (r *Repository) InsertBFBonus(ctx context.Context, userID int64, validTill return nil } -func (r *Repository) RemoveBFBonus(ctx context.Context, userID int64) (int64, error) { +func (r *Repository) RemoveAddOnBonus(ctx context.Context, userID int64) (int64, error) { bonusID := fmt.Sprintf("%s-%d", storagebonus.AddOnBf2023, userID) res, err := r.DB.ExecContext(ctx, "DELETE FROM storage_bonus WHERE bonus_id = $1", bonusID) if err != nil { @@ -24,7 +24,7 @@ func (r *Repository) RemoveBFBonus(ctx context.Context, userID int64) (int64, er return res.RowsAffected() } -func (r *Repository) UpdateBFBonus(ctx context.Context, userID int64, validTill int64, storage int64) error { +func (r *Repository) UpdateAddOnBonus(ctx context.Context, userID int64, validTill int64, storage int64) error { bonusID := fmt.Sprintf("%s-%d", storagebonus.AddOnBf2023, userID) _, err := r.DB.ExecContext(ctx, "UPDATE storage_bonus SET storage = $1, valid_till = $2 WHERE bonus_id = $3", storage, validTill, bonusID) if err != nil { From e0eda79a919e0486f0f4458721ee5f2075aef53b Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 11:20:27 +0530 Subject: [PATCH 012/275] [server] Refactor --- server/pkg/api/admin.go | 7 ++++--- server/pkg/controller/offer/offer.go | 3 ++- server/pkg/repo/storagebonus/bf_addon.go | 12 ++++++------ 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/server/pkg/api/admin.go b/server/pkg/api/admin.go index 82e550f5c1..53be188779 100644 --- a/server/pkg/api/admin.go +++ b/server/pkg/api/admin.go @@ -10,6 +10,7 @@ import ( "github.com/ente-io/museum/pkg/controller/family" + bonusEntity "github.com/ente-io/museum/ente/storagebonus" "github.com/ente-io/museum/pkg/repo/storagebonus" gTime "time" @@ -473,11 +474,11 @@ func (h *AdminHandler) UpdateBFDeal(c *gin.Context) { var err error switch r.Action { case ente.ADD: - err = h.StorageBonusRepo.InsertAddOnBonus(c, r.UserID, validTill, storage) + err = h.StorageBonusRepo.InsertAddOnBonus(c, bonusEntity.AddOnBf2023, r.UserID, validTill, storage) case ente.UPDATE: - err = h.StorageBonusRepo.UpdateAddOnBonus(c, r.UserID, validTill, storage) + err = h.StorageBonusRepo.UpdateAddOnBonus(c, bonusEntity.AddOnBf2023, r.UserID, validTill, storage) case ente.REMOVE: - _, err = h.StorageBonusRepo.RemoveAddOnBonus(c, r.UserID) + _, err = h.StorageBonusRepo.RemoveAddOnBonus(c, bonusEntity.AddOnBf2023, r.UserID) } if err != nil { handler.Error(c, stacktrace.Propagate(err, "")) diff --git a/server/pkg/controller/offer/offer.go b/server/pkg/controller/offer/offer.go index 81b78d206f..65679f0906 100644 --- a/server/pkg/controller/offer/offer.go +++ b/server/pkg/controller/offer/offer.go @@ -10,6 +10,7 @@ import ( "github.com/ente-io/museum/pkg/controller/usercache" "github.com/ente-io/museum/ente" + storeageBonusEntity "github.com/ente-io/museum/ente/storagebonus" "github.com/ente-io/museum/pkg/controller/discord" "github.com/ente-io/museum/pkg/repo" "github.com/ente-io/museum/pkg/repo/storagebonus" @@ -105,7 +106,7 @@ func (c *OfferController) ApplyOffer(email string, productID string) error { } } - err = c.StorageBonusRepo.InsertAddOnBonus(context.Background(), userID, validTill, offerToBeApplied.Storage) + err = c.StorageBonusRepo.InsertAddOnBonus(context.Background(), storeageBonusEntity.AddOnBf2023, userID, validTill, offerToBeApplied.Storage) if err != nil { c.DiscordController.Notify("Error inserting bonus") return stacktrace.Propagate(err, "") diff --git a/server/pkg/repo/storagebonus/bf_addon.go b/server/pkg/repo/storagebonus/bf_addon.go index 25b69add09..a057025486 100644 --- a/server/pkg/repo/storagebonus/bf_addon.go +++ b/server/pkg/repo/storagebonus/bf_addon.go @@ -6,8 +6,8 @@ import ( "github.com/ente-io/museum/ente/storagebonus" ) -func (r *Repository) InsertAddOnBonus(ctx context.Context, userID int64, validTill int64, storage int64) error { - bonusID := fmt.Sprintf("%s-%d", storagebonus.AddOnBf2023, userID) +func (r *Repository) InsertAddOnBonus(ctx context.Context, bonusType storagebonus.BonusType, userID int64, validTill int64, storage int64) error { + bonusID := fmt.Sprintf("%s-%d", bonusType, userID) _, err := r.DB.ExecContext(ctx, "INSERT INTO storage_bonus (bonus_id, user_id, storage, type, valid_till) VALUES ($1, $2, $3, $4, $5)", bonusID, userID, storage, storagebonus.AddOnBf2023, validTill) if err != nil { return err @@ -15,8 +15,8 @@ func (r *Repository) InsertAddOnBonus(ctx context.Context, userID int64, validTi return nil } -func (r *Repository) RemoveAddOnBonus(ctx context.Context, userID int64) (int64, error) { - bonusID := fmt.Sprintf("%s-%d", storagebonus.AddOnBf2023, userID) +func (r *Repository) RemoveAddOnBonus(ctx context.Context, bonusType storagebonus.BonusType, userID int64) (int64, error) { + bonusID := fmt.Sprintf("%s-%d", bonusType, userID) res, err := r.DB.ExecContext(ctx, "DELETE FROM storage_bonus WHERE bonus_id = $1", bonusID) if err != nil { return 0, err @@ -24,8 +24,8 @@ func (r *Repository) RemoveAddOnBonus(ctx context.Context, userID int64) (int64, return res.RowsAffected() } -func (r *Repository) UpdateAddOnBonus(ctx context.Context, userID int64, validTill int64, storage int64) error { - bonusID := fmt.Sprintf("%s-%d", storagebonus.AddOnBf2023, userID) +func (r *Repository) UpdateAddOnBonus(ctx context.Context, bonusType storagebonus.BonusType, userID int64, validTill int64, storage int64) error { + bonusID := fmt.Sprintf("%s-%d", bonusType, userID) _, err := r.DB.ExecContext(ctx, "UPDATE storage_bonus SET storage = $1, valid_till = $2 WHERE bonus_id = $3", storage, validTill, bonusID) if err != nil { return err From bf7f1d43c0a5190854b8b5c6766791c1f0a01260 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 11:26:59 +0530 Subject: [PATCH 013/275] [server] Update endpoint --- server/cmd/museum/main.go | 2 +- server/ente/admin.go | 8 ++++---- server/pkg/api/admin.go | 4 ++-- server/pkg/repo/storagebonus/bf_addon.go | 16 ++++++++++++++++ 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/server/cmd/museum/main.go b/server/cmd/museum/main.go index 3391b43ecc..c9144a30b9 100644 --- a/server/cmd/museum/main.go +++ b/server/cmd/museum/main.go @@ -653,7 +653,7 @@ func main() { adminAPI.POST("/emails-from-hashes", adminHandler.GetEmailsFromHashes) adminAPI.PUT("/user/subscription", adminHandler.UpdateSubscription) adminAPI.POST("/queue/re-queue", adminHandler.ReQueueItem) - adminAPI.POST("/user/bf-2013", adminHandler.UpdateBFDeal) + adminAPI.POST("/user/bonus", adminHandler.UpdateBonus) adminAPI.POST("/job/clear-orphan-objects", adminHandler.ClearOrphanObjects) userEntityController := &userEntityCtrl.Controller{Repo: userEntityRepo} diff --git a/server/ente/admin.go b/server/ente/admin.go index 828173be7f..75ab9f3b53 100644 --- a/server/ente/admin.go +++ b/server/ente/admin.go @@ -86,7 +86,7 @@ const ( UPDATE AddOnAction = "UPDATE" ) -type UpdateBlackFridayDeal struct { +type SupportUpdateBonus struct { Action AddOnAction `json:"action" binding:"required"` UserID int64 `json:"userID" binding:"required"` Year int `json:"year"` @@ -96,15 +96,15 @@ type UpdateBlackFridayDeal struct { Minute int64 `json:"minute"` } -func (u UpdateBlackFridayDeal) UpdateLog() string { +func (u SupportUpdateBonus) UpdateLog() string { if u.Testing { - return fmt.Sprintf("BF_UPDATE_TESTING: %s, storageInMB: %d, minute: %d", u.Action, u.StorageInMB, u.Minute) + return fmt.Sprintf("SupportUpdateBonus: %s, storageInMB: %d, minute: %d", u.Action, u.StorageInMB, u.Minute) } else { return fmt.Sprintf("BF_UPDATE: %s, storageInGB: %d, year: %d", u.Action, u.StorageInGB, u.Year) } } -func (u UpdateBlackFridayDeal) Validate() error { +func (u SupportUpdateBonus) Validate() error { if u.Action == ADD || u.Action == UPDATE { if u.Testing { if u.StorageInMB == 0 && u.Minute == 0 { diff --git a/server/pkg/api/admin.go b/server/pkg/api/admin.go index 53be188779..6e301df7e1 100644 --- a/server/pkg/api/admin.go +++ b/server/pkg/api/admin.go @@ -452,8 +452,8 @@ func (h *AdminHandler) ReQueueItem(c *gin.Context) { c.JSON(http.StatusOK, gin.H{}) } -func (h *AdminHandler) UpdateBFDeal(c *gin.Context) { - var r ente.UpdateBlackFridayDeal +func (h *AdminHandler) UpdateBonus(c *gin.Context) { + var r ente.SupportUpdateBonus if err := c.ShouldBindJSON(&r); err != nil { handler.Error(c, stacktrace.Propagate(ente.ErrBadRequest, "Bad request")) return diff --git a/server/pkg/repo/storagebonus/bf_addon.go b/server/pkg/repo/storagebonus/bf_addon.go index a057025486..edaca9b52b 100644 --- a/server/pkg/repo/storagebonus/bf_addon.go +++ b/server/pkg/repo/storagebonus/bf_addon.go @@ -7,6 +7,9 @@ import ( ) func (r *Repository) InsertAddOnBonus(ctx context.Context, bonusType storagebonus.BonusType, userID int64, validTill int64, storage int64) error { + if err := _validate(bonusType); err != nil { + return err + } bonusID := fmt.Sprintf("%s-%d", bonusType, userID) _, err := r.DB.ExecContext(ctx, "INSERT INTO storage_bonus (bonus_id, user_id, storage, type, valid_till) VALUES ($1, $2, $3, $4, $5)", bonusID, userID, storage, storagebonus.AddOnBf2023, validTill) if err != nil { @@ -16,6 +19,9 @@ func (r *Repository) InsertAddOnBonus(ctx context.Context, bonusType storagebonu } func (r *Repository) RemoveAddOnBonus(ctx context.Context, bonusType storagebonus.BonusType, userID int64) (int64, error) { + if err := _validate(bonusType); err != nil { + return 0, err + } bonusID := fmt.Sprintf("%s-%d", bonusType, userID) res, err := r.DB.ExecContext(ctx, "DELETE FROM storage_bonus WHERE bonus_id = $1", bonusID) if err != nil { @@ -25,6 +31,9 @@ func (r *Repository) RemoveAddOnBonus(ctx context.Context, bonusType storagebonu } func (r *Repository) UpdateAddOnBonus(ctx context.Context, bonusType storagebonus.BonusType, userID int64, validTill int64, storage int64) error { + if err := _validate(bonusType); err != nil { + return err + } bonusID := fmt.Sprintf("%s-%d", bonusType, userID) _, err := r.DB.ExecContext(ctx, "UPDATE storage_bonus SET storage = $1, valid_till = $2 WHERE bonus_id = $3", storage, validTill, bonusID) if err != nil { @@ -32,3 +41,10 @@ func (r *Repository) UpdateAddOnBonus(ctx context.Context, bonusType storagebonu } return nil } + +func _validate(bonusType storagebonus.BonusType) error { + if bonusType == storagebonus.AddOnBf2023 || bonusType == storagebonus.AddOnSupport { + return nil + } + return fmt.Errorf("invalid bonus type: %s", bonusType) +} From 0925f7f0a2f3c848bd79c3cc8031ebab0f238f61 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 11:32:48 +0530 Subject: [PATCH 014/275] [server] Allow adding support bonus --- server/ente/admin.go | 14 ++++++++++++-- server/ente/storagebonus/storge_bonus.go | 15 +++++++++++++++ server/pkg/api/admin.go | 7 ++++--- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/server/ente/admin.go b/server/ente/admin.go index 75ab9f3b53..3990635324 100644 --- a/server/ente/admin.go +++ b/server/ente/admin.go @@ -87,6 +87,7 @@ const ( ) type SupportUpdateBonus struct { + BonusType string `json:"bonusType" binding:"required"` Action AddOnAction `json:"action" binding:"required"` UserID int64 `json:"userID" binding:"required"` Year int `json:"year"` @@ -105,17 +106,26 @@ func (u SupportUpdateBonus) UpdateLog() string { } func (u SupportUpdateBonus) Validate() error { + isSupportBonus := u.BonusType == "ADD_ON_SUPPORT" + if u.BonusType != "ADD_ON_SUPPORT" && u.BonusType != "ADD_ON_BF_2023" { + return errors.New("invalid bonus type") + } if u.Action == ADD || u.Action == UPDATE { if u.Testing { if u.StorageInMB == 0 && u.Minute == 0 { return errors.New("invalid input, set in MB and minute for test") } } else { - if u.StorageInGB != 100 && u.StorageInGB != 2000 && u.StorageInGB != 500 { + if u.StorageInGB != 200 && u.StorageInGB != 2000 && u.StorageInGB != 500 { return errors.New("invalid input for deal, only 100, 500, 2000 allowed") } - if u.Year != 3 && u.Year != 5 { + if isSupportBonus { + if u.Year == 0 || u.Year > 100 { + return errors.New("invalid input for year, only 1-100") + } + } else if u.Year != 3 && u.Year != 5 { return errors.New("invalid input for year, only 3 or 5") + } } } diff --git a/server/ente/storagebonus/storge_bonus.go b/server/ente/storagebonus/storge_bonus.go index 9a876fb4d7..6ea63386a0 100644 --- a/server/ente/storagebonus/storge_bonus.go +++ b/server/ente/storagebonus/storge_bonus.go @@ -34,6 +34,21 @@ func (t BonusType) ExtendsExpiry() bool { } } +func BonusFromType(bonusType string) BonusType { + switch bonusType { + case "REFERRAL": + return Referral + case "SIGN_UP": + return SignUp + case "ADD_ON_SUPPORT": + return AddOnSupport + case "ADD_ON_BF_2023": + return AddOnBf2023 + default: + return "" + } +} + // RestrictToDoublingStorage returns true if the bonus type restricts the doubling of storage. // This indicates, the usable bonus storage should not exceed the current plan storage. // Note: Current plan storage includes both base subscription and storage bonus that can ExtendsExpiry diff --git a/server/pkg/api/admin.go b/server/pkg/api/admin.go index 6e301df7e1..92786c3d28 100644 --- a/server/pkg/api/admin.go +++ b/server/pkg/api/admin.go @@ -472,13 +472,14 @@ func (h *AdminHandler) UpdateBonus(c *gin.Context) { validTill = gTime.Now().AddDate(r.Year, 0, 0).UnixMicro() } var err error + bonusType := bonusEntity.BonusType(r.BonusType) switch r.Action { case ente.ADD: - err = h.StorageBonusRepo.InsertAddOnBonus(c, bonusEntity.AddOnBf2023, r.UserID, validTill, storage) + err = h.StorageBonusRepo.InsertAddOnBonus(c, bonusType, r.UserID, validTill, storage) case ente.UPDATE: - err = h.StorageBonusRepo.UpdateAddOnBonus(c, bonusEntity.AddOnBf2023, r.UserID, validTill, storage) + err = h.StorageBonusRepo.UpdateAddOnBonus(c, bonusType, r.UserID, validTill, storage) case ente.REMOVE: - _, err = h.StorageBonusRepo.RemoveAddOnBonus(c, bonusEntity.AddOnBf2023, r.UserID) + _, err = h.StorageBonusRepo.RemoveAddOnBonus(c, bonusType, r.UserID) } if err != nil { handler.Error(c, stacktrace.Propagate(err, "")) From a5b289d290bcbb62a67651688a00f55babeab70e Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 11:36:26 +0530 Subject: [PATCH 015/275] [server] Allow 200,1TB, & 2TB --- server/ente/admin.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/ente/admin.go b/server/ente/admin.go index 3990635324..0085ae95d8 100644 --- a/server/ente/admin.go +++ b/server/ente/admin.go @@ -116,8 +116,8 @@ func (u SupportUpdateBonus) Validate() error { return errors.New("invalid input, set in MB and minute for test") } } else { - if u.StorageInGB != 200 && u.StorageInGB != 2000 && u.StorageInGB != 500 { - return errors.New("invalid input for deal, only 100, 500, 2000 allowed") + if u.StorageInGB != 200 && u.StorageInGB != 2000 && u.StorageInGB != 1000 { + return errors.New("invalid input for deal, only 200, 1000, 2000 allowed") } if isSupportBonus { if u.Year == 0 || u.Year > 100 { From 571d721925a3cf3c4f8f5244795347d33e21f1e8 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 11:42:39 +0530 Subject: [PATCH 016/275] [desktop] Fix broken nightly builds due to ajv I'm not sure why it started happening now. Earlier I thought it was because of this - https://github.com/ente-io/ente/pull/2969 - but that was a red-herring (I think!), instead this likely got triggered because of https://github.com/ente-io/action-electron-builder/commit/eff78a1d33bdab4c54ede0e5cdc71e0c2cf803e2. This change fixed the issue locally, will see if it works on CI too. Workaround from: https://github.com/ajv-validator/ajv/issues/2443#issuecomment-2147026958 --- desktop/docs/dependencies.md | 4 ++++ desktop/package.json | 1 + desktop/yarn.lock | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/desktop/docs/dependencies.md b/desktop/docs/dependencies.md index 8cbf43c83d..7b11a79256 100644 --- a/desktop/docs/dependencies.md +++ b/desktop/docs/dependencies.md @@ -95,6 +95,10 @@ Some extra ones specific to the code here are: for allowing us to set environment variables in a way that also works on Windows. +- We don't need `ajv`, but it is a transitive dependency which breaks the + build if we let its version be resolved via the yarn resolution mechanism. + Taking a direct dependency on it is the easiest workaround for now. + ## Functionality ### Format conversion diff --git a/desktop/package.json b/desktop/package.json index 1a33272037..84fe052bb8 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -45,6 +45,7 @@ "@types/auto-launch": "^5.0.5", "@types/eslint__js": "^8.42.3", "@types/ffmpeg-static": "^3.0.3", + "ajv": "^8.17.1", "concurrently": "^8.2.2", "cross-env": "^7.0.3", "electron": "^30.4.0", diff --git a/desktop/yarn.lock b/desktop/yarn.lock index 376d2c3527..1ea4bf759b 100644 --- a/desktop/yarn.lock +++ b/desktop/yarn.lock @@ -531,7 +531,7 @@ ajv@^6.10.0, ajv@^6.12.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.0, ajv@^8.6.3: +ajv@^8.0.0, ajv@^8.17.1, ajv@^8.6.3: version "8.17.1" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== From e32facf3e63d376cd53ca1cea4eb6e165bc69e94 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 12:01:00 +0530 Subject: [PATCH 017/275] [server] Refresh fileCount only if trash or usage changed --- server/cmd/museum/main.go | 4 ++- server/ente/cache/user_data_cache.go | 14 ++++++--- server/pkg/controller/usercache/controller.go | 2 ++ server/pkg/controller/usercache/count.go | 29 +++++++++++++++---- server/pkg/repo/trash.go | 10 +++++++ 5 files changed, 49 insertions(+), 10 deletions(-) diff --git a/server/cmd/museum/main.go b/server/cmd/museum/main.go index 3391b43ecc..2d60a970e9 100644 --- a/server/cmd/museum/main.go +++ b/server/cmd/museum/main.go @@ -188,7 +188,9 @@ func main() { } userCache := cache2.NewUserCache() - userCacheCtrl := &usercache.Controller{UserCache: userCache, FileRepo: fileRepo, StoreBonusRepo: storagBonusRepo} + userCacheCtrl := &usercache.Controller{UserCache: userCache, FileRepo: fileRepo, + UsageRepo: usageRepo, TrashRepo: trashRepo, + StoreBonusRepo: storagBonusRepo} offerController := offer.NewOfferController(*userRepo, discordController, storagBonusRepo, userCacheCtrl) plans := billing.GetPlans() defaultPlan := billing.GetDefaultPlans(plans) diff --git a/server/ente/cache/user_data_cache.go b/server/ente/cache/user_data_cache.go index 45308f0663..c202d7dd7c 100644 --- a/server/ente/cache/user_data_cache.go +++ b/server/ente/cache/user_data_cache.go @@ -10,20 +10,26 @@ import ( // UserCache struct holds can be used to fileCount various entities for user. type UserCache struct { mu sync.Mutex - fileCache map[string]int64 + fileCache map[string]*FileCountCache bonusCache map[int64]*storagebonus.ActiveStorageBonus } +type FileCountCache struct { + Count int64 + TrashUpdatedAt int64 + Usage int64 +} + // NewUserCache creates a new instance of the UserCache struct. func NewUserCache() *UserCache { return &UserCache{ - fileCache: make(map[string]int64), + fileCache: make(map[string]*FileCountCache), bonusCache: make(map[int64]*storagebonus.ActiveStorageBonus), } } // SetFileCount updates the fileCount with the given userID and fileCount. -func (c *UserCache) SetFileCount(userID, fileCount int64, app ente.App) { +func (c *UserCache) SetFileCount(userID int64, fileCount *FileCountCache, app ente.App) { c.mu.Lock() defer c.mu.Unlock() c.fileCache[cacheKey(userID, app)] = fileCount @@ -44,7 +50,7 @@ func (c *UserCache) GetBonus(userID int64) (*storagebonus.ActiveStorageBonus, bo // GetFileCount retrieves the file count from the fileCount for the given userID. // It returns the file count and a boolean indicating if the value was found. -func (c *UserCache) GetFileCount(userID int64, app ente.App) (int64, bool) { +func (c *UserCache) GetFileCount(userID int64, app ente.App) (*FileCountCache, bool) { c.mu.Lock() defer c.mu.Unlock() count, ok := c.fileCache[cacheKey(userID, app)] diff --git a/server/pkg/controller/usercache/controller.go b/server/pkg/controller/usercache/controller.go index b6645653cd..efce2d11bd 100644 --- a/server/pkg/controller/usercache/controller.go +++ b/server/pkg/controller/usercache/controller.go @@ -14,6 +14,8 @@ import ( // Avoid adding any direct dependencies to the other controller. type Controller struct { FileRepo *repo.FileRepository + UsageRepo *repo.UsageRepository + TrashRepo *repo.TrashRepository StoreBonusRepo *storagebonus.Repository UserCache *cache.UserCache } diff --git a/server/pkg/controller/usercache/count.go b/server/pkg/controller/usercache/count.go index a0f3bb0435..22b5b512ca 100644 --- a/server/pkg/controller/usercache/count.go +++ b/server/pkg/controller/usercache/count.go @@ -2,7 +2,9 @@ package usercache import ( "github.com/ente-io/museum/ente" + "github.com/ente-io/museum/ente/cache" "github.com/ente-io/stacktrace" + "github.com/sirupsen/logrus" ) func (c *Controller) GetUserFileCountWithCache(userID int64, app ente.App) (int64, error) { @@ -10,18 +12,35 @@ func (c *Controller) GetUserFileCountWithCache(userID int64, app ente.App) (int6 if count, ok := c.UserCache.GetFileCount(userID, app); ok { // Cache hit, update the cache asynchronously go func() { - _, _ = c.getUserCountAndUpdateCache(userID, app) + _, _ = c.getUserCountAndUpdateCache(userID, app, count) }() - return count, nil + return count.Count, nil } - return c.getUserCountAndUpdateCache(userID, app) + return c.getUserCountAndUpdateCache(userID, app, nil) } -func (c *Controller) getUserCountAndUpdateCache(userID int64, app ente.App) (int64, error) { +func (c *Controller) getUserCountAndUpdateCache(userID int64, app ente.App, oldCache *cache.FileCountCache) (int64, error) { + usage, err := c.UsageRepo.GetUsage(userID) + if err != nil { + return 0, stacktrace.Propagate(err, "") + } + trashUpdatedAt, err := c.TrashRepo.GetTrashUpdatedAt(userID) + if err != nil { + return 0, stacktrace.Propagate(err, "") + } + if oldCache != nil && oldCache.Usage == usage && oldCache.TrashUpdatedAt == trashUpdatedAt { + logrus.Debugf("Cache hit for user %d", userID) + return oldCache.Count, nil + } count, err := c.FileRepo.GetFileCountForUser(userID, app) if err != nil { return 0, stacktrace.Propagate(err, "") } - c.UserCache.SetFileCount(userID, count, app) + cntCache := &cache.FileCountCache{ + Count: count, + Usage: usage, + TrashUpdatedAt: trashUpdatedAt, + } + c.UserCache.SetFileCount(userID, cntCache, app) return count, nil } diff --git a/server/pkg/repo/trash.go b/server/pkg/repo/trash.go index 3d1cac2bd5..5218caf55d 100644 --- a/server/pkg/repo/trash.go +++ b/server/pkg/repo/trash.go @@ -422,6 +422,16 @@ func (t *TrashRepository) EmptyTrash(ctx context.Context, userID int64, lastUpda return t.QueueRepo.InsertItem(ctx, TrashEmptyQueue, itemID) } +func (t *TrashRepository) GetTrashUpdatedAt(userID int64) (int64, error) { + row := t.DB.QueryRow(`SELECT max(updated_at) FROM trash WHERE user_id = $1`, userID) + var updatedAt int64 + err := row.Scan(&updatedAt) + if errors.Is(err, sql.ErrNoRows) { + return 0, nil + } + return updatedAt, stacktrace.Propagate(err, "") +} + func convertRowsToTrash(rows *sql.Rows) ([]ente.Trash, error) { defer rows.Close() trashFiles := make([]ente.Trash, 0) From 4ecc64e478e1203fd4147381d9d708bdf06254ac Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 12:34:36 +0530 Subject: [PATCH 018/275] [server] Handle case when no entry exists in trash --- server/pkg/repo/trash.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/pkg/repo/trash.go b/server/pkg/repo/trash.go index 5218caf55d..1c6ab6b45f 100644 --- a/server/pkg/repo/trash.go +++ b/server/pkg/repo/trash.go @@ -423,7 +423,7 @@ func (t *TrashRepository) EmptyTrash(ctx context.Context, userID int64, lastUpda } func (t *TrashRepository) GetTrashUpdatedAt(userID int64) (int64, error) { - row := t.DB.QueryRow(`SELECT max(updated_at) FROM trash WHERE user_id = $1`, userID) + row := t.DB.QueryRow(`SELECT coalesce(max(updated_at),0) FROM trash WHERE user_id = $1`, userID) var updatedAt int64 err := row.Scan(&updatedAt) if errors.Is(err, sql.ErrNoRows) { From 80b86189d08af6d20dc5c4b057069ab1fc39453d Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 12:39:51 +0530 Subject: [PATCH 019/275] Update the docs around ffmpeg on Intel macOS --- .../docs/photos/troubleshooting/thumbnails.md | 5 +++++ .../src/services/upload/uploadService.ts | 19 ++++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/docs/docs/photos/troubleshooting/thumbnails.md b/docs/docs/photos/troubleshooting/thumbnails.md index f26319c2e5..b4627f648b 100644 --- a/docs/docs/photos/troubleshooting/thumbnails.md +++ b/docs/docs/photos/troubleshooting/thumbnails.md @@ -22,6 +22,11 @@ canvas. ## Desktop +> [!NOTE] +> +> This issue has been fixed in the latest beta releases, and the fix will be +> also out in the next release, 1.7.4. + The only known case where thumbnails might be missing on desktop is when uploading **videos** during a Google Takeout or watched folder sync on **Intel macOS** machines. This is because the bundled ffmpeg that we use does not work diff --git a/web/apps/photos/src/services/upload/uploadService.ts b/web/apps/photos/src/services/upload/uploadService.ts index 8e7cd747e9..54239e334e 100644 --- a/web/apps/photos/src/services/upload/uploadService.ts +++ b/web/apps/photos/src/services/upload/uploadService.ts @@ -1108,22 +1108,19 @@ const withThumbnail = async ( // // We can only get here when we're running in our desktop app (since // only that works with non-File uploadItems), and the thumbnail - // generation failed. The scenarios are: + // generation failed. // - // 1. We're trying to generate an image thumbnail on Windows or on - // ARM64 Linux. This won't be possible since the bundled - // imagemagick doesn't yet support these OS/arch combinations. - // - // 2. We're trying to generate a video thumbnail on Intel macOS. - // This won't be possible since the bundled ffmpeg doesn't - // support Rosetta. - // - // 3. Some other arbitrary exception happened. + // The only know scenario is when we're trying to generate an image + // thumbnail on Windows or on ARM64 Linux, or are trying to + // generated the thumbnail for an HEIC file on Linux. This won't be + // possible since the bundled imagemagick doesn't yet support these + // OS/arch combinations. // // The fallback in this case involves reading the entire stream into // memory, and passing that data across the IPC boundary in a single // go (i.e. not in a streaming manner). This is risky for videos of - // unbounded sizes, so we can only apply this fallback for images. + // unbounded sizes, and since anyways we are not expected to come + // here for videos, soo we only apply this fallback for images. if (fileTypeInfo.fileType == FileType.image) { const data = await readEntireStream(fileStream.stream); From f3860a077e86a11316e4b683c35f9f3df2474d72 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 12:44:07 +0530 Subject: [PATCH 020/275] [desktop] Use latest version of our updated fork of the electron-builder action So that it refs this commit https://github.com/ente-io/action-electron-builder/commit/eff78a1d33bdab4c54ede0e5cdc71e0c2cf803e2 --- desktop/.github/workflows/desktop-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desktop/.github/workflows/desktop-release.yml b/desktop/.github/workflows/desktop-release.yml index 5590083a20..192bb50194 100644 --- a/desktop/.github/workflows/desktop-release.yml +++ b/desktop/.github/workflows/desktop-release.yml @@ -91,7 +91,7 @@ jobs: run: sudo apt-get install libarchive-tools - name: Build - uses: ente-io/action-electron-builder@v1.0.0 + uses: ente-io/action-electron-builder with: package_root: desktop build_script_name: build:ci From 13dea41c97bdce993c5168aac722bf023d25a144 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 12:54:55 +0530 Subject: [PATCH 021/275] [desktop] Specify an action version Apparently, specifying something after the @ is necessary. Without this, the action stopped working. --- desktop/.github/workflows/desktop-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desktop/.github/workflows/desktop-release.yml b/desktop/.github/workflows/desktop-release.yml index 192bb50194..fbaac39546 100644 --- a/desktop/.github/workflows/desktop-release.yml +++ b/desktop/.github/workflows/desktop-release.yml @@ -91,7 +91,7 @@ jobs: run: sudo apt-get install libarchive-tools - name: Build - uses: ente-io/action-electron-builder + uses: ente-io/action-electron-builder@eff78a1d33bdab4c54ede0e5cdc71e0c2cf803e2 with: package_root: desktop build_script_name: build:ci From 375260d701ce6b4a516882420c511dae74e59909 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Tue, 27 Aug 2024 10:05:31 +0200 Subject: [PATCH 022/275] [mob][photos] Better logging for image retrieval --- mobile/lib/utils/ml_util.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mobile/lib/utils/ml_util.dart b/mobile/lib/utils/ml_util.dart index 13fb1474c7..cb9ab5d630 100644 --- a/mobile/lib/utils/ml_util.dart +++ b/mobile/lib/utils/ml_util.dart @@ -299,7 +299,8 @@ Future getImagePathForML(EnteFile enteFile) async { final stopwatch = Stopwatch()..start(); File? file; - if (enteFile.fileType == FileType.video) { + final bool isVideo = enteFile.fileType == FileType.video; + if (isVideo) { try { file = await getThumbnailForUploadedFile(enteFile); } on PlatformException catch (e, s) { @@ -328,8 +329,8 @@ Future getImagePathForML(EnteFile enteFile) async { ); if (imagePath == null) { - _logger.warning( - "Failed to get any data for enteFile with uploadedFileID ${enteFile.uploadedFileID} since its file path is null", + _logger.severe( + "Failed to get any data for enteFile with uploadedFileID ${enteFile.uploadedFileID} since its file path is null (isVideo: $isVideo)", ); throw CouldNotRetrieveAnyFileData(); } From d299f94518675f391f281557d17e81b11af8b032 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Tue, 27 Aug 2024 10:11:12 +0200 Subject: [PATCH 023/275] [mob][photos] More logs --- mobile/lib/utils/thumbnail_util.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mobile/lib/utils/thumbnail_util.dart b/mobile/lib/utils/thumbnail_util.dart index cd67345659..06b26c9be6 100644 --- a/mobile/lib/utils/thumbnail_util.dart +++ b/mobile/lib/utils/thumbnail_util.dart @@ -47,6 +47,7 @@ Future getThumbnail(EnteFile file) async { Future getThumbnailForUploadedFile(EnteFile file) async { final cachedThumbnail = cachedThumbnailPath(file); if (await cachedThumbnail.exists()) { + _logger.info("Thumbnail already exists for ${file.uploadedFileID}"); return cachedThumbnail; } final thumbnail = await getThumbnail(file); @@ -55,8 +56,10 @@ Future getThumbnailForUploadedFile(EnteFile file) async { if (!await cachedThumbnail.exists()) { await cachedThumbnail.writeAsBytes(thumbnail, flush: true); } + _logger.info("Thumbnail obtained for ${file.uploadedFileID}"); return cachedThumbnail; } + _logger.severe("Failed to get thumbnail for ${file.uploadedFileID}"); return null; } From ef01223d9dce24282fdbe0b8540a3720db63e8d2 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Tue, 27 Aug 2024 13:49:28 +0530 Subject: [PATCH 024/275] [mob][photos] update flutter version in README.md --- mobile/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/README.md b/mobile/README.md index 418338759e..bd937f4ed2 100644 --- a/mobile/README.md +++ b/mobile/README.md @@ -46,7 +46,7 @@ You can alternatively install the build from PlayStore or F-Droid. ## 🧑‍💻 Building from source -1. [Install Flutter v3.22.2](https://flutter.dev/docs/get-started/install). +1. [Install Flutter v3.24.0](https://flutter.dev/docs/get-started/install). 2. Pull in all submodules with `git submodule update --init --recursive` From 7718da93a5cabfa988123cf709091b05ee6aaa38 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Tue, 27 Aug 2024 10:23:15 +0200 Subject: [PATCH 025/275] [mob][photos] Logs --- mobile/lib/services/machine_learning/ml_service.dart | 2 +- mobile/lib/utils/ml_util.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mobile/lib/services/machine_learning/ml_service.dart b/mobile/lib/services/machine_learning/ml_service.dart index ef428f3946..e3e41c73d2 100644 --- a/mobile/lib/services/machine_learning/ml_service.dart +++ b/mobile/lib/services/machine_learning/ml_service.dart @@ -495,7 +495,7 @@ class MLService { return true; } _logger.severe( - "Failed to analyze using FaceML for image with ID: ${instruction.file.uploadedFileID}. Not storing any results locally, which means it will be automatically retried later.", + "Failed to analyze using FaceML for image with ID: ${instruction.file.uploadedFileID} and format ${instruction.file.displayName.split('.').last} (${instruction.file.fileType}). Not storing any results locally, which means it will be automatically retried later.", e, s, ); diff --git a/mobile/lib/utils/ml_util.dart b/mobile/lib/utils/ml_util.dart index cb9ab5d630..e07740acba 100644 --- a/mobile/lib/utils/ml_util.dart +++ b/mobile/lib/utils/ml_util.dart @@ -330,7 +330,7 @@ Future getImagePathForML(EnteFile enteFile) async { if (imagePath == null) { _logger.severe( - "Failed to get any data for enteFile with uploadedFileID ${enteFile.uploadedFileID} since its file path is null (isVideo: $isVideo)", + "Failed to get any data for enteFile with uploadedFileID ${enteFile.uploadedFileID} and format ${enteFile.displayName.split('.').last} and size ${enteFile.fileSize} since its file path is null (isVideo: $isVideo)", ); throw CouldNotRetrieveAnyFileData(); } From 2450dcf4c2e3949028b1d423c926d5708f9f84d6 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Tue, 27 Aug 2024 07:11:11 +0000 Subject: [PATCH 026/275] New Crowdin translations by GitHub Action --- mobile/fastlane/metadata/ios/da/keywords.txt | 1 + mobile/fastlane/metadata/ios/da/name.txt | 1 + mobile/lib/l10n/intl_pl.arb | 2 +- mobile/lib/l10n/intl_pt.arb | 4 +- mobile/lib/l10n/intl_zh.arb | 63 ++++++++++++-------- 5 files changed, 43 insertions(+), 28 deletions(-) create mode 100644 mobile/fastlane/metadata/ios/da/keywords.txt create mode 100644 mobile/fastlane/metadata/ios/da/name.txt diff --git a/mobile/fastlane/metadata/ios/da/keywords.txt b/mobile/fastlane/metadata/ios/da/keywords.txt new file mode 100644 index 0000000000..e436784418 --- /dev/null +++ b/mobile/fastlane/metadata/ios/da/keywords.txt @@ -0,0 +1 @@ +fotos,fotografi,familie, privatliv, sky,backup,videoer,foto,kryptering,lager,album,alternativ diff --git a/mobile/fastlane/metadata/ios/da/name.txt b/mobile/fastlane/metadata/ios/da/name.txt new file mode 100644 index 0000000000..3a991c4abc --- /dev/null +++ b/mobile/fastlane/metadata/ios/da/name.txt @@ -0,0 +1 @@ +Ente Photos diff --git a/mobile/lib/l10n/intl_pl.arb b/mobile/lib/l10n/intl_pl.arb index 3e124d3081..7be752f684 100644 --- a/mobile/lib/l10n/intl_pl.arb +++ b/mobile/lib/l10n/intl_pl.arb @@ -496,7 +496,7 @@ "removeDuplicates": "Usuń duplikaty", "removeDuplicatesDesc": "Przejrzyj i usuń pliki, które są dokładnymi duplikatami.", "viewLargeFiles": "Duże pliki", - "viewLargeFilesDesc": "Wyświetl pliki zużywające największą ilość pamięci", + "viewLargeFilesDesc": "Wyświetl pliki zużywające największą ilość pamięci.", "noDuplicates": "✨ Brak duplikatów", "youveNoDuplicateFilesThatCanBeCleared": "Nie masz duplikatów plików, które mogą być wyczyszczone", "success": "Sukces", diff --git a/mobile/lib/l10n/intl_pt.arb b/mobile/lib/l10n/intl_pt.arb index 2c09c839c2..0ca1ce69cd 100644 --- a/mobile/lib/l10n/intl_pt.arb +++ b/mobile/lib/l10n/intl_pt.arb @@ -496,7 +496,7 @@ "removeDuplicates": "Excluir duplicados", "removeDuplicatesDesc": "Revise e remova arquivos que sejam duplicatas exatas.", "viewLargeFiles": "Arquivos grandes", - "viewLargeFilesDesc": "Ver arquivos que estão consumindo mais espaço de armazenamento", + "viewLargeFilesDesc": "Ver arquivos que estão consumindo mais espaço de armazenamento.", "noDuplicates": "✨ Sem duplicados", "youveNoDuplicateFilesThatCanBeCleared": "Você não tem arquivos duplicados que possam ser limpos", "success": "Bem-sucedido", @@ -1151,7 +1151,7 @@ "hiding": "Ocultando...", "unhiding": "Reexibindo...", "successfullyHid": "Ocultado com sucesso", - "successfullyUnhid": "Desocultado com sucesso", + "successfullyUnhid": "Reexibido com sucesso", "crashReporting": "Relatório de falhas", "resumableUploads": "Envios retomáveis", "addToHiddenAlbum": "Adicionar a álbum oculto", diff --git a/mobile/lib/l10n/intl_zh.arb b/mobile/lib/l10n/intl_zh.arb index be97d070f4..abb3a223ae 100644 --- a/mobile/lib/l10n/intl_zh.arb +++ b/mobile/lib/l10n/intl_zh.arb @@ -273,6 +273,11 @@ "failedToApplyCode": "无法使用此代码", "enterReferralCode": "输入推荐代码", "codeAppliedPageTitle": "代码已应用", + "changeYourReferralCode": "更改您的推荐代码", + "change": "更改", + "unavailableReferralCode": "抱歉,此代码不可用。", + "codeChangeLimitReached": "抱歉,您已达到代码更改的限制。", + "onlyFamilyAdminCanChangeCode": "请联系{familyAdminEmail} 以更改您的代码。", "storageInGB": "{storageAmountInGB} GB", "claimed": "已领取", "@claimed": { @@ -409,8 +414,13 @@ "photoGridSize": "照片网格大小", "manageDeviceStorage": "管理设备存储", "machineLearning": "机器学习", + "mlConsent": "启用机器学习", + "mlConsentTitle": "要启用机器学习吗?", + "mlConsentDescription": "如果您启用机器学习,Ente 将从文件(包括与您共享的文件)中提取面部几何形状等信息。\n\n这将在您的设备上进行,并且任何生成的生物特征信息都将被端到端加密。", + "mlConsentPrivacy": "请点击此处查看我们隐私政策中有关此功能的更多详细信息", + "mlConsentConfirmation": "我了解了,并希望启用机器学习", "magicSearch": "魔法搜索", - "mlIndexingDescription": "请注意,机器学习将使用更高的带宽和更多的电量,直到所有项目都被索引为止。", + "mlIndexingDescription": "请注意,机器学习会导致带宽和电池使用量增加,直到所有项目都被索引。请考虑使用桌面应用程序来加快索引速度,所有结果都将自动同步。", "loadingModel": "正在下载模型...", "waitingForWifi": "正在等待 WiFi...", "status": "状态", @@ -486,7 +496,7 @@ "removeDuplicates": "移除重复内容", "removeDuplicatesDesc": "检查并删除完全重复的文件。", "viewLargeFiles": "大文件", - "viewLargeFilesDesc": "查看占用存储空间最多的文件", + "viewLargeFilesDesc": "查看占用存储空间最多的文件。", "noDuplicates": "✨ 没有重复内容", "youveNoDuplicateFilesThatCanBeCleared": "您没有可以被清除的重复文件", "success": "成功", @@ -1143,7 +1153,7 @@ "successfullyHid": "已成功隐藏", "successfullyUnhid": "已成功取消隐藏", "crashReporting": "上报崩溃", - "enableMultiPartUpload": "启用分片上传", + "resumableUploads": "可续传上传", "addToHiddenAlbum": "添加到隐藏相册", "moveToHiddenAlbum": "移至隐藏相册", "fileTypes": "文件类型", @@ -1253,20 +1263,6 @@ "right": "向右", "whatsNew": "更新日志", "reviewSuggestions": "查看建议", - "reenterPassword": "再次输入密码", - "reenterPin": "再次输入 PIN 码", - "deviceLock": "设备锁", - "pinLock": "PIN 锁定", - "next": "下一步", - "setNewPassword": "设置新密码", - "enterPin": "输入 PIN 码", - "setNewPin": "设置新 PIN 码", - "appLock": "应用锁", - "noSystemLockFound": "未找到系统锁", - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "要启用应用锁,请在系统设置中设置设备密码或屏幕锁定。", - "tapToUnlock": "点击解锁", - "tooManyIncorrectAttempts": "错误尝试次数过多", - "mlFunctions": "ML functions", "useAsCover": "用作封面", "notPersonLabel": "不是 {name}?", "@notPersonLabel": { @@ -1278,9 +1274,25 @@ } } }, + "enable": "启用", + "enabled": "已启用", + "moreDetails": "更多详情", + "enableMLIndexingDesc": "Ente 支持设备上的机器学习,实现人脸识别、魔法搜索和其他高级搜索功能", + "magicSearchHint": "魔法搜索允许按内容搜索照片,例如“lower'”、“red car”、“identity documents”", "panorama": "全景", + "reenterPassword": "再次输入密码", + "reenterPin": "再次输入 PIN 码", + "deviceLock": "设备锁", + "pinLock": "PIN 锁定", + "next": "下一步", + "setNewPassword": "设置新密码", + "enterPin": "输入 PIN 码", + "setNewPin": "设置新 PIN 码", + "appLock": "应用锁", + "noSystemLockFound": "未找到系统锁", + "tapToUnlock": "点击解锁", + "tooManyIncorrectAttempts": "错误尝试次数过多", "videoInfo": "视频详情", - "appLockDescription": "在设备的默认锁定屏幕和带有 PIN 或密码的自定义锁定屏幕之间进行选择。", "autoLock": "自动锁定", "immediately": "立即", "autoLockFeatureDescription": "应用程序进入后台后锁定的时间", @@ -1295,12 +1307,13 @@ "guestView": "访客视图", "guestViewEnablePreSteps": "要启用访客视图,请在系统设置中设置设备密码或屏幕锁。", "cl_guest_view_title": "访客视图", - "cl_guest_view_description": "要把手机递给朋友看照片?别担心他们滑动太远。访客视图将锁定您选择的照片。", - "cl_guest_view_call_to_action": "选择照片并查看\"访客视图\"。", - "cl_panorama_viewer_title": "全景查看器", - "cl_panorama_viewer_description": "我们新增了支持 360 度全景照片查看功能。结合动作导航,体验更加身临其境!", + "cl_guest_view_description": "把手机交给朋友看照片?不用担心 Ta 们滑动屏幕乱看照片。访客视图会将 Ta 们锁定在您选择的照片中。", + "cl_guest_view_call_to_action": "选择照片并使用“访客视图”。", + "cl_panorama_viewer_title": "全景图查看器", + "cl_panorama_viewer_description": "我们添加了对 360 度全景照片的支持。通过基于动作的导航,用户可获得身临其境的体验!", "cl_video_player_title": "视频播放器", - "cl_video_player_description": "推出全新的视频播放器,具有更好的播放控制功能并支持 HDR 视频。", - "appLockDescriptions": "Choose between your device's default lock screen and a custom lock screen with a PIN or password.", - "authToViewPasskey": "Please authenticate to view your passkey" + "cl_video_player_description": "推出全新的视频播放器,提供更好的播放控制并添加了对 HDR 视频的支持。", + "appLockDescriptions": "在设备的默认锁定屏幕和带有 PIN 或密码的自定义锁定屏幕之间进行选择。", + "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "要启用应用锁,请在系统设置中设置设备密码或屏幕锁。", + "authToViewPasskey": "请验证身份以查看您的通行密钥" } \ No newline at end of file From 6c5dd38dbf0fd073eb20196275c1aaf22c8dcdfa Mon Sep 17 00:00:00 2001 From: ashilkn Date: Tue, 27 Aug 2024 14:06:50 +0530 Subject: [PATCH 027/275] [mob][photos] Update flutter version to 3.24.1 in README.md --- mobile/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/README.md b/mobile/README.md index bd937f4ed2..9e3ed475f4 100644 --- a/mobile/README.md +++ b/mobile/README.md @@ -46,7 +46,7 @@ You can alternatively install the build from PlayStore or F-Droid. ## 🧑‍💻 Building from source -1. [Install Flutter v3.24.0](https://flutter.dev/docs/get-started/install). +1. [Install Flutter v3.24.1](https://flutter.dev/docs/get-started/install). 2. Pull in all submodules with `git submodule update --init --recursive` From 55b4ce83262d26497633340ade22b739ddc9d770 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Tue, 27 Aug 2024 14:09:27 +0530 Subject: [PATCH 028/275] [mob][photos] Update flutter version in github workflows --- .github/workflows/mobile-internal-release.yml | 2 +- .github/workflows/mobile-lint.yml | 2 +- .github/workflows/mobile-release.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/mobile-internal-release.yml b/.github/workflows/mobile-internal-release.yml index 2eb9979bf9..a05fdcc236 100644 --- a/.github/workflows/mobile-internal-release.yml +++ b/.github/workflows/mobile-internal-release.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: # Allow manually running the action env: - FLUTTER_VERSION: "3.22.2" + FLUTTER_VERSION: "3.24.1" jobs: build: diff --git a/.github/workflows/mobile-lint.yml b/.github/workflows/mobile-lint.yml index 0a57c0b30b..27a3303294 100644 --- a/.github/workflows/mobile-lint.yml +++ b/.github/workflows/mobile-lint.yml @@ -9,7 +9,7 @@ on: env: - FLUTTER_VERSION: "3.22.2" + FLUTTER_VERSION: "3.24.1" jobs: lint: diff --git a/.github/workflows/mobile-release.yml b/.github/workflows/mobile-release.yml index 363f232c80..e1d5998387 100644 --- a/.github/workflows/mobile-release.yml +++ b/.github/workflows/mobile-release.yml @@ -9,7 +9,7 @@ on: - "photos-v*" env: - FLUTTER_VERSION: "3.22.2" + FLUTTER_VERSION: "3.24.1" jobs: build: From b1f3b440f7ab74ac6533d5f0a8cc995df0be0296 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Tue, 27 Aug 2024 14:18:17 +0530 Subject: [PATCH 029/275] [mob][photos] changes in pubspec.lock --- mobile/pubspec.lock | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/mobile/pubspec.lock b/mobile/pubspec.lock index 7388ae92f2..0223bc5236 100644 --- a/mobile/pubspec.lock +++ b/mobile/pubspec.lock @@ -1297,18 +1297,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.4" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: @@ -1441,10 +1441,10 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" media_extension: dependency: "direct main" description: @@ -1529,10 +1529,10 @@ packages: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.15.0" mgrs_dart: dependency: transitive description: @@ -1901,10 +1901,10 @@ packages: dependency: transitive description: name: platform - sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "3.1.5" plugin_platform_interface: dependency: transitive description: @@ -2410,26 +2410,26 @@ packages: dependency: "direct dev" description: name: test - sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073" + sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e" url: "https://pub.dev" source: hosted - version: "1.25.2" + version: "1.25.7" test_api: dependency: transitive description: name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.7.2" test_core: dependency: transitive description: name: test_core - sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4" + sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.6.4" timezone: dependency: transitive description: @@ -2708,10 +2708,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.2.1" + version: "14.2.5" volume_controller: dependency: transitive description: From 4278e9c47441532c94e212a9a643b2ae999633fc Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 14:34:26 +0530 Subject: [PATCH 030/275] [mob]Remove dst from crowdin template --- mobile/crowdin.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/mobile/crowdin.yml b/mobile/crowdin.yml index 27c72a52b0..7bacd35953 100644 --- a/mobile/crowdin.yml +++ b/mobile/crowdin.yml @@ -4,7 +4,6 @@ preserve_hierarchy: true files: - source: /lib/l10n/intl_en.arb translation: /lib/l10n/intl_%two_letters_code%.arb - dest: /%original_file_name% type: arb - source: /fastlane/metadata/playstore/en-US/*.txt translation: /fastlane/metadata/playstore/%two_letters_code%/%original_file_name% From ac3061a23204e89e1bfabf76bc4d987d9dcb0b84 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 14:41:58 +0530 Subject: [PATCH 031/275] Revert "[mob]Remove dst from crowdin template" This reverts commit 4278e9c47441532c94e212a9a643b2ae999633fc. --- mobile/crowdin.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/mobile/crowdin.yml b/mobile/crowdin.yml index 7bacd35953..27c72a52b0 100644 --- a/mobile/crowdin.yml +++ b/mobile/crowdin.yml @@ -4,6 +4,7 @@ preserve_hierarchy: true files: - source: /lib/l10n/intl_en.arb translation: /lib/l10n/intl_%two_letters_code%.arb + dest: /%original_file_name% type: arb - source: /fastlane/metadata/playstore/en-US/*.txt translation: /fastlane/metadata/playstore/%two_letters_code%/%original_file_name% From 9b82ba22a33a48af94cb1e8f4b1a112e1ed69d62 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Tue, 27 Aug 2024 11:41:59 +0200 Subject: [PATCH 032/275] [mob][photos] Remove last tflite remnants --- mobile/.gitignore | 1 - mobile/docs/dev.md | 21 +-------------------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/mobile/.gitignore b/mobile/.gitignore index b6ee5c6161..452efa9a2c 100644 --- a/mobile/.gitignore +++ b/mobile/.gitignore @@ -40,4 +40,3 @@ android/.settings/ .env fastlane/report.xml -TensorFlowLiteC.framework diff --git a/mobile/docs/dev.md b/mobile/docs/dev.md index e13ffe2c9e..53a7c25ad6 100644 --- a/mobile/docs/dev.md +++ b/mobile/docs/dev.md @@ -12,23 +12,4 @@ cd ios && pod install && cd .. ```sh sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer sudo xcodebuild -runFirstLaunch -``` - -#### Error (Xcode): Framework not found TensorFlowLiteC - -Copy tflite package from pub.dev to pub.dartlang.org - -```sh -cp -r ~/.pub-cache/hosted/pub.dev/tflite_flutter-0.9.1 ~/.pub-cache/hosted/pub.dartlang.org/tflite_flutter-0.9.1 -``` - -Run setup.sh -```bash -./setup.sh -``` - -Install the pod again - -```bash -cd ios && pod install && cd .. -``` +``` \ No newline at end of file From 8044bd75dfc03a084a2f9a150824e6e880f927cc Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Tue, 27 Aug 2024 12:09:51 +0200 Subject: [PATCH 033/275] [mob][photos] stop annoying analyzer emphasis --- mobile/lib/services/user_service.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mobile/lib/services/user_service.dart b/mobile/lib/services/user_service.dart index 4c20429b08..03e8646a83 100644 --- a/mobile/lib/services/user_service.dart +++ b/mobile/lib/services/user_service.dart @@ -610,7 +610,7 @@ class UserService { SetupSRPResponse.fromJson(response.data); final serverB = SRP6Util.decodeBigInt(base64Decode(setupSRPResponse.srpB)); - // ignore: need to calculate secret to get M1, unused_local_variable + // ignore: unused_local_variable, need to calculate secret to get M1 final clientS = client.calculateSecret(serverB); final clientM = client.calculateClientEvidenceMessage(); // ignore: unused_local_variable @@ -696,7 +696,7 @@ class UserService { final String srpB = createSessionResponse.data["srpB"]; final serverB = SRP6Util.decodeBigInt(base64Decode(srpB)); - // ignore: need to calculate secret to get M1, unused_local_variable + // ignore: unused_local_variable, need to calculate secret to get M1, final clientS = client.calculateSecret(serverB); final clientM = client.calculateClientEvidenceMessage(); final response = await _dio.post( From cba69a84d3882f77fba7ffdf870e9f44b4370d26 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:39:41 +0530 Subject: [PATCH 034/275] [mob] Skip exporting untranslated strings for store listing --- mobile/crowdin.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mobile/crowdin.yml b/mobile/crowdin.yml index 27c72a52b0..fca358689a 100644 --- a/mobile/crowdin.yml +++ b/mobile/crowdin.yml @@ -6,15 +6,19 @@ files: translation: /lib/l10n/intl_%two_letters_code%.arb dest: /%original_file_name% type: arb + skip_untranslated_files: false - source: /fastlane/metadata/playstore/en-US/*.txt translation: /fastlane/metadata/playstore/%two_letters_code%/%original_file_name% dest: /playstore/%original_file_name% type: txt + skip_untranslated_files: true - source: /fastlane/metadata/android/en-US/*.txt translation: /fastlane/metadata/android/%two_letters_code%/%original_file_name% dest: /fdroid/%original_file_name% type: txt + skip_untranslated_files: true - source: /fastlane/metadata/ios/en-US/*.txt translation: /fastlane/metadata/ios/%two_letters_code%/%original_file_name% dest: /appstore/%original_file_name% type: txt + skip_untranslated_files: true From 5e05e50049c465725769c8556252d3621b671811 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:46:43 +0530 Subject: [PATCH 035/275] [mob] Fix lint --- mobile/lib/services/user_service.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mobile/lib/services/user_service.dart b/mobile/lib/services/user_service.dart index 4c20429b08..fca3fbcff5 100644 --- a/mobile/lib/services/user_service.dart +++ b/mobile/lib/services/user_service.dart @@ -610,7 +610,8 @@ class UserService { SetupSRPResponse.fromJson(response.data); final serverB = SRP6Util.decodeBigInt(base64Decode(setupSRPResponse.srpB)); - // ignore: need to calculate secret to get M1, unused_local_variable + + // ignore: unused_local_variable final clientS = client.calculateSecret(serverB); final clientM = client.calculateClientEvidenceMessage(); // ignore: unused_local_variable @@ -696,7 +697,7 @@ class UserService { final String srpB = createSessionResponse.data["srpB"]; final serverB = SRP6Util.decodeBigInt(base64Decode(srpB)); - // ignore: need to calculate secret to get M1, unused_local_variable + // ignore: unused_local_variable final clientS = client.calculateSecret(serverB); final clientM = client.calculateClientEvidenceMessage(); final response = await _dio.post( From b9f8f55a30fd6a13de54657f53d746ea7227e441 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:57:58 +0530 Subject: [PATCH 036/275] [mob] Upgrade crowdin config --- .github/workflows/mobile-crowdin-sync.yml | 1 - mobile/crowdin.yml | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mobile-crowdin-sync.yml b/.github/workflows/mobile-crowdin-sync.yml index 5f8da62b4d..39062cd6f5 100644 --- a/.github/workflows/mobile-crowdin-sync.yml +++ b/.github/workflows/mobile-crowdin-sync.yml @@ -26,7 +26,6 @@ jobs: download_translations: true localization_branch_name: translations/mobile create_pull_request: true - skip_untranslated_strings: true pull_request_title: "[mobile] New translations" pull_request_body: "New translations from [Crowdin](https://crowdin.com/project/ente-photos-app)" pull_request_base_branch_name: "main" diff --git a/mobile/crowdin.yml b/mobile/crowdin.yml index fca358689a..c478a5ded7 100644 --- a/mobile/crowdin.yml +++ b/mobile/crowdin.yml @@ -6,6 +6,7 @@ files: translation: /lib/l10n/intl_%two_letters_code%.arb dest: /%original_file_name% type: arb + skip_untranslated_strings: false skip_untranslated_files: false - source: /fastlane/metadata/playstore/en-US/*.txt translation: /fastlane/metadata/playstore/%two_letters_code%/%original_file_name% From c2a5f85a02857d45a711d63c1dd97a2d0a15660e Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 16:02:10 +0530 Subject: [PATCH 037/275] [mob] Skip untranslated strings --- mobile/crowdin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/crowdin.yml b/mobile/crowdin.yml index c478a5ded7..efe5e4de50 100644 --- a/mobile/crowdin.yml +++ b/mobile/crowdin.yml @@ -6,7 +6,7 @@ files: translation: /lib/l10n/intl_%two_letters_code%.arb dest: /%original_file_name% type: arb - skip_untranslated_strings: false + skip_untranslated_strings: true skip_untranslated_files: false - source: /fastlane/metadata/playstore/en-US/*.txt translation: /fastlane/metadata/playstore/%two_letters_code%/%original_file_name% From 4649561886015e463a1df6243bd1b0fd747e732b Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Tue, 27 Aug 2024 10:33:54 +0000 Subject: [PATCH 038/275] New Crowdin translations by GitHub Action --- mobile/lib/l10n/intl_ar.arb | 27 + mobile/lib/l10n/intl_bg.arb | 3 + mobile/lib/l10n/intl_ca.arb | 3 + mobile/lib/l10n/intl_cs.arb | 60 +- mobile/lib/l10n/intl_da.arb | 89 +++ mobile/lib/l10n/intl_de.arb | 1 - mobile/lib/l10n/intl_el.arb | 4 + mobile/lib/l10n/intl_es.arb | 85 ++- mobile/lib/l10n/intl_et.arb | 3 + mobile/lib/l10n/intl_fa.arb | 312 ++++++++++ mobile/lib/l10n/intl_fr.arb | 284 ++++++---- mobile/lib/l10n/intl_gu.arb | 3 + mobile/lib/l10n/intl_he.arb | 823 +++++++++++++++++++++++++++ mobile/lib/l10n/intl_hi.arb | 53 ++ mobile/lib/l10n/intl_id.arb | 1069 +++++++++++++++++++++++++++++++++++ mobile/lib/l10n/intl_it.arb | 134 ++--- mobile/lib/l10n/intl_ja.arb | 3 + mobile/lib/l10n/intl_km.arb | 3 + mobile/lib/l10n/intl_ko.arb | 73 +-- mobile/lib/l10n/intl_nl.arb | 84 +-- mobile/lib/l10n/intl_no.arb | 420 ++++++++++++-- mobile/lib/l10n/intl_ru.arb | 86 +-- mobile/lib/l10n/intl_sv.arb | 427 ++++++++++++++ mobile/lib/l10n/intl_te.arb | 3 + mobile/lib/l10n/intl_th.arb | 301 ++++++++++ mobile/lib/l10n/intl_ti.arb | 3 + mobile/lib/l10n/intl_tr.arb | 134 +---- 27 files changed, 3860 insertions(+), 630 deletions(-) create mode 100644 mobile/lib/l10n/intl_ar.arb create mode 100644 mobile/lib/l10n/intl_bg.arb create mode 100644 mobile/lib/l10n/intl_ca.arb create mode 100644 mobile/lib/l10n/intl_da.arb create mode 100644 mobile/lib/l10n/intl_el.arb create mode 100644 mobile/lib/l10n/intl_et.arb create mode 100644 mobile/lib/l10n/intl_fa.arb create mode 100644 mobile/lib/l10n/intl_gu.arb create mode 100644 mobile/lib/l10n/intl_he.arb create mode 100644 mobile/lib/l10n/intl_hi.arb create mode 100644 mobile/lib/l10n/intl_id.arb create mode 100644 mobile/lib/l10n/intl_ja.arb create mode 100644 mobile/lib/l10n/intl_km.arb create mode 100644 mobile/lib/l10n/intl_sv.arb create mode 100644 mobile/lib/l10n/intl_te.arb create mode 100644 mobile/lib/l10n/intl_th.arb create mode 100644 mobile/lib/l10n/intl_ti.arb diff --git a/mobile/lib/l10n/intl_ar.arb b/mobile/lib/l10n/intl_ar.arb new file mode 100644 index 0000000000..86273581a6 --- /dev/null +++ b/mobile/lib/l10n/intl_ar.arb @@ -0,0 +1,27 @@ +{ + "@@locale ": "en", + "enterYourEmailAddress": "أدخل عنوان بريدك الإلكتروني", + "accountWelcomeBack": "مرحبًا مجددًا!", + "email": "البريد الإلكتروني", + "cancel": "إلغاء", + "verify": "التحقّق", + "invalidEmailAddress": "عنوان البريد الإلكتروني غير صالح", + "thisWillLogYouOutOfThisDevice": "سيؤدي هذا إلى تسجيل خروجك من هذا الجهاز!", + "thisWillLogYouOutOfTheFollowingDevice": "سيؤدي هذا إلى تسجيل خروجك من الجهاز التالي:", + "terminateSession": "إنهاء الجلسة؟", + "terminate": "إنهاء", + "thisDevice": "هذا الجهاز", + "recoverButton": "استرداد", + "recoverySuccessful": "نجح الاسترداد!", + "decrypting": "فك التشفير...", + "incorrectRecoveryKeyTitle": "مفتاح الاسترداد غير صحيح", + "incorrectRecoveryKeyBody": "مفتاح الاسترداد الذي أدخلته غير صحيح", + "forgotPassword": "نسيت كلمة المرور", + "enterYourRecoveryKey": "أدخل رمز الاسترداد", + "noRecoveryKey": "ما من مفتاح استرداد؟", + "sorry": "المعذرة", + "noRecoveryKeyNoDecryption": "لا يمكن فك تشفير بياناتك دون كلمة المرور أو مفتاح الاسترداد بسبب طبيعة بروتوكول التشفير الخاص بنا من النهاية إلى النهاية", + "verifyEmail": "التحقق من البريد الإلكتروني", + "toResetVerifyEmail": "لإعادة تعيين كلمة المرور، يرجى التحقق من بريدك الإلكتروني أولاً.", + "ackPasswordLostWarning": "أُدركُ أنّني فقدتُ كلمة مروري، فقد أفقد بياناتي لأن بياناتي مشفرة تشفيرًا تامًّا من النهاية إلى النهاية." +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_bg.arb b/mobile/lib/l10n/intl_bg.arb new file mode 100644 index 0000000000..c8494661c6 --- /dev/null +++ b/mobile/lib/l10n/intl_bg.arb @@ -0,0 +1,3 @@ +{ + "@@locale ": "en" +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ca.arb b/mobile/lib/l10n/intl_ca.arb new file mode 100644 index 0000000000..c8494661c6 --- /dev/null +++ b/mobile/lib/l10n/intl_ca.arb @@ -0,0 +1,3 @@ +{ + "@@locale ": "en" +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_cs.arb b/mobile/lib/l10n/intl_cs.arb index 49563ff49d..c8494661c6 100644 --- a/mobile/lib/l10n/intl_cs.arb +++ b/mobile/lib/l10n/intl_cs.arb @@ -1,61 +1,3 @@ { - "addToHiddenAlbum": "Add to hidden album", - "moveToHiddenAlbum": "Move to hidden album", - "fileTypes": "File types", - "deleteConfirmDialogBody": "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted.", - "yourMap": "Your map", - "modifyYourQueryOrTrySearchingFor": "Modify your query, or try searching for", - "contacts": "Contacts", - "editLocation": "Edit location", - "selectALocation": "Select a location", - "selectALocationFirst": "Select a location first", - "changeLocationOfSelectedItems": "Change location of selected items?", - "editsToLocationWillOnlyBeSeenWithinEnte": "Edits to location will only be seen within Ente", - "joinDiscord": "Join Discord", - "locations": "Locations", - "descriptions": "Descriptions", - "addViewers": "{count, plural, zero {Add viewer} one {Add viewer} other {Add viewers}}", - "addCollaborators": "{count, plural, zero {Add collaborator} one {Add collaborator} other {Add collaborators}}", - "longPressAnEmailToVerifyEndToEndEncryption": "Long press an email to verify end to end encryption.", - "createCollaborativeLink": "Create collaborative link", - "search": "Search", - "enterPersonName": "Enter person name", - "removePersonLabel": "Remove person label", - "faceRecognition": "Face recognition", - "faceRecognitionIndexingDescription": "Please note that this will result in a higher bandwidth and battery usage until all items are indexed.", - "foundFaces": "Found faces", - "clusteringProgress": "Clustering progress", - "indexingIsPaused": "Indexing is paused, will automatically resume when device is ready", - "reenterPassword": "Re-enter password", - "mlFunctions": "ML functions", - "reenterPin": "Re-enter PIN", - "deviceLock": "Device lock", - "pinLock": "PIN lock", - "passwordLock": "Password lock", - "next": "Next", - "setNewPassword": "Set new password", - "enterPin": "Enter PIN", - "setNewPin": "Set new PIN", - "appLock": "App lock", - "noSystemLockFound": "No system lock found", - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "To enable app lock, please setup device passcode or screen lock in your system settings.", - "tapToUnlock": "Tap to unlock", - "tooManyIncorrectAttempts": "Too many incorrect attempts", - "appLockDescription": "Choose between your device\\'s default lock screen and a custom lock screen with a PIN or password.", - "swipeLockEnablePreSteps": "To enable swipe lock, please setup device passcode or screen lock in your system settings.", - "autoLock": "Auto lock", - "immediately": "Immediately", - "autoLockFeatureDescription": "Time after which the app locks after being put in the background", - "hideContent": "Hide content", - "hideContentDescriptionAndroid": "Hides app content in the app switcher and disables screenshots", - "hideContentDescriptionIos": "Hides app content in the app switcher", - "passwordStrengthInfo": "Password strength is calculated considering the length of the password, used characters, and whether or not the password appears in the top 10,000 most used passwords", - "noQuickLinksSelected": "No quick links selected", - "pleaseSelectQuickLinksToRemove": "Please select quick links to remove", - "removePublicLinks": "Remove public links", - "thisWillRemovePublicLinksOfAllSelectedQuickLinks": "This will remove public links of all selected quick links.", - "guestView": "Guest view", - "guestViewEnablePreSteps": "To enable guest view, please setup device passcode or screen lock in your system settings.", - "appLockDescriptions": "Choose between your device's default lock screen and a custom lock screen with a PIN or password.", - "authToViewPasskey": "Please authenticate to view your passkey" + "@@locale ": "en" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_da.arb b/mobile/lib/l10n/intl_da.arb new file mode 100644 index 0000000000..49c26657f9 --- /dev/null +++ b/mobile/lib/l10n/intl_da.arb @@ -0,0 +1,89 @@ +{ + "@@locale ": "en", + "enterYourEmailAddress": "Indtast din email adresse", + "accountWelcomeBack": "Velkommen tilbage!", + "email": "Email", + "cancel": "Annuller", + "verify": "Bekræft", + "invalidEmailAddress": "Ugyldig email adresse", + "enterValidEmail": "Indtast venligst en gyldig email adresse.", + "deleteAccount": "Slet konto", + "askDeleteReason": "Hvad er hovedårsagen til, at du sletter din konto?", + "deleteAccountFeedbackPrompt": "Vi er kede af at du forlader os. Forklar venligst hvorfor, så vi kan forbedre os.", + "feedback": "Feedback", + "kindlyHelpUsWithThisInformation": "Hjælp os venligst med disse oplysninger", + "confirmDeletePrompt": "Ja, jeg ønsker at slette denne konto og alle dens data permanent.", + "confirmAccountDeletion": "Bekræft Sletning Af Konto", + "deleteAccountPermanentlyButton": "Slet konto permanent", + "yourAccountHasBeenDeleted": "Din konto er blevet slettet", + "selectReason": "Vælg årsag", + "deleteReason1": "Der mangler en vigtig funktion, som jeg har brug for", + "deleteReason3": "Jeg fandt en anden tjeneste, som jeg syntes bedre om", + "deleteReason4": "Min grund er ikke angivet", + "sendEmail": "Send email", + "deleteRequestSLAText": "Din anmodning vil blive behandlet inden for 72 timer.", + "deleteEmailRequest": "Send venligst en email til account-deletion@ente.io fra din registrerede email adresse.", + "ok": "Ok", + "createAccount": "Opret konto", + "createNewAccount": "Opret en ny konto", + "password": "Adgangskode", + "confirmPassword": "Bekræft adgangskode", + "activeSessions": "Aktive sessioner", + "oops": "Ups", + "somethingWentWrongPleaseTryAgain": "Noget gik galt, prøv venligst igen", + "thisWillLogYouOutOfThisDevice": "Dette vil logge dig ud af denne enhed!", + "thisWillLogYouOutOfTheFollowingDevice": "Dette vil logge dig ud af følgende enhed:", + "terminateSession": "Afslut session?", + "incorrectRecoveryKeyBody": "Den gendannelsesnøgle du indtastede er forkert", + "forgotPassword": "Glemt adgangskode", + "incorrectPasswordTitle": "Forkert adgangskode", + "copypasteThisCodentoYourAuthenticatorApp": "Kopiér denne kode\ntil din autentificeringsapp", + "scanThisBarcodeWithnyourAuthenticatorApp": "Skan denne QR-kode med godkendelses-appen", + "manage": "Administrér", + "shareTextConfirmOthersVerificationID": "Hey, kan du bekræfte, at dette er dit ente.io verifikation ID: {verificationID}", + "subscribe": "Abonner", + "memoryCount": "{count, plural, zero{ingen minder} one{{formattedCount} minde} other{{formattedCount} minder}}", + "@memoryCount": { + "description": "The text to display the number of memories", + "type": "text", + "placeholders": { + "count": { + "example": "1", + "type": "int" + }, + "formattedCount": { + "type": "String", + "example": "11.513, 11,511" + } + } + }, + "selectedPhotos": "{count} valgt", + "@selectedPhotos": { + "description": "Display the number of selected photos", + "type": "text", + "placeholders": { + "count": { + "example": "5", + "type": "int" + } + } + }, + "mlIndexingDescription": "Bemærk venligst, at maskinindlæring vil resultere i en højere båndbredde og batteriforbrug, indtil alle elementer er indekseret. Overvej at bruge desktop app til hurtigere indeksering, vil alle resultater blive synkroniseret automatisk.", + "backedUpFolders": "Sikkerhedskopierede mapper", + "couldNotUpdateSubscription": "Abonnementet kunne ikke opdateres.", + "pleaseContactSupportAndWeWillBeHappyToHelp": "Kontakt support@ente.io og vi vil være glade for at hjælpe!", + "loggingOut": "Logger ud...", + "invite": "Inviter", + "fileSavedToGallery": "Fil gemt i galleri", + "renameFile": "Omdøb fil", + "moments": "Øjeblikke", + "familyPlanPortalTitle": "Familie", + "viewAddOnButton": "Vis tilføjelser", + "addOnPageSubtitle": "Oplysninger om tilføjelser", + "searchHint1": "Hurtig, søgning på enheden", + "findPeopleByName": "Find folk hurtigt ved navn", + "longPressAnEmailToVerifyEndToEndEncryption": "Langt tryk på en e-mail for at bekræfte slutningen af krypteringen.", + "developerSettingsWarning": "Er du sikker på, at du vil ændre udviklerindstillingerne?", + "next": "Næste", + "enterPin": "Indtast PIN" +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_de.arb b/mobile/lib/l10n/intl_de.arb index 97160ae71f..aa50482f8d 100644 --- a/mobile/lib/l10n/intl_de.arb +++ b/mobile/lib/l10n/intl_de.arb @@ -496,7 +496,6 @@ "removeDuplicates": "Duplikate entfernen", "removeDuplicatesDesc": "Überprüfe und lösche Dateien, die exakte Duplikate sind.", "viewLargeFiles": "Große Dateien", - "viewLargeFilesDesc": "Dateien anzeigen, die den meisten Speicherplatz belegen", "noDuplicates": "✨ Keine Duplikate", "youveNoDuplicateFilesThatCanBeCleared": "Du hast keine Duplikate, die gelöscht werden können", "success": "Abgeschlossen", diff --git a/mobile/lib/l10n/intl_el.arb b/mobile/lib/l10n/intl_el.arb new file mode 100644 index 0000000000..ce8b1a1a54 --- /dev/null +++ b/mobile/lib/l10n/intl_el.arb @@ -0,0 +1,4 @@ +{ + "@@locale ": "en", + "enterYourEmailAddress": "Εισάγετε την διεύθυνση ηλ. ταχυδρομείου σας" +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_es.arb b/mobile/lib/l10n/intl_es.arb index 8b6bef5acc..238f61095f 100644 --- a/mobile/lib/l10n/intl_es.arb +++ b/mobile/lib/l10n/intl_es.arb @@ -1,4 +1,5 @@ { + "@@locale ": "en", "enterYourEmailAddress": "Escribe tu correo electrónico", "accountWelcomeBack": "¡Bienvenido de nuevo!", "email": "Correo electrónico", @@ -12,7 +13,7 @@ "feedback": "Sugerencias", "kindlyHelpUsWithThisInformation": "Por favor ayúdanos con esta información", "confirmDeletePrompt": "Sí, quiero eliminar permanentemente esta cuenta y todos sus datos.", - "confirmAccountDeletion": "Corfirmar borrado de cuenta", + "confirmAccountDeletion": "Confirmar borrado de cuenta", "deleteAccountPermanentlyButton": "Eliminar cuenta permanentemente", "yourAccountHasBeenDeleted": "Tu cuenta ha sido eliminada", "selectReason": "Seleccionar motivo", @@ -73,7 +74,7 @@ "weakStrength": "Poco segura", "strongStrength": "Segura", "moderateStrength": "Moderada", - "passwordStrength": "Seguridad de la contraseña : {passwordStrengthValue}", + "passwordStrength": "Seguridad de la contraseña: {passwordStrengthValue}", "@passwordStrength": { "description": "Text to indicate the password strength", "placeholders": { @@ -409,7 +410,6 @@ "manageDeviceStorage": "Administrar almacenamiento del dispositivo", "machineLearning": "Aprendizaje automático", "magicSearch": "Búsqueda mágica", - "mlIndexingDescription": "Por favor, ten en cuenta que el aprendizaje automático resultará en un mayor ancho de banda y uso de batería hasta que todos los elementos sean indexados.", "loadingModel": "Descargando modelos...", "waitingForWifi": "Esperando WiFi...", "status": "Estado", @@ -485,7 +485,6 @@ "removeDuplicates": "Eliminar duplicados", "removeDuplicatesDesc": "Revisar y eliminar archivos que son duplicados exactos.", "viewLargeFiles": "Archivos grandes", - "viewLargeFilesDesc": "Ver archivos que consumen la mayor cantidad de almacenamiento", "noDuplicates": "✨ Sin duplicados", "youveNoDuplicateFilesThatCanBeCleared": "No tienes archivos duplicados que puedan ser borrados", "success": "Éxito", @@ -739,7 +738,7 @@ "unhide": "Dejar de ocultar", "unarchive": "Desarchivar", "favorite": "Favorito", - "removeFromFavorite": "Quitar de favoritos", + "removeFromFavorite": "Remover desde favoritos", "shareLink": "Compartir enlace", "createCollage": "Crear un collage", "saveCollage": "Guardar collage", @@ -1251,42 +1250,42 @@ "right": "Derecha", "whatsNew": "Qué hay de nuevo", "reviewSuggestions": "Revisar sugerencias", - "reenterPassword": "Re-enter password", - "mlFunctions": "ML functions", - "reenterPin": "Re-enter PIN", - "deviceLock": "Device lock", - "pinLock": "PIN lock", - "next": "Next", - "setNewPassword": "Set new password", - "enterPin": "Enter PIN", - "setNewPin": "Set new PIN", - "appLock": "App lock", - "noSystemLockFound": "No system lock found", - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "To enable app lock, please setup device passcode or screen lock in your system settings.", - "tapToUnlock": "Tap to unlock", - "tooManyIncorrectAttempts": "Too many incorrect attempts", - "appLockDescription": "Choose between your device\\'s default lock screen and a custom lock screen with a PIN or password.", - "swipeLockEnablePreSteps": "To enable swipe lock, please setup device passcode or screen lock in your system settings.", - "autoLock": "Auto lock", - "immediately": "Immediately", - "autoLockFeatureDescription": "Time after which the app locks after being put in the background", - "hideContent": "Hide content", - "hideContentDescriptionAndroid": "Hides app content in the app switcher and disables screenshots", - "hideContentDescriptionIos": "Hides app content in the app switcher", - "passwordStrengthInfo": "Password strength is calculated considering the length of the password, used characters, and whether or not the password appears in the top 10,000 most used passwords", - "noQuickLinksSelected": "No quick links selected", - "pleaseSelectQuickLinksToRemove": "Please select quick links to remove", - "removePublicLinks": "Remove public links", - "thisWillRemovePublicLinksOfAllSelectedQuickLinks": "This will remove public links of all selected quick links.", - "guestView": "Guest view", - "guestViewEnablePreSteps": "To enable guest view, please setup device passcode or screen lock in your system settings.", - "cl_guest_view_title": "Vista de Invitado", - "cl_guest_view_description": "¿Vas a mostrar fotos a un amigo? No te preocupes por si desliza demasiado. La vista de invitado bloqueará las fotos que selecciones.", - "cl_guest_view_call_to_action": "Selecciona fotos y prueba la \"Vista de Invitado\".", - "cl_panorama_viewer_title": "Visor Panorámico", - "cl_panorama_viewer_description": "Hemos añadido soporte para ver fotos panorámicas con vistas de 360 grados. ¡La experiencia es inmersiva con navegación basada en el movimiento!", - "cl_video_player_title": "Reproductor de Video", - "cl_video_player_description": "Presentamos un nuevo reproductor de video, con mejores controles de reproducción y soporte para videos HDR.", - "appLockDescriptions": "Choose between your device's default lock screen and a custom lock screen with a PIN or password.", - "authToViewPasskey": "Please authenticate to view your passkey" + "useAsCover": "Usar como cubierta", + "notPersonLabel": "¿No es {name}?", + "@notPersonLabel": { + "description": "Label to indicate that the person in the photo is not the person whose name is mentioned", + "placeholders": { + "name": { + "content": "{name}", + "type": "String" + } + } + }, + "panorama": "Panorama", + "reenterPassword": "Rescribe tu contraseña", + "reenterPin": "Rescribe tu PIN", + "deviceLock": "Dispositivo Bloqueado", + "pinLock": "PIN Bloqueado", + "next": "Siguiente", + "setNewPassword": "Ingresa tu nueva contraseña", + "enterPin": "Ingresa tu contraseña", + "setNewPin": "Ingresa tu nuevo PIN", + "appLock": "Aplicación bloqueada", + "noSystemLockFound": "Bloqueo de sistema no encontrado", + "tapToUnlock": "Toca para desbloquear", + "tooManyIncorrectAttempts": "Demasiados intentos incorrectos", + "videoInfo": "Información de video", + "autoLock": "Autobloqueo", + "immediately": "Inmediatamente", + "autoLockFeatureDescription": "Tiempo después de que la aplicación esté en segundo plano", + "hideContent": "Ocultar contenido", + "hideContentDescriptionAndroid": "Oculta el contenido de la aplicación en el selector de aplicaciones y desactivar capturas de pantalla", + "hideContentDescriptionIos": "Ocultar el contenido de la aplicación en el selector de aplicaciones", + "passwordStrengthInfo": "La intensidad de la contraseña se calcula teniendo en cuenta la longitud de la contraseña, los caracteres utilizados, y si la contraseña aparece o no en el top 10,000 de contraseñas más usadas", + "noQuickLinksSelected": "No se han seleccionado enlaces rápidos", + "pleaseSelectQuickLinksToRemove": "Por favor, selecciona enlaces rápidos para eliminar", + "removePublicLinks": "Eliminar enlaces públicos", + "thisWillRemovePublicLinksOfAllSelectedQuickLinks": "Esto eliminará los enlaces públicos de todos los enlaces rápidos seleccionados.", + "guestView": "Vista de invitado", + "guestViewEnablePreSteps": "Para habilitar la vista de invitados, por favor configure el código de acceso del dispositivo o el bloqueo de pantalla en los ajustes de su sistema." } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_et.arb b/mobile/lib/l10n/intl_et.arb new file mode 100644 index 0000000000..c8494661c6 --- /dev/null +++ b/mobile/lib/l10n/intl_et.arb @@ -0,0 +1,3 @@ +{ + "@@locale ": "en" +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_fa.arb b/mobile/lib/l10n/intl_fa.arb new file mode 100644 index 0000000000..d5dbe63862 --- /dev/null +++ b/mobile/lib/l10n/intl_fa.arb @@ -0,0 +1,312 @@ +{ + "@@locale ": "en", + "enterYourEmailAddress": "آدرس ایمیل خود را وارد کنید", + "accountWelcomeBack": "خوش آمدید!", + "email": "ایمیل", + "cancel": "لغو", + "verify": "تایید", + "invalidEmailAddress": "آدرس ایمیل معتبر نیست", + "enterValidEmail": "لطفا یک ایمیل معتبر وارد کنید.", + "deleteAccount": "حذف حساب کاربری", + "askDeleteReason": "دلیل اصلی که حساب کاربری‌تان را حذف می‌کنید، چیست؟", + "deleteAccountFeedbackPrompt": "ما متاسفیم که می‌بینیم شما می‌روید. لطفا نظرات خود را برای کمک به بهبود ما به اشتراک بگذارید.", + "feedback": "بازخورد", + "kindlyHelpUsWithThisInformation": "لطفا با این اطلاعات به ما کمک کنید", + "confirmDeletePrompt": "بله، من می‌خواهم برای همیشه این حساب کاربری و تمام اطلاعات آن را حذف کنم.", + "confirmAccountDeletion": "تایید حذف حساب کاربری", + "deleteAccountPermanentlyButton": "حذف دائمی حساب کاربری", + "yourAccountHasBeenDeleted": "حساب کاربری شما حذف شده است", + "selectReason": "انتخاب دلیل", + "deleteReason1": "یک ویژگی کلیدی که به آن نیاز دارم، وجود ندارد", + "deleteReason2": "برنامه یا یک ویژگی خاص آنطور که من فکر می‌کنم، عمل نمی‌کند", + "deleteReason3": "سرویس دیگری پیدا کردم که بهتر می‌پسندم", + "deleteReason4": "دلیل من ذکر نشده است", + "sendEmail": "ارسال ایمیل", + "deleteRequestSLAText": "درخواست شما ظرف مدت ۷۲ ساعت پردازش خواهد شد.", + "deleteEmailRequest": "لطفا یک ایمیل به account-deletion@ente.io از آدرس ایمیل ثبت شده خود ارسال کنید.", + "entePhotosPerm": "Ente برای نگه‌داری عکس‌های شما به دسترسی نیاز دارد", + "ok": "تایید", + "createAccount": "ایجاد حساب کاربری", + "createNewAccount": "ایجاد حساب کاربری جدید", + "password": "رمز عبور", + "confirmPassword": "تایید رمز عبور", + "activeSessions": "دستگاه‌های فعال", + "oops": "اوه", + "somethingWentWrongPleaseTryAgain": "مشکلی پیش آمده، لطفا دوباره تلاش کنید", + "thisWillLogYouOutOfThisDevice": "این کار شما را از این دستگاه خارج می‌کند!", + "thisWillLogYouOutOfTheFollowingDevice": "با این کار شما از دستگاه زیر خارج می‌شوید:", + "terminateSession": "خروچ دستگاه؟", + "terminate": "خروج", + "thisDevice": "این دستگاه", + "recoverButton": "بازیابی", + "recoverySuccessful": "بازیابی موفقیت آمیز بود!", + "decrypting": "در حال رمزگشایی...", + "incorrectRecoveryKeyTitle": "کلید بازیابی درست نیست", + "incorrectRecoveryKeyBody": "کلید بازیابی که وارد کردید درست نیست", + "forgotPassword": "رمز عبور را فراموش کرده‌اید", + "enterYourRecoveryKey": "کلید بازیابی خود را وارد کنید", + "noRecoveryKey": "کلید بازیابی ندارید؟", + "sorry": "متاسفیم", + "noRecoveryKeyNoDecryption": "با توجه به ماهیت پروتکل رمزگذاری سرتاسر ما، اطلاعات شما بدون رمز عبور یا کلید بازیابی شما قابل رمزگشایی نیست", + "verifyEmail": "تایید ایمیل", + "toResetVerifyEmail": "برای تنظیم مجدد رمز عبور، لطفا ابتدا ایمیل خود را تایید کنید.", + "checkInboxAndSpamFolder": "لطفا صندوق ورودی (و هرزنامه) خود را برای تایید کامل بررسی کنید", + "tapToEnterCode": "برای وارد کردن کد ضربه بزنید", + "resendEmail": "ارسال مجدد ایمیل", + "weHaveSendEmailTo": "ما یک ایمیل به {email} ارسال کرده‌ایم", + "@weHaveSendEmailTo": { + "description": "Text to indicate that we have sent a mail to the user", + "placeholders": { + "email": { + "description": "The email address of the user", + "type": "String", + "example": "example@ente.io" + } + } + }, + "setPasswordTitle": "تنظیم رمز عبور", + "changePasswordTitle": "تغییر رمز عبور", + "resetPasswordTitle": "بازنشانی رمز عبور", + "encryptionKeys": "کلیدهای رمزنگاری", + "passwordWarning": "ما این رمز عبور را ذخیره نمی‌کنیم، بنابراین اگر فراموش کنید، نمی‌توانیم اطلاعات شما را رمزگشایی کنیم", + "enterPasswordToEncrypt": "رمز عبوری را وارد کنید که بتوانیم از آن برای رمزگذاری اطلاعات شما استفاده کنیم", + "enterNewPasswordToEncrypt": "رمز عبور جدیدی را وارد کنید که بتوانیم از آن برای رمزگذاری اطلاعات شما استفاده کنیم", + "weakStrength": "ضعیف", + "strongStrength": "قوی", + "moderateStrength": "متوسط", + "passwordStrength": "قدرت رمز عبور: {passwordStrengthValue}", + "@passwordStrength": { + "description": "Text to indicate the password strength", + "placeholders": { + "passwordStrengthValue": { + "description": "The strength of the password as a string", + "type": "String", + "example": "Weak or Moderate or Strong" + } + }, + "message": "Password Strength: {passwordStrengthText}" + }, + "passwordChangedSuccessfully": "رمز عبور با موفقیت تغییر کرد", + "generatingEncryptionKeys": "در حال تولید کلیدهای رمزگذاری...", + "pleaseWait": "لطفا صبر کنید...", + "continueLabel": "ادامه", + "insecureDevice": "دستگاه ناامن", + "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": "با عرض پوزش، ما نمی‌توانیم کلیدهای امن را در این دستگاه تولید کنیم.\n\nلطفا از دستگاه دیگری ثبت نام کنید.", + "howItWorks": "چگونه کار می‌کند", + "encryption": "رمزگذاری", + "ackPasswordLostWarning": "من درک می‌کنم که اگر رمز عبور خود را گم کنم، ممکن است اطلاعات خود را از دست بدهم، زیرا اطلاعات من رمزگذاری سرتاسر شده است.", + "privacyPolicyTitle": "سیاست حفظ حریم خصوصی", + "termsOfServicesTitle": "شرایط و مقررات", + "signUpTerms": "من با شرایط خدمات و سیاست حفظ حریم خصوصی موافقم", + "logInLabel": "ورود", + "loginTerms": "با کلیک بر روی ورود به سیستم، من با شرایط خدمات و سیاست حفظ حریم خصوصی موافقم", + "changeEmail": "تغییر ایمیل", + "enterYourPassword": "رمز عبور خود را وارد کنید", + "welcomeBack": "خوش آمدید!", + "contactSupport": "ارتباط با پشتیبانی", + "incorrectPasswordTitle": "رمز عبور درست نیست", + "pleaseTryAgain": "لطفا دوباره تلاش کنید", + "recreatePasswordTitle": "بازتولید رمز عبور", + "useRecoveryKey": "از کلید بازیابی استفاده کنید", + "recreatePasswordBody": "دستگاه فعلی به اندازه کافی قدرتمند نیست تا رمز عبور شما را تایید کند، اما ما می‌توانیم به گونه‌ای بازسازی کنیم که با تمام دستگاه‌ها کار کند.\n\nلطفا با استفاده از کلید بازیابی خود وارد شوید و رمز عبور خود را دوباره ایجاد کنید (در صورت تمایل می‌توانید دوباره از همان رمز عبور استفاده کنید).", + "verifyPassword": "تایید رمز عبور", + "recoveryKey": "کلید بازیابی", + "recoveryKeyOnForgotPassword": "اگر رمز عبور خود را فراموش کردید، تنها راهی که می‌توانید اطلاعات خود را بازیابی کنید با این کلید است.", + "recoveryKeySaveDescription": "ما این کلید را ذخیره نمی‌کنیم، لطفا این کلید ۲۴ کلمه‌ای را در مکانی امن ذخیره کنید.", + "doThisLater": "بعداً انجام شود", + "saveKey": "ذخیره کلید", + "recoveryKeyCopiedToClipboard": "کلید بازیابی در کلیپ‌بورد کپی شد", + "recoverAccount": "بازیابی حساب کاربری", + "recover": "بازیابی", + "dropSupportEmail": "لطفا یک ایمیل از آدرس ایمیلی که ثبت نام کردید به {supportEmail} ارسال کنید", + "@dropSupportEmail": { + "placeholders": { + "supportEmail": { + "description": "The support email address", + "type": "String", + "example": "support@ente.io" + } + } + }, + "confirm": "تایید", + "invalidKey": "کلید نامعتبر", + "tryAgain": "دوباره امتحان کنید", + "viewRecoveryKey": "نمایش کلید بازیابی", + "confirmRecoveryKey": "تایید کلید بازیابی", + "confirmYourRecoveryKey": "کلید بازیابی خود را تایید کنید", + "addViewer": "افزودن بیننده", + "addCollaborator": "افزودن همکار", + "addANewEmail": "افزودن ایمیل جدید", + "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": "همکاران می‌توانند عکس‌ها و ویدیوها را به آلبوم اشتراک گذاری شده اضافه کنند.", + "enterEmail": "ایمیل را وارد کنید", + "you": "شما", + "collaborator": "همکار", + "addMore": "افزودن بیشتر", + "@addMore": { + "description": "Button text to add more collaborators/viewers" + }, + "viewer": "بیننده", + "manage": "مدیریت", + "addedAs": "اضافه شده به عنوان", + "yesConvertToViewer": "بله، تبدیل به بیننده شود", + "allowAddingPhotos": "اجازه اضافه کردن عکس", + "@allowAddingPhotos": { + "description": "Switch button to enable uploading photos to a public link" + }, + "allowAddPhotosDescription": "به افراد که این پیوند را دارند، اجازه دهید عکس‌ها را به آلبوم اشتراک گذاری شده اضافه کنند.", + "lockButtonLabel": "قفل", + "enterPassword": "رمز عبور را وارد کنید", + "removeLink": "حذف پیوند", + "manageLink": "مدیریت پیوند", + "albumUpdated": "آلبوم به‌روز شد", + "never": "هرگز", + "custom": "سفارشی", + "@custom": { + "description": "Label for setting custom value for link expiry" + }, + "manageParticipants": "مدیریت", + "collabLinkSectionDescription": "پیوندی ایجاد کنید تا به افراد اجازه دهید بدون نیاز به برنامه یا حساب کاربری Ente عکس‌ها را در آلبوم اشتراک گذاشته شده شما اضافه و مشاهده کنند. برای جمع‌آوری عکس‌های رویداد عالی است.", + "verifyEmailID": "تایید {email}", + "shareTextRecommendUsingEnte": "Ente را دانلود کنید تا بتوانید به راحتی عکس‌ها و ویدیوهای با کیفیت اصلی را به اشتراک بگذارید\n\nhttps://ente.io", + "details": "جزئیات", + "faq": "سوالات متداول", + "archive": "بایگانی", + "uncategorized": "دسته‌بندی نشده", + "videoSmallCase": "ویدیو", + "photoSmallCase": "عکس", + "status": "وضعیت", + "selectFoldersForBackup": "پوشه‌ها را برای پشتیبان گیری انتخاب کنید", + "selectedFoldersWillBeEncryptedAndBackedUp": "پوشه‌های انتخاب شده، رمزگذاری شده و از آنها نسخه پشتیبان تهیه می‌شود", + "unselectAll": "لغو انتخاب همه", + "selectAll": "انتخاب همه", + "skip": "رد کردن", + "updatingFolderSelection": "در حال به‌روزرسانی گزینش پوشه...", + "about": "درباره ما", + "weAreOpenSource": "ما متن‌باز هستیم!", + "privacy": "حریم خصوصی", + "terms": "شرایط و مقررات", + "checkForUpdates": "بررسی برای به‌روزرسانی", + "checkStatus": "بررسی وضعیت", + "checking": "در حال بررسی...", + "youAreOnTheLatestVersion": "شما در حال استفاده از آخرین نسخه هستید", + "account": "حساب کاربری", + "manageSubscription": "مدیریت اشتراک", + "logout": "خروج", + "areYouSureYouWantToLogout": "آیا برای خارج شدن مطمئن هستید؟", + "yesLogout": "بله، خارج می‌شوم", + "aNewVersionOfEnteIsAvailable": "نسخه جدید Ente در دسترس است.", + "update": "به‌روزرسانی", + "installManually": "نصب دستی", + "criticalUpdateAvailable": "به‌روزرسانی حیاتی در دسترس است", + "updateAvailable": "به‌رورزرسانی در دسترس است", + "ignoreUpdate": "نادیده گرفتن", + "downloading": "در حال دانلود...", + "cannotDeleteSharedFiles": "پرونده‌های به اشتراک گذاشته شده را نمی‌توان حذف کرد", + "theDownloadCouldNotBeCompleted": "دانلود کامل نشد", + "retry": "سعی مجدد", + "backedUpFolders": "پوشه‌های پشتیبان گیری شده", + "backup": "پشتیبان گیری", + "familyPlans": "برنامه‌های خانوادگی", + "notifications": "آگاه‌سازی‌ها", + "sharedPhotoNotifications": "عکس‌های جدید به اشتراک گذاشته شده", + "sharedPhotoNotificationsExplanation": "هنگامی که شخصی عکسی را به آلبوم مشترکی که شما بخشی از آن هستید اضافه می‌کند، آگاه‌سازی دریافت می‌کنید", + "advanced": "پیشرفته", + "general": "عمومی", + "security": "امنیت", + "viewActiveSessions": "مشاهده دستگاه‌های فعال", + "authToViewYourActiveSessions": "لطفاً برای مشاهده دستگاه‌های فعال خود احراز هویت کنید", + "no": "خیر", + "yes": "بله", + "social": "شبکه اجتماعی", + "rateUsOnStore": "به ما در {storeName} امتیاز دهید", + "blog": "وبلاگ", + "merchandise": "کالا", + "twitter": "توییتر", + "mastodon": "ماستودون", + "matrix": "ماتریس", + "discord": "دیسکورد", + "reddit": "ردیت", + "support": "پشتیبانی", + "theme": "تم", + "lightTheme": "روشن", + "darkTheme": "تیره", + "systemTheme": "سیستم", + "manageFamily": "مدیریت خانواده", + "send": "ارسال", + "youAreOnAFamilyPlan": "شما در یک برنامه خانوادگی هستید!", + "startBackup": "شروع پشتیبان گیری", + "grantFullAccessPrompt": "لطفا اجازه دسترسی به تمام عکس‌ها را در تنظیمات برنامه بدهید", + "existingUser": "کاربر موجود", + "privateBackups": "پشتیبان گیری خصوصی", + "forYourMemories": "برای خاطرات شما", + "endtoendEncryptedByDefault": "به صورت پیش‌فرض رمزگذاری سرتاسر", + "safelyStored": "به طور ایمن", + "atAFalloutShelter": "در یک پناهگاه ذخیره می‌شود", + "designedToOutlive": "طراحی شده تا بیشتر زنده بماند", + "available": "در دسترس", + "everywhere": "همه جا", + "androidIosWebDesktop": "اندروید، آی‌اواس، وب، رایانه رومیزی", + "newToEnte": "کاربر جدید Ente", + "pleaseLoginAgain": "لطفا دوباره وارد شوید", + "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": "Ente فقط در صورتی می‌تواند پرونده‌ها را رمزگذاری و نگه‌داری کند که به آن‌ها دسترسی داشته باشید", + "pleaseGrantPermissions": "لطفا دسترسی بدهید", + "grantPermission": "دسترسی دادن", + "privateSharing": "اشتراک گذاری خصوصی", + "shareOnlyWithThePeopleYouWant": "فقط با افرادی که می‌خواهید به اشتراک بگذارید", + "usePublicLinksForPeopleNotOnEnte": "استفاده از پیوندهای عمومی برای افرادی که در Ente نیستند", + "allowPeopleToAddPhotos": "به افراد اجازه دهید عکس اضافه کنند", + "loggingOut": "در حال خروج...", + "deleteAll": "حذف همه", + "renameAlbum": "تغییر نام آلبوم", + "convertToAlbum": "تبدیل به آلبوم", + "sortAlbumsBy": "مرتب‌سازی براساس", + "sortNewestFirst": "ایتدا جدیدترین", + "sortOldestFirst": "ایتدا قدیمی‌ترین", + "rename": "تغییر نام", + "verifying": "در حال تایید...", + "renameFile": "تغییر نام پرونده", + "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "به نظر می‌رسد مشکلی وجود دارد. لطفا بعد از مدتی دوباره تلاش کنید. اگر همچنان با خطا مواجه می‌شوید، لطفا با تیم پشتیبانی ما ارتباط برقرار کنید.", + "error": "خطا", + "tempErrorContactSupportIfPersists": "به نظر می‌رسد مشکلی وجود دارد. لطفا بعد از مدتی دوباره تلاش کنید. اگر همچنان با خطا مواجه می‌شوید، لطفا با تیم پشتیبانی ما ارتباط برقرار کنید.", + "preparingLogs": "در حال آماده‌سازی لاگ‌ها...", + "didYouKnow": "آیا می‌دانستید؟", + "loadMessage2": "ما تا کنون بیش از ۳۰ میلیون خاطره را حفظ کرده‌ایم", + "color": "رنگ", + "dayToday": "امروز", + "dayYesterday": "دیروز", + "storage": "حافظه ذخیره‌سازی", + "storageBreakupFamily": "خانوادگی", + "storageBreakupYou": "شما", + "@storageBreakupYou": { + "description": "Label to indicate how much storage you are using when you are part of a family plan" + }, + "storageUsageInfo": "{usedAmount} {usedStorageUnit} از {totalAmount} {totalStorageUnit} استفاده شده", + "@storageUsageInfo": { + "description": "Example: 1.2 GB of 2 GB used or 100 GB or 2TB used" + }, + "availableStorageSpace": "{freeAmount} {storageUnit} رایگان", + "appVersion": "نسخه: {versionValue}", + "verifyIDLabel": "تایید", + "fileInfoAddDescHint": "افزودن توضیحات...", + "editLocationTagTitle": "ویرایش مکان", + "familyPlanPortalTitle": "خانوادگی", + "androidBiometricHint": "تایید هویت", + "@androidBiometricHint": { + "description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters." + }, + "androidBiometricSuccess": "موفقیت", + "@androidBiometricSuccess": { + "description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters." + }, + "androidCancelButton": "لغو", + "@androidCancelButton": { + "description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters." + }, + "fileTypes": "انواع پرونده", + "hearUsWhereTitle": "از کجا در مورد Ente شنیدی؟ (اختیاری)", + "hearUsExplanation": "ما نصب برنامه را ردیابی نمی‌کنیم. اگر بگویید کجا ما را پیدا کردید، به ما کمک می‌کند!", + "developerSettings": "تنظیمات توسعه‌دهنده", + "search": "جستجو", + "whatsNew": "تغییرات جدید", + "reviewSuggestions": "مرور پیشنهادها" +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_fr.arb b/mobile/lib/l10n/intl_fr.arb index 5d9188b80c..8f4b1e375e 100644 --- a/mobile/lib/l10n/intl_fr.arb +++ b/mobile/lib/l10n/intl_fr.arb @@ -1,4 +1,5 @@ { + "@@locale ": "en", "enterYourEmailAddress": "Entrez votre adresse e-mail", "accountWelcomeBack": "Bienvenue !", "email": "E-mail", @@ -8,7 +9,7 @@ "enterValidEmail": "Veuillez entrer une adresse email valide.", "deleteAccount": "Supprimer le compte", "askDeleteReason": "Quelle est la principale raison pour laquelle vous supprimez votre compte ?", - "deleteAccountFeedbackPrompt": "Nous sommes désolés de vous voir partir. S'il vous plaît partagez vos commentaires pour nous aider à améliorer le service.", + "deleteAccountFeedbackPrompt": "Nous sommes désolés de vous voir partir. N'hésitez pas à partager vos commentaires pour nous aider à améliorer le service.", "feedback": "Commentaires", "kindlyHelpUsWithThisInformation": "Merci de nous aider avec cette information", "confirmDeletePrompt": "Oui, je veux supprimer définitivement ce compte et toutes ses données.", @@ -23,7 +24,7 @@ "sendEmail": "Envoyer un e-mail", "deleteRequestSLAText": "Votre demande sera traitée sous 72 heures.", "deleteEmailRequest": "Veuillez envoyer un e-mail à account-deletion@ente.io à partir de votre adresse e-mail enregistrée.", - "entePhotosPerm": "ente a besoin d'une autorisation pour préserver vos photos", + "entePhotosPerm": "Ente a besoin d'une autorisation pour préserver vos photos", "ok": "Ok", "createAccount": "Créer un compte", "createNewAccount": "Créer un nouveau compte", @@ -44,7 +45,7 @@ "incorrectRecoveryKeyBody": "La clé de secours que vous avez entrée est incorrecte", "forgotPassword": "Mot de passe oublié", "enterYourRecoveryKey": "Entrez votre clé de récupération", - "noRecoveryKey": "Aucune clé de récupération?", + "noRecoveryKey": "Aucune clé de récupération ?", "sorry": "Désolé", "noRecoveryKeyNoDecryption": "En raison de notre protocole de chiffrement de bout en bout, vos données ne peuvent pas être déchiffré sans votre mot de passe ou clé de récupération", "verifyEmail": "Vérifier l'email", @@ -71,8 +72,8 @@ "enterPasswordToEncrypt": "Entrez un mot de passe que nous pouvons utiliser pour chiffrer vos données", "enterNewPasswordToEncrypt": "Entrez un nouveau mot de passe que nous pouvons utiliser pour chiffrer vos données", "weakStrength": "Securité Faible", - "strongStrength": "Securité forte", - "moderateStrength": "Sécurité moyenne", + "strongStrength": "Forte", + "moderateStrength": "Moyen", "passwordStrength": "Sécurité du mot de passe : {passwordStrengthValue}", "@passwordStrength": { "description": "Text to indicate the password strength", @@ -136,7 +137,7 @@ "scanThisBarcodeWithnyourAuthenticatorApp": "Scannez ce code-barres avec\nvotre application d'authentification", "enterThe6digitCodeFromnyourAuthenticatorApp": "Entrez le code à 6 chiffres de\nvotre application d'authentification", "confirm": "Confirmer", - "setupComplete": "Configuration fini", + "setupComplete": "Configuration terminée", "saveYourRecoveryKeyIfYouHaventAlready": "Enregistrez votre clé de récupération si vous ne l'avez pas déjà fait", "thisCanBeUsedToRecoverYourAccountIfYou": "Cela peut être utilisé pour récupérer votre compte si vous perdez votre deuxième facteur", "twofactorAuthenticationPageTitle": "Authentification à deux facteurs", @@ -144,7 +145,7 @@ "verifyingRecoveryKey": "Vérification de la clé de récupération...", "recoveryKeyVerified": "Clé de récupération vérifiée", "recoveryKeySuccessBody": "Génial ! Votre clé de récupération est valide. Merci de votre vérification.\n\nN'oubliez pas de garder votre clé de récupération sauvegardée.", - "invalidRecoveryKey": "La clé de récupération que vous avez saisie n'est pas valide. Veuillez vous assurer qu'elle ", + "invalidRecoveryKey": "La clé de récupération que vous avez saisie n'est pas valide. Veuillez vérifier qu'elle contient 24 caractères et qu'ils sont correctement orthographiés.\n\nSi vous avez saisi un ancien code de récupération, veuillez vérifier qu'il contient 64 caractères et qu'ils sont correctement orthographiés.", "invalidKey": "Clé invalide", "tryAgain": "Réessayer", "viewRecoveryKey": "Voir la clé de récupération", @@ -163,12 +164,12 @@ }, "you": "Vous", "collaborator": "Collaborateur", - "addMore": "Ajouter Plus", + "addMore": "Ajouter", "@addMore": { "description": "Button text to add more collaborators/viewers" }, "viewer": "Observateur", - "remove": "Enlever", + "remove": "Supprimer", "removeParticipant": "Supprimer le participant", "@removeParticipant": { "description": "menuSectionTitle for removing a participant" @@ -177,7 +178,7 @@ "addedAs": "Ajouté comme", "changePermissions": "Modifier les permissions ?", "yesConvertToViewer": "Oui, convertir en observateur", - "cannotAddMorePhotosAfterBecomingViewer": "{user} ne pourra pas ajouter plus de photos à cet album\n\nIl pourrait toujours supprimer les photos existantes ajoutées par eux", + "cannotAddMorePhotosAfterBecomingViewer": "{user} ne pourra pas ajouter plus de photos à cet album\n\nIl pourra toujours supprimer les photos existantes ajoutées par eux", "allowAddingPhotos": "Autoriser l'ajout de photos", "@allowAddingPhotos": { "description": "Switch button to enable uploading photos to a public link" @@ -185,7 +186,7 @@ "allowAddPhotosDescription": "Autoriser les personnes avec le lien à ajouter des photos à l'album partagé.", "passwordLock": "Mot de passe verrou", "disableDownloadWarningTitle": "Veuillez remarquer", - "disableDownloadWarningBody": "Les téléspectateurs peuvent toujours prendre des captures d'écran ou enregistrer une copie de vos photos en utilisant des outils externes", + "disableDownloadWarningBody": "Les observateurs peuvent toujours prendre des captures d'écran ou enregistrer une copie de vos photos en utilisant des outils externes", "allowDownloads": "Autoriser les téléchargements", "linkDeviceLimit": "Limite d'appareil", "noDeviceLimit": "Aucune", @@ -225,17 +226,17 @@ }, "description": "Number of participants in an album, including the album owner." }, - "collabLinkSectionDescription": "Créez un lien pour permettre aux gens d'ajouter et de voir des photos dans votre album partagé sans avoir besoin d'une application ente ou d'un compte. Idéal pour collecter des photos d'événement.", + "collabLinkSectionDescription": "Créez un lien pour permettre aux gens d'ajouter et de voir des photos dans votre album partagé sans avoir besoin d'une application ente ou d'un compte. Idéal pour récupérer des photos d'événement.", "collectPhotos": "Récupérer les photos", "collaborativeLink": "Lien collaboratif", - "shareWithNonenteUsers": "Partager avec des utilisateurs non-ente", + "shareWithNonenteUsers": "Partager avec des utilisateurs non-Ente", "createPublicLink": "Créer un lien public", "sendLink": "Envoyer le lien", "copyLink": "Copier le lien", "linkHasExpired": "Le lien a expiré", "publicLinkEnabled": "Lien public activé", "shareALink": "Partager le lien", - "sharedAlbumSectionDescription": "Créez des albums partagés et collaboratifs avec d'autres utilisateurs de ente, y compris des utilisateurs sur des plans gratuits.", + "sharedAlbumSectionDescription": "Créez des albums partagés et collaboratifs avec d'autres utilisateurs de Ente, y compris des utilisateurs ayant des plans gratuits.", "shareWithPeopleSectionTitle": "{numberOfPeople, plural, =0 {Partagez avec des personnes spécifiques} =1 {Partagé avec 1 personne} other {Partagé avec {numberOfPeople} des gens}}", "@shareWithPeopleSectionTitle": { "placeholders": { @@ -259,12 +260,12 @@ }, "verificationId": "ID de vérification", "verifyEmailID": "Vérifier {email}", - "emailNoEnteAccount": "{email} n'a pas de compte ente.\n\nEnvoyez une invitation pour partager des photos.", + "emailNoEnteAccount": "{email} n'a pas de compte Ente.\n\nEnvoyez une invitation pour partager des photos.", "shareMyVerificationID": "Voici mon ID de vérification : {verificationID} pour ente.io.", "shareTextConfirmOthersVerificationID": "Hé, pouvez-vous confirmer qu'il s'agit de votre ID de vérification ente.io : {verificationID}", "somethingWentWrong": "Un problème est survenu", "sendInvite": "Envoyer Invitations", - "shareTextRecommendUsingEnte": "Téléchargez ente pour que nous puissions facilement partager des photos et des vidéos de qualité originale\n\nhttps://ente.io", + "shareTextRecommendUsingEnte": "Téléchargez Ente pour que nous puissions facilement partager des photos et des vidéos de qualité originale\n\nhttps://ente.io", "done": "Terminé", "applyCodeTitle": "Utiliser le code", "enterCodeDescription": "Entrez le code fourni par votre ami pour réclamer de l'espace de stockage gratuit pour vous deux", @@ -272,6 +273,10 @@ "failedToApplyCode": "Impossible d'appliquer le code", "enterReferralCode": "Entrez le code de parrainage", "codeAppliedPageTitle": "Code appliqué", + "changeYourReferralCode": "Modifier votre code de parrainage", + "change": "Modifier", + "unavailableReferralCode": "Désolé, ce code n'est pas disponible.", + "codeChangeLimitReached": "Désolé, vous avez atteint la limite de changements de code.", "storageInGB": "{storageAmountInGB} Go", "claimed": "Réclamée", "@claimed": { @@ -281,7 +286,7 @@ "claimMore": "Réclamez plus !", "theyAlsoGetXGb": "Ils obtiennent aussi {storageAmountInGB} Go", "freeStorageOnReferralSuccess": "{storageAmountInGB} Go chaque fois que quelqu'un s'inscrit à une offre payante et applique votre code", - "shareTextReferralCode": "code de parrainage ente : {referralCode} \n\nAppliquez le dans Paramètres → Général → Références pour obtenir {referralStorageInGB} Go gratuitement après votre inscription à un plan payant\n\nhttps://ente.io", + "shareTextReferralCode": "Code de parrainage Ente : {referralCode} \n\nValidez le dans Paramètres → Général → Références pour obtenir {referralStorageInGB} Go gratuitement après votre inscription à un plan payant\n\nhttps://ente.io", "claimFreeStorage": "Réclamer le stockage gratuit", "inviteYourFriends": "Invite tes ami(e)s", "failedToFetchReferralDetails": "Impossible de récupérer les détails du parrainage. Veuillez réessayer plus tard.", @@ -304,6 +309,7 @@ } }, "faq": "FAQ", + "help": "Aide", "oopsSomethingWentWrong": "Oups, une erreur est arrivée", "peopleUsingYourCode": "Personnes utilisant votre code", "eligible": "éligible", @@ -333,7 +339,7 @@ "removeParticipantBody": "{userEmail} sera retiré de cet album partagé\n\nToutes les photos ajoutées par eux seront également retirées de l'album", "keepPhotos": "Conserver les photos", "deletePhotos": "Supprimer des photos", - "inviteToEnte": "Inviter à ente", + "inviteToEnte": "Inviter à rejoindre Ente", "removePublicLink": "Supprimer le lien public", "disableLinkMessage": "Cela supprimera le lien public pour accéder à \"{albumName}\".", "sharing": "Partage...", @@ -350,9 +356,9 @@ "photoSmallCase": "photo", "singleFileDeleteHighlight": "Elle sera supprimée de tous les albums.", "singleFileInBothLocalAndRemote": "Cette {fileType} est à la fois sur ente et sur votre appareil.", - "singleFileInRemoteOnly": "Ce {fileType} sera supprimé de ente.", + "singleFileInRemoteOnly": "Cette {fileType} sera supprimée de l'Ente.", "singleFileDeleteFromDevice": "Elle {fileType} sera supprimée de votre appareil.", - "deleteFromEnte": "Supprimer de ente", + "deleteFromEnte": "Supprimé de Ente", "yesDelete": "Oui, supprimer", "movedToTrash": "Déplacé dans la corbeille", "deleteFromDevice": "Supprimer de l'appareil", @@ -406,6 +412,14 @@ }, "photoGridSize": "Taille de la grille photo", "manageDeviceStorage": "Gérer le stockage de l'appareil", + "machineLearning": "Apprentissage automatique", + "magicSearch": "Recherche magique", + "loadingModel": "Téléchargement des modèles...", + "waitingForWifi": "En attente de connexion Wi-Fi...", + "status": "État", + "indexedItems": "Éléments indexés", + "pendingItems": "Éléments en attente", + "clearIndexes": "Effacer les index", "selectFoldersForBackup": "Sélectionner les dossiers à sauvegarder", "selectedFoldersWillBeEncryptedAndBackedUp": "Les dossiers sélectionnés seront cryptés et sauvegardés", "unselectAll": "Désélectionner tout", @@ -441,6 +455,7 @@ "privacy": "Confidentialité", "terms": "Conditions", "checkForUpdates": "Vérifier les mises à jour", + "checkStatus": "Vérifier le statut", "checking": "Vérification...", "youAreOnTheLatestVersion": "Vous êtes sur la dernière version", "account": "Compte", @@ -455,7 +470,7 @@ "authToInitiateAccountDeletion": "Veuillez vous authentifier pour débuter la suppression du compte", "areYouSureYouWantToLogout": "Voulez-vous vraiment vous déconnecter ?", "yesLogout": "Oui, se déconnecter", - "aNewVersionOfEnteIsAvailable": "Une nouvelle version de ente est disponible.", + "aNewVersionOfEnteIsAvailable": "Une nouvelle version de Ente est disponible.", "update": "Mise à jour", "installManually": "Installation manuelle", "criticalUpdateAvailable": "Mise à jour critique disponible", @@ -468,9 +483,12 @@ "backedUpFolders": "Dossiers sauvegardés", "backup": "Sauvegarde", "freeUpDeviceSpace": "Libérer de l'espace sur l'appareil", + "freeUpDeviceSpaceDesc": "Économisez de l'espace sur votre appareil en effaçant les fichiers qui ont déjà été sauvegardés.", "allClear": "✨ Tout est effacé", "noDeviceThatCanBeDeleted": "Vous n'avez pas de fichiers sur cet appareil qui peuvent être supprimés", "removeDuplicates": "Supprimer les doublons", + "removeDuplicatesDesc": "Examiner et supprimer les fichiers qui sont des doublons exacts.", + "viewLargeFiles": "Fichiers volumineux", "noDuplicates": "✨ Aucun doublon", "youveNoDuplicateFilesThatCanBeCleared": "Vous n'avez aucun fichier dédupliqué pouvant être nettoyé", "success": "Succès", @@ -515,7 +533,7 @@ "authToViewYourRecoveryKey": "Veuillez vous authentifier pour afficher votre clé de récupération", "twofactor": "Double authentification", "authToConfigureTwofactorAuthentication": "Veuillez vous authentifier pour configurer l'authentification à deux facteurs", - "lockscreen": "Ecran de vérouillage", + "lockscreen": "Écran de verrouillage", "authToChangeLockscreenSetting": "Veuillez vous authentifier pour modifier les paramètres de l'écran de verrouillage", "viewActiveSessions": "Afficher les sessions actives", "authToViewYourActiveSessions": "Veuillez vous authentifier pour voir vos sessions actives", @@ -543,11 +561,11 @@ "systemTheme": "Système", "freeTrial": "Essai gratuit", "selectYourPlan": "Sélectionner votre offre", - "enteSubscriptionPitch": "ente conserve vos souvenirs, donc ils sont toujours disponibles pour vous, même si vous perdez votre appareil.", + "enteSubscriptionPitch": "Ente conserve vos souvenirs, ils sont donc toujours disponibles pour vous, même si vous perdez votre appareil.", "enteSubscriptionShareWithFamily": "Vous pouvez également ajouter votre famille à votre forfait.", "currentUsageIs": "L'utilisation actuelle est ", "@currentUsageIs": { - "description": "This text is followed by storage usaged", + "description": "This text is followed by storage usage", "examples": { "0": "Current usage is 1.2 GB" }, @@ -557,6 +575,7 @@ "renewsOn": "Renouvellement le {endDate}", "freeTrialValidTill": "Essai gratuit valide jusqu’au {endDate}", "validTill": "Valable jusqu'au {endDate}", + "addOnValidTill": "Votre extension de {storageAmount} est valable jusqu'au {endDate}", "playStoreFreeTrialValidTill": "Essai gratuit valable jusqu'à {endDate}.\nVous pouvez choisir un plan payant par la suite.", "subWillBeCancelledOn": "Votre abonnement sera annulé le {endDate}", "subscription": "Abonnement", @@ -608,7 +627,7 @@ "appleId": "Apple ID", "playstoreSubscription": "Abonnement au PlayStore", "appstoreSubscription": "Abonnement à l'AppStore", - "subAlreadyLinkedErrMessage": "Votre {id} est déjà lié à un autre compte ente.\nSi vous souhaitez utiliser votre {id} avec ce compte, veuillez contacter notre support", + "subAlreadyLinkedErrMessage": "Votre {id} est déjà lié à un autre compte Ente.\nSi vous souhaitez utiliser votre {id} avec ce compte, veuillez contacter notre support", "visitWebToManage": "Veuillez visiter web.ente.io pour gérer votre abonnement", "couldNotUpdateSubscription": "Impossible de mettre à jour l’abonnement", "pleaseContactSupportAndWeWillBeHappyToHelp": "Veuillez contacter support@ente.io et nous serons heureux de vous aider!", @@ -629,7 +648,7 @@ "thankYou": "Merci", "failedToVerifyPaymentStatus": "Échec de la vérification du statut du paiement", "pleaseWaitForSometimeBeforeRetrying": "Veuillez attendre quelque temps avant de réessayer", - "paymentFailedWithReason": "Malheureusement, votre paiement a échoué pour {reason}", + "paymentFailedMessage": "Malheureusement votre paiement a échoué. Veuillez contacter le support et nous vous aiderons !", "youAreOnAFamilyPlan": "Vous êtes sur un plan familial !", "contactFamilyAdmin": "Veuillez contacter {familyAdminEmail} pour gérer votre abonnement", "leaveFamily": "Quitter le plan familial", @@ -653,9 +672,9 @@ "everywhere": "partout", "androidIosWebDesktop": "Android, iOS, Web, Ordinateur", "mobileWebDesktop": "Mobile, Web, Ordinateur", - "newToEnte": "Nouveau sur ente", + "newToEnte": "Nouveau à Ente", "pleaseLoginAgain": "Veuillez vous reconnecter", - "devAccountChanged": "Le compte développeur que nous utilisons pour publier ente sur l'App Store a changé. Pour cette raison, vous devrez vous connecter à nouveau.\n\nNous nous excusons pour la gêne occasionnée, mais cela était inévitable.", + "autoLogoutMessage": "En raison d'un problème technique, vous avez été déconnecté. Veuillez nous excuser pour le désagrément.", "yourSubscriptionHasExpired": "Votre abonnement a expiré", "storageLimitExceeded": "Limite de stockage atteinte", "upgrade": "Améliorer", @@ -666,12 +685,12 @@ }, "backupFailed": "Échec de la sauvegarde", "couldNotBackUpTryLater": "Nous n'avons pas pu sauvegarder vos données.\nNous allons réessayer plus tard.", - "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": "ente peut chiffrer et conserver des fichiers que si vous leur accordez l'accès", + "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": "Ente peut chiffrer et conserver des fichiers que si vous leur accordez l'accès", "pleaseGrantPermissions": "Veuillez accorder la permission", "grantPermission": "Accorder la permission", "privateSharing": "Partage privé", "shareOnlyWithThePeopleYouWant": "Partager uniquement avec les personnes que vous voulez", - "usePublicLinksForPeopleNotOnEnte": "Utiliser des liens publics pour les personnes qui ne sont pas sur ente", + "usePublicLinksForPeopleNotOnEnte": "Utiliser des liens publics pour les personnes qui ne sont pas sur Ente", "allowPeopleToAddPhotos": "Autoriser les personnes à ajouter des photos", "shareAnAlbumNow": "Partagez un album maintenant", "collectEventPhotos": "Collecter des photos de l'événement", @@ -683,7 +702,7 @@ }, "onDevice": "Sur l'appareil", "@onEnte": { - "description": "The text displayed above albums backed up to ente", + "description": "The text displayed above albums backed up to Ente", "type": "text" }, "onEnte": "Sur ente", @@ -694,6 +713,21 @@ "deleteEmptyAlbumsWithQuestionMark": "Supprimer les albums vides ?", "deleteAlbumsDialogBody": "Ceci supprimera tous les albums vides. Ceci est utile lorsque vous voulez réduire l'encombrement dans votre liste d'albums.", "deleteProgress": "Suppression de {currentlyDeleting} / {totalCount}", + "genericProgress": "Traitement en cours {currentlyProcessing} / {totalCount}", + "@genericProgress": { + "description": "Generic progress text to display when processing multiple items", + "type": "text", + "placeholders": { + "currentlyProcessing": { + "example": "1", + "type": "int" + }, + "totalCount": { + "example": "10", + "type": "int" + } + } + }, "permanentlyDelete": "Supprimer définitivement", "canOnlyCreateLinkForFilesOwnedByYou": "Ne peut créer de lien que pour les fichiers que vous possédez", "publicLinkCreated": "Lien public créé", @@ -714,7 +748,7 @@ "saveCollage": "Enregistrer le collage", "collageSaved": "Collage sauvegardé dans la galerie", "collageLayout": "Disposition", - "addToEnte": "Ajouter à ente", + "addToEnte": "Ajouter à Ente", "addToAlbum": "Ajouter à l'album", "delete": "Supprimer", "hide": "Masquer", @@ -779,10 +813,10 @@ "photosAddedByYouWillBeRemovedFromTheAlbum": "Les photos ajoutées par vous seront retirées de l'album", "youveNoFilesInThisAlbumThatCanBeDeleted": "Vous n'avez pas de fichiers dans cet album qui peuvent être supprimés", "youDontHaveAnyArchivedItems": "Vous n'avez aucun élément archivé.", - "ignoredFolderUploadReason": "Certains fichiers de cet album sont ignorés parce qu'ils avaient été précédemment supprimés de ente.", + "ignoredFolderUploadReason": "Certains fichiers de cet album sont ignorés parce qu'ils avaient été précédemment supprimés de Ente.", "resetIgnoredFiles": "Réinitialiser les fichiers ignorés", - "deviceFilesAutoUploading": "Les fichiers ajoutés à cet album seront automatiquement téléchargés sur ente.", - "turnOnBackupForAutoUpload": "Activez la sauvegarde pour télécharger automatiquement les fichiers ajoutés à ce dossier de l'appareil sur ente.", + "deviceFilesAutoUploading": "Les fichiers ajoutés à cet album seront automatiquement téléchargés sur Ente.", + "turnOnBackupForAutoUpload": "Activez la sauvegarde pour charger automatiquement sur Ente les fichiers ajoutés à ce dossier de l'appareil.", "noHiddenPhotosOrVideos": "Aucune photo ou vidéo cachée", "toHideAPhotoOrVideo": "Cacher une photo ou une vidéo", "openTheItem": "• Ouvrir l'élément", @@ -808,6 +842,7 @@ "close": "Fermer", "setAs": "Définir comme", "fileSavedToGallery": "Fichier enregistré dans la galerie", + "filesSavedToGallery": "Fichiers enregistrés dans la galerie", "fileFailedToSaveToGallery": "Échec de l'enregistrement dans la galerie", "download": "Télécharger", "pressAndHoldToPlayVideo": "Appuyez et maintenez enfoncé pour lire la vidéo", @@ -820,7 +855,6 @@ "clubByFileName": "Grouper par nom de fichier", "count": "Total", "totalSize": "Taille totale", - "time": "Date et heure", "longpressOnAnItemToViewInFullscreen": "Appuyez longuement sur un élément pour le voir en plein écran", "decryptingVideo": "Déchiffrement de la vidéo...", "authToViewYourMemories": "Veuillez vous authentifier pour voir vos souvenirs", @@ -897,10 +931,10 @@ "description": "Text to tell user how many memories have been preserved", "placeholders": { "completed": { - "type": "int" + "type": "String" }, "total": { - "type": "int" + "type": "String" } } }, @@ -911,21 +945,23 @@ "renameFile": "Renommer le fichier", "enterFileName": "Entrez le nom du fichier", "filesDeleted": "Fichiers supprimés", - "selectedFilesAreNotOnEnte": "Les fichiers sélectionnés ne sont pas sur ente", + "selectedFilesAreNotOnEnte": "Les fichiers sélectionnés ne sont pas sur Ente", "thisActionCannotBeUndone": "Cette action ne peut pas être annulée", "emptyTrash": "Vider la corbeille ?", "permDeleteWarning": "Tous les éléments de la corbeille seront définitivement supprimés\n\nCette action ne peut pas être annulée", - "empty": "Vide", + "empty": "Vider", "couldNotFreeUpSpace": "Impossible de libérer de l'espace", "permanentlyDeleteFromDevice": "Supprimer définitivement de l'appareil ?", "someOfTheFilesYouAreTryingToDeleteAre": "Certains des fichiers que vous essayez de supprimer ne sont disponibles que sur votre appareil et ne peuvent pas être récupérés s'ils sont supprimés", "theyWillBeDeletedFromAllAlbums": "Ils seront supprimés de tous les albums.", - "someItemsAreInBothEnteAndYourDevice": "Certains éléments sont à la fois dans ente et votre appareil.", + "someItemsAreInBothEnteAndYourDevice": "Certains éléments sont à la fois sur Ente et votre appareil.", "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": "Les éléments sélectionnés seront supprimés de tous les albums et déplacés dans la corbeille.", "theseItemsWillBeDeletedFromYourDevice": "Ces éléments seront supprimés de votre appareil.", "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Il semble qu'une erreur s'est produite. Veuillez réessayer après un certain temps. Si l'erreur persiste, veuillez contacter notre équipe d'assistance.", "error": "Erreur", "tempErrorContactSupportIfPersists": "Il semble qu'une erreur s'est produite. Veuillez réessayer après un certain temps. Si l'erreur persiste, veuillez contacter notre équipe d'assistance.", + "networkHostLookUpErr": "Impossible de se connecter à Ente, veuillez vérifier vos paramètres réseau et contacter le support si l'erreur persiste.", + "networkConnectionRefusedErr": "Impossible de se connecter à Ente, veuillez réessayer après un certain temps. Si l'erreur persiste, veuillez contacter le support.", "cachedData": "Données mises en cache", "clearCaches": "Nettoyer le cache", "remoteImages": "Images distantes", @@ -958,7 +994,7 @@ "fileTypesAndNames": "Types et noms de fichiers", "location": "Emplacement", "moments": "Souvenirs", - "searchFaceEmptySection": "Trouver toutes les photos d'une personne", + "searchFaceEmptySection": "Les personnes seront affichées ici une fois l'indexation terminée", "searchDatesEmptySection": "Recherche par date, mois ou année", "searchLocationEmptySection": "Grouper les photos qui sont prises dans un certain angle d'une photo", "searchPeopleEmptySection": "Invitez des gens, et vous verrez ici toutes les photos qu'ils partagent", @@ -1013,7 +1049,7 @@ "@storageUsageInfo": { "description": "Example: 1.2 GB of 2 GB used or 100 GB or 2TB used" }, - "availableStorageSpace": "{freeAmount} {storageUnit} libre", + "availableStorageSpace": "{freeAmount} {storageUnit} gratuit", "appVersion": "Version : {versionValue}", "verifyIDLabel": "Vérifier", "fileInfoAddDescHint": "Ajouter une description...", @@ -1102,7 +1138,7 @@ "noAlbumsSharedByYouYet": "Aucun album que vous avez partagé", "sharedWithYou": "Partagé avec vous", "sharedByYou": "Partagé par vous", - "inviteYourFriendsToEnte": "Invitez vos amis sur ente", + "inviteYourFriendsToEnte": "Invitez vos amis sur Ente", "failedToDownloadVideo": "Échec du téléchargement de la vidéo", "hiding": "Masquage en cours...", "unhiding": "Démasquage en cours...", @@ -1112,7 +1148,7 @@ "addToHiddenAlbum": "Ajouter à un album masqué", "moveToHiddenAlbum": "Déplacer vers un album masqué", "fileTypes": "Types de fichiers", - "deleteConfirmDialogBody": "Ce compte est lié à d'autres applications ente, si vous en utilisez une.\\n\\nVos données téléchargées, dans toutes les applications ente, seront planifiées pour suppression, et votre compte sera définitivement supprimé.", + "deleteConfirmDialogBody": "Ce compte est lié à d'autres applications Ente, si vous en utilisez une. Vos données téléchargées, dans toutes les applications ente, seront planifiées pour suppression, et votre compte sera définitivement supprimé.", "hearUsWhereTitle": "Comment avez-vous entendu parler de Ente? (facultatif)", "hearUsExplanation": "Nous ne suivons pas les installations d'applications. Il serait utile que vous nous disiez comment vous nous avez trouvés !", "viewAddOnButton": "Afficher les modules complémentaires", @@ -1142,68 +1178,112 @@ } }, "faces": "Visages", + "people": "Personnes", "contents": "Contenus", "addNew": "Ajouter un nouveau", "@addNew": { "description": "Text to add a new item (location tag, album, caption etc)" }, "contacts": "Contacts", - "editLocation": "Edit location", - "selectALocation": "Select a location", - "selectALocationFirst": "Select a location first", - "changeLocationOfSelectedItems": "Change location of selected items?", - "editsToLocationWillOnlyBeSeenWithinEnte": "Edits to location will only be seen within Ente", - "joinDiscord": "Join Discord", - "locations": "Locations", + "noInternetConnection": "Aucune connexion internet", + "pleaseCheckYourInternetConnectionAndTryAgain": "S'il vous plaît, vérifiez votre connexion à internet et réessayez.", + "signOutFromOtherDevices": "Se déconnecter d'autres appareils", + "signOutOtherBody": "Si vous pensez que quelqu'un peut connaître votre mot de passe, vous pouvez forcer tous les autres appareils utilisant votre compte à se déconnecter.", + "signOutOtherDevices": "Déconnecter les autres appareils", + "doNotSignOut": "Ne pas se déconnecter", + "editLocation": "Modifier l’emplacement", + "selectALocation": "Sélectionnez un emplacement", + "selectALocationFirst": "Sélectionnez d'abord un emplacement", + "changeLocationOfSelectedItems": "Changer l'emplacement des éléments sélectionnés ?", + "editsToLocationWillOnlyBeSeenWithinEnte": "Les modifications de l'emplacement ne seront visibles que dans Ente", + "cleanUncategorized": "Effacer les éléments non classés", + "cleanUncategorizedDescription": "Supprimer tous les fichiers non-catégorisés étant présents dans d'autres albums", + "waitingForVerification": "En attente de vérification...", + "passkey": "Code d'accès", + "passkeyAuthTitle": "Vérification du code d'accès", + "passKeyPendingVerification": "La vérification est toujours en attente", + "loginSessionExpired": "Session expirée", + "loginSessionExpiredDetails": "Votre session a expiré. Veuillez vous reconnecter.", + "verifyPasskey": "Vérifier le code d'accès", + "playOnTv": "Lire l'album sur la TV", + "pair": "Associer", + "deviceNotFound": "Appareil non trouvé", + "castInstruction": "Visitez cast.ente.io sur l'appareil que vous voulez associer.\n\nEntrez le code ci-dessous pour lire l'album sur votre TV.", + "deviceCodeHint": "Saisissez le code", + "joinDiscord": "Rejoindre Discord", + "locations": "Emplacements", "descriptions": "Descriptions", - "addViewers": "{count, plural, zero {Add viewer} one {Add viewer} other {Add viewers}}", - "addCollaborators": "{count, plural, zero {Add collaborator} one {Add collaborator} other {Add collaborators}}", - "longPressAnEmailToVerifyEndToEndEncryption": "Long press an email to verify end to end encryption.", - "createCollaborativeLink": "Create collaborative link", - "search": "Search", - "enterPersonName": "Enter person name", - "removePersonLabel": "Remove person label", - "faceRecognition": "Face recognition", - "faceRecognitionIndexingDescription": "Please note that this will result in a higher bandwidth and battery usage until all items are indexed.", - "foundFaces": "Found faces", - "clusteringProgress": "Clustering progress", - "indexingIsPaused": "Indexing is paused, will automatically resume when device is ready", - "reenterPassword": "Re-enter password", - "mlFunctions": "ML functions", - "reenterPin": "Re-enter PIN", - "deviceLock": "Device lock", - "pinLock": "PIN lock", - "next": "Next", - "setNewPassword": "Set new password", - "enterPin": "Enter PIN", - "setNewPin": "Set new PIN", - "appLock": "App lock", - "noSystemLockFound": "No system lock found", - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "To enable app lock, please setup device passcode or screen lock in your system settings.", - "tapToUnlock": "Tap to unlock", - "tooManyIncorrectAttempts": "Too many incorrect attempts", - "appLockDescription": "Choose between your device\\'s default lock screen and a custom lock screen with a PIN or password.", - "swipeLockEnablePreSteps": "To enable swipe lock, please setup device passcode or screen lock in your system settings.", - "autoLock": "Auto lock", - "immediately": "Immediately", - "autoLockFeatureDescription": "Time after which the app locks after being put in the background", - "hideContent": "Hide content", - "hideContentDescriptionAndroid": "Hides app content in the app switcher and disables screenshots", - "hideContentDescriptionIos": "Hides app content in the app switcher", - "passwordStrengthInfo": "Password strength is calculated considering the length of the password, used characters, and whether or not the password appears in the top 10,000 most used passwords", - "noQuickLinksSelected": "No quick links selected", - "pleaseSelectQuickLinksToRemove": "Please select quick links to remove", - "removePublicLinks": "Remove public links", - "thisWillRemovePublicLinksOfAllSelectedQuickLinks": "This will remove public links of all selected quick links.", - "guestView": "Guest view", - "guestViewEnablePreSteps": "To enable guest view, please setup device passcode or screen lock in your system settings.", - "cl_guest_view_title": "Vue Invité", - "cl_guest_view_description": "Vous montrez des photos à un ami ? Pas de souci, il ne pourra pas trop faire défiler. La vue invité verrouille les photos que vous sélectionnez.", - "cl_guest_view_call_to_action": "Sélectionnez des photos et essayez la \"Vue Invité\".", - "cl_panorama_viewer_title": "Visionneuse Panorama", - "cl_panorama_viewer_description": "Nous avons ajouté le support pour visionner des photos panoramiques avec des vues à 360 degrés. L'expérience est immersive avec une navigation basée sur le mouvement !", - "cl_video_player_title": "Lecteur Vidéo", - "cl_video_player_description": "Découvrez notre nouveau lecteur vidéo avec de meilleurs contrôles de lecture et le support des vidéos HDR.", - "appLockDescriptions": "Choose between your device's default lock screen and a custom lock screen with a PIN or password.", - "authToViewPasskey": "Please authenticate to view your passkey" + "addAName": "Ajouter un nom", + "findPeopleByName": "Trouver des personnes rapidement par leur nom", + "addViewers": "{count, plural, zero {Ajouter un lecteur} one {Ajouter un lecteur} other {Ajouter des lecteurs}}", + "addCollaborators": "{count, plural, zero {Ajouter un coauteur} one {Ajouter un coauteur} other {Ajouter des coauteurs}}", + "longPressAnEmailToVerifyEndToEndEncryption": "Appuyez longuement sur un e-mail pour vérifier le chiffrement de bout en bout.", + "developerSettingsWarning": "Êtes-vous sûr de vouloir modifier les paramètres du développeur ?", + "developerSettings": "Paramètres du développeur", + "serverEndpoint": "Point de terminaison serveur", + "invalidEndpoint": "Point de terminaison non valide", + "invalidEndpointMessage": "Désolé, le point de terminaison que vous avez entré n'est pas valide. Veuillez en entrer un valide puis réessayez.", + "endpointUpdatedMessage": "Point de terminaison mis à jour avec succès", + "customEndpoint": "Connecté à {endpoint}", + "createCollaborativeLink": "Créer un lien collaboratif", + "search": "Rechercher", + "enterPersonName": "Entrez le nom d'une personne", + "removePersonLabel": "Supprimer le libellé d'une personne", + "autoPairDesc": "L'appairage automatique ne fonctionne qu'avec les appareils qui prennent en charge Chromecast.", + "manualPairDesc": "L'appairage avec le code PIN fonctionne avec n'importe quel écran sur lequel vous souhaitez voir votre album.", + "connectToDevice": "Connexion à l'appareil", + "autoCastDialogBody": "Vous verrez ici les appareils Cast disponibles.", + "autoCastiOSPermission": "Assurez-vous que les autorisations de réseau local sont activées pour l'application Ente Photos, dans les paramètres.", + "noDeviceFound": "Aucun appareil trouvé", + "stopCastingTitle": "Arrêter la diffusion", + "stopCastingBody": "Voulez-vous arrêter la diffusion ?", + "castIPMismatchTitle": "Échec de la diffusion de l'album", + "castIPMismatchBody": "Veuillez vous assurer que vous êtes sur le même réseau que la TV.", + "pairingComplete": "Appairage terminé", + "savingEdits": "Enregistrement des modifications...", + "autoPair": "Appairage automatique", + "pairWithPin": "Appairer avec le code PIN", + "faceRecognition": "Reconnaissance faciale", + "foundFaces": "Visages trouvés", + "clusteringProgress": "Progression du regroupement", + "indexingIsPaused": "L'indexation est en pause. Elle reprendra automatiquement lorsque l'appareil sera prêt.", + "rotate": "Pivoter", + "left": "Gauche", + "right": "Droite", + "whatsNew": "Nouveautés", + "reviewSuggestions": "Consulter les suggestions", + "useAsCover": "Utiliser comme couverture", + "panorama": "Panorama", + "reenterPassword": "Ressaisir le mot de passe", + "reenterPin": "Ressaisir le code PIN", + "deviceLock": "Verrouillage de l'appareil", + "pinLock": "Verrouillage du code PIN", + "next": "Suivant", + "setNewPassword": "Définir un nouveau mot de passe", + "enterPin": "Saisir le code PIN", + "setNewPin": "Définir un nouveau code PIN", + "appLock": "Verrouillage d'applications", + "noSystemLockFound": "Aucun verrou système trouvé", + "tapToUnlock": "Appuyer pour déverrouiller", + "tooManyIncorrectAttempts": "Trop de tentatives incorrectes", + "videoInfo": "Informations vidéo", + "autoLock": "Verrouillage automatique", + "immediately": "Immédiatement", + "autoLockFeatureDescription": "Délai après lequel l'application se verrouille une fois qu'elle a été mise en arrière-plan", + "hideContent": "Masquer le contenu", + "hideContentDescriptionAndroid": "Masque le contenu de l'application dans le sélecteur d'applications et désactive les captures d'écran", + "hideContentDescriptionIos": "Masque le contenu de l'application dans le sélecteur d'application", + "passwordStrengthInfo": "La force du mot de passe est calculée en tenant compte de la longueur du mot de passe, des caractères utilisés et du fait que le mot de passe figure ou non parmi les 10 000 mots de passe les plus utilisés", + "noQuickLinksSelected": "Aucun lien rapide sélectionné", + "pleaseSelectQuickLinksToRemove": "Veuillez sélectionner les liens rapides à supprimer", + "removePublicLinks": "Supprimer les liens publics", + "thisWillRemovePublicLinksOfAllSelectedQuickLinks": "Ceci supprimera les liens publics de tous les liens rapides sélectionnés.", + "cl_guest_view_title": "Vue invité", + "cl_guest_view_description": "Montrer des photos à un ami en les transmettant sur votre téléphone ? Ne vous inquiétez pas si vous les faites glisser trop loin.\nLa vue \"invité\" les verrouillera dans les photos que vous avez sélectionnées.", + "cl_guest_view_call_to_action": "Sélectionnez les photos et fixez les en \"Vue Invité\".", + "cl_panorama_viewer_title": "Visionneuse en panorama", + "cl_panorama_viewer_description": "Nous avons ajouté le support pour visionner des photos panoramiques avec des vues à 360 degrés. L'expérience est immersive avec la navigation basée sur les mouvements !", + "cl_video_player_title": "Lecteur vidéo", + "cl_video_player_description": "Intégration d'un nouveau lecteur vidéo, avec de meilleurs contrôles de lecture et la prise en charge des vidéos HDR.", + "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Pour activer le verrouillage d'application, veuillez configurer le code d'accès de l'appareil ou le verrouillage de l'écran dans les paramètres de votre système." } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_gu.arb b/mobile/lib/l10n/intl_gu.arb new file mode 100644 index 0000000000..c8494661c6 --- /dev/null +++ b/mobile/lib/l10n/intl_gu.arb @@ -0,0 +1,3 @@ +{ + "@@locale ": "en" +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_he.arb b/mobile/lib/l10n/intl_he.arb new file mode 100644 index 0000000000..ad713b19d7 --- /dev/null +++ b/mobile/lib/l10n/intl_he.arb @@ -0,0 +1,823 @@ +{ + "@@locale ": "en", + "enterYourEmailAddress": "הכנס את כתובת הדוא״ל שלך", + "accountWelcomeBack": "ברוך שובך!", + "email": "דוא\"ל", + "cancel": "בטל", + "verify": "אמת", + "invalidEmailAddress": "כתובת דוא״ל לא תקינה", + "enterValidEmail": "אנא הכנס כתובת דוא\"ל חוקית.", + "deleteAccount": "מחק חשבון", + "askDeleteReason": "מה הסיבה העיקרית שבגללה אתה מוחק את החשבון שלך?", + "deleteAccountFeedbackPrompt": "אנחנו מצטערים לראות שאתה עוזב. אנא תחלוק את המשוב שלך כדי לעזור לנו להשתפר.", + "feedback": "משוב", + "kindlyHelpUsWithThisInformation": "אנא עזור לנו עם המידע הזה", + "confirmDeletePrompt": "כן, אני רוצה למחוק לצמיתות את החשבון הזה וכל המידע שלו.", + "confirmAccountDeletion": "אשר את מחיקת החשבון", + "deleteAccountPermanentlyButton": "מחק את החשבון לצמיתות", + "yourAccountHasBeenDeleted": "החשבון שלך נמחק", + "selectReason": "בחר סיבה", + "deleteReason1": "חסר מאפיין מרכזי שאני צריך", + "deleteReason2": "היישומון או מאפיין מסוים לא מתנהג כמו שאני חושב שהוא צריך", + "deleteReason3": "מצאתי שירות אחר שאני יותר מחבב", + "deleteReason4": "הסיבה שלי לא כלולה", + "sendEmail": "שלח דוא\"ל", + "deleteRequestSLAText": "הבקשה שלך תועבד תוך 72 שעות.", + "deleteEmailRequest": "אנא תשלח דוא\"ל לaccount-deletion@ente.io מהכתובת דוא\"ל שנרשמת איתה.", + "entePhotosPerm": "Ente צריך הרשאות על מנת לשמור את התמונות שלך", + "ok": "אוקיי", + "createAccount": "צור חשבון", + "createNewAccount": "צור חשבון חדש", + "password": "סיסמא", + "confirmPassword": "אמת סיסמא", + "activeSessions": "חיבורים פעילים", + "oops": "אופס", + "somethingWentWrongPleaseTryAgain": "משהו השתבש, אנא נסה שנית", + "thisWillLogYouOutOfThisDevice": "זה ינתק אותך במכשיר זה!", + "thisWillLogYouOutOfTheFollowingDevice": "זה ינתק אותך מהמכשיר הבא:", + "terminateSession": "סיים חיבור?", + "terminate": "סיים", + "thisDevice": "מכשיר זה", + "recoverButton": "שחזר", + "recoverySuccessful": "השחזור עבר בהצלחה!", + "decrypting": "מפענח...", + "incorrectRecoveryKeyTitle": "מפתח שחזור שגוי", + "incorrectRecoveryKeyBody": "המפתח שחזור שהזנת שגוי", + "forgotPassword": "שכחתי סיסמה", + "enterYourRecoveryKey": "הזן את מפתח השחזור שלך", + "noRecoveryKey": "אין מפתח שחזור?", + "sorry": "מצטער", + "noRecoveryKeyNoDecryption": "בשל טבע הפרוטוקול של ההצפנת קצה-אל-קצה שלנו, אין אפשרות לפענח את הנתונים שלך בלי הסיסמה או מפתח השחזור שלך", + "verifyEmail": "אימות דוא\"ל", + "toResetVerifyEmail": "כדי לאפס את הסיסמא שלך, אנא אמת את האימייל שלך קודם.", + "checkInboxAndSpamFolder": "אנא בדוק את תיבת הדואר שלך (והספאם) כדי להשלים את האימות", + "tapToEnterCode": "הקש כדי להזין את הקוד", + "resendEmail": "שלח דוא\"ל מחדש", + "weHaveSendEmailTo": "שלחנו דוא\"ל ל{email}", + "@weHaveSendEmailTo": { + "description": "Text to indicate that we have sent a mail to the user", + "placeholders": { + "email": { + "description": "The email address of the user", + "type": "String", + "example": "example@ente.io" + } + } + }, + "setPasswordTitle": "הגדר סיסמא", + "changePasswordTitle": "שנה סיסמה", + "resetPasswordTitle": "איפוס סיסמה", + "encryptionKeys": "מפתחות ההצפנה", + "passwordWarning": "אנחנו לא שומרים את הסיסמא הזו, לכן אם אתה שוכח אותה, אנחנו לא יכולים לפענח את המידע שלך", + "enterPasswordToEncrypt": "הזן סיסמא כדי שנוכל לפענח את המידע שלך", + "enterNewPasswordToEncrypt": "הזן סיסמא חדשה שנוכל להשתמש בה כדי להצפין את המידע שלך", + "weakStrength": "חלשה", + "strongStrength": "חזקה", + "moderateStrength": "מתונה", + "passwordStrength": "חוזק הסיסמא: {passwordStrengthValue}", + "@passwordStrength": { + "description": "Text to indicate the password strength", + "placeholders": { + "passwordStrengthValue": { + "description": "The strength of the password as a string", + "type": "String", + "example": "Weak or Moderate or Strong" + } + }, + "message": "Password Strength: {passwordStrengthText}" + }, + "passwordChangedSuccessfully": "הססמה הוחלפה בהצלחה", + "generatingEncryptionKeys": "יוצר מפתחות הצפנה...", + "pleaseWait": "אנא המתן...", + "continueLabel": "המשך", + "insecureDevice": "מכשיר בלתי מאובטח", + "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": "אנחנו מצטערים, לא הצלחנו ליצור מפתחות מאובטחים על מכשיר זה.\n\nאנא הירשם ממכשיר אחר.", + "howItWorks": "איך זה עובד", + "encryption": "הצפנה", + "ackPasswordLostWarning": "אני מבין שאם אאבד את הסיסמא, אני עלול לאבד את המידע שלי מכיוון שהמידע שלי מוצפן מקצה אל קצה.", + "privacyPolicyTitle": "מדיניות פרטיות", + "termsOfServicesTitle": "תנאים", + "signUpTerms": "אני מסכים לתנאי שירות ולמדיניות הפרטיות", + "logInLabel": "התחבר", + "loginTerms": "על ידי לחיצה על התחברות, אני מסכים לתנאי שירות ולמדיניות הפרטיות", + "changeEmail": "שנה דוא\"ל", + "enterYourPassword": "הכנס סיסמא", + "welcomeBack": "ברוך שובך!", + "contactSupport": "צור קשר עם התמיכה", + "incorrectPasswordTitle": "סיסמא לא נכונה", + "pleaseTryAgain": "אנא נסה שנית", + "recreatePasswordTitle": "צור סיסמא מחדש", + "useRecoveryKey": "השתמש במפתח שחזור", + "recreatePasswordBody": "המכשיר הנוכחי אינו חזק מספיק כדי לאמת את הסיסמא שלך, אבל אנחנו יכולים ליצור בצורה שתעבוד עם כל המכשירים.\n\nאנא התחבר בעזרת המפתח שחזור שלך וצור מחדש את הסיסמא שלך (אתה יכול להשתמש באותה אחת אם אתה רוצה).", + "verifyPassword": "אמת סיסמא", + "recoveryKey": "מפתח שחזור", + "recoveryKeyOnForgotPassword": "אם אתה שוכח את הסיסמא שלך, הדרך היחידה שתוכל לשחזר את המידע שלך היא עם המפתח הזה.", + "recoveryKeySaveDescription": "אנחנו לא מאחסנים את המפתח הזה, אנא שמור את המפתח 24 מילים הזה במקום בטוח.", + "doThisLater": "מאוחר יותר", + "saveKey": "שמור מפתח", + "recoveryKeyCopiedToClipboard": "מפתח השחזור הועתק ללוח", + "recoverAccount": "שחזר חשבון", + "recover": "שחזר", + "dropSupportEmail": "אנא תשלח דוא\"ל ל{supportEmail} מהכתובת דוא\"ל שנרשמת איתה", + "@dropSupportEmail": { + "placeholders": { + "supportEmail": { + "description": "The support email address", + "type": "String", + "example": "support@ente.io" + } + } + }, + "twofactorSetup": "אימות דו-שלבי", + "enterCode": "הזן קוד", + "scanCode": "סרוק קוד", + "codeCopiedToClipboard": "הקוד הועתק ללוח", + "copypasteThisCodentoYourAuthenticatorApp": "תעתיק ותדביק את הקוד הזה\nלאפליקציית האימות שלך", + "tapToCopy": "הקש כדי להעתיק", + "scanThisBarcodeWithnyourAuthenticatorApp": "סרוק את הברקוד הזה\nבעזרת אפליקציית האימות שלך", + "enterThe6digitCodeFromnyourAuthenticatorApp": "הכנס את הקוד בעל 6 ספרות מתוך\nאפליקציית האימות שלך", + "confirm": "אשר", + "setupComplete": "ההתקנה הושלמה", + "saveYourRecoveryKeyIfYouHaventAlready": "שמור את מפתח השחזור שלך אם לא שמרת כבר", + "thisCanBeUsedToRecoverYourAccountIfYou": "זה יכול לשמש לשחזור החשבון שלך במקרה ותאבד את הגורם השני", + "twofactorAuthenticationPageTitle": "אימות דו-גורמי", + "lostDevice": "איבדת את המכשיר?", + "verifyingRecoveryKey": "מוודא את מפתח השחזור...", + "recoveryKeyVerified": "מפתח השחזור אומת", + "recoveryKeySuccessBody": "נהדר! מפתח השחזור תקין. אנחנו מודים לך על האימות.\n\nאנא תזכור לגבות את מפתח השחזור שלך באופן בטוח.", + "invalidRecoveryKey": "מפתח השחזור שהזמנת אינו תקין. אנא וודא שהוא מכיל 24 מילים, ותבדוק את האיות של כל אחת.\n\nאם הכנסת קוד שחזור ישן, וודא שהוא בעל 64 אותיות, ותבדוק כל אחת מהן.", + "invalidKey": "מפתח לא חוקי", + "tryAgain": "נסה שוב", + "viewRecoveryKey": "צפה במפתח השחזור", + "confirmRecoveryKey": "אמת את מפתח השחזור", + "recoveryKeyVerifyReason": "מפתח השחזור שלך הוא הדרך היחידה לשחזר את התמונות שלך במקרה ותשכח את הסיסמא שלך. אתה יכול למצוא את מפתח השחזור שלך ב-הגדרות > אבטחה.\n\nאנא הכנס את מפתח השחזור שלך כאן על מנת לוודא ששמרת אותו כשורה.", + "confirmYourRecoveryKey": "אמת את מפתח השחזור", + "addViewer": "הוסף צופה", + "addCollaborator": "הוסף משתף פעולה", + "addANewEmail": "הוסף דוא\"ל חדש", + "orPickAnExistingOne": "או בחר באחד קיים", + "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": "משתפי פעולה יכולים להוסיף תמונות וסרטונים לאלבום המשותף.", + "enterEmail": "הזן דוא\"ל", + "albumOwner": "בעלים", + "@albumOwner": { + "description": "Role of the album owner" + }, + "you": "אתה", + "collaborator": "משתף פעולה", + "addMore": "הוסף עוד", + "@addMore": { + "description": "Button text to add more collaborators/viewers" + }, + "viewer": "צפיין", + "remove": "הסר", + "removeParticipant": "הסר משתתף", + "@removeParticipant": { + "description": "menuSectionTitle for removing a participant" + }, + "manage": "נהל", + "addedAs": "הוסף בתור", + "changePermissions": "שנה הרשאה?", + "yesConvertToViewer": "כן, המר לצפיין", + "cannotAddMorePhotosAfterBecomingViewer": "{user} לא יוכל להוסיף עוד תמונות לאלבום זה\n\nהם עדיין יכולו להסיר תמונות קיימות שנוספו על ידיהם", + "allowAddingPhotos": "אפשר הוספת תמונות", + "@allowAddingPhotos": { + "description": "Switch button to enable uploading photos to a public link" + }, + "allowAddPhotosDescription": "בנוסף אפשר לאנשים עם הלינק להוסיף תמונות לאלבום המשותף.", + "passwordLock": "נעילת סיסמא", + "disableDownloadWarningTitle": "שים לב", + "disableDownloadWarningBody": "צופים יכולים עדיין לקחת צילומי מסך או לשמור עותק של התמונות שלך בעזרת כלים חיצוניים", + "allowDownloads": "אפשר הורדות", + "linkDeviceLimit": "מגבלת כמות מכשירים", + "noDeviceLimit": "אין", + "@noDeviceLimit": { + "description": "Text to indicate that there is limit on number of devices" + }, + "linkExpiry": "תאריך תפוגה ללינק", + "linkExpired": "פג תוקף", + "linkEnabled": "מאופשר", + "linkNeverExpires": "לעולם לא", + "expiredLinkInfo": "פג תוקף הקישור. אנא בחר בתאריך תפוגה חדש או השבת את תאריך התפוגה של הקישור.", + "setAPassword": "הגדר סיסמה", + "lockButtonLabel": "נעל", + "enterPassword": "הזן את הסיסמה", + "removeLink": "הסרת קישור", + "manageLink": "ניהול קישור", + "linkExpiresOn": "תוקף הקישור יפוג ב-{expiryTime}", + "albumUpdated": "האלבום עודכן", + "never": "לעולם לא", + "custom": "מותאם אישית", + "@custom": { + "description": "Label for setting custom value for link expiry" + }, + "after1Hour": "אחרי שעה 1", + "after1Day": "אחרי יום 1", + "after1Week": "אחרי שבוע 1", + "after1Month": "אחרי חודש 1", + "after1Year": "אחרי שנה 1", + "manageParticipants": "נהל", + "albumParticipantsCount": "{count, plural, one {} two {{count} משתתפים} many {{count} משתתפים}=0 {אין משתתפים} =1 {1 משתתף} other {{count} משתתפים}}", + "@albumParticipantsCount": { + "placeholders": { + "count": { + "type": "int", + "example": "5" + } + }, + "description": "Number of participants in an album, including the album owner." + }, + "collabLinkSectionDescription": "צור קישור על מנת לאפשר לאנשים להוסיף ולצפות בתמונות באלבום ששיתפת בלי צורך באפליקציית ente או חשבון. נהדר לאיסוף תמונות של אירועים.", + "collectPhotos": "אסוף תמונות", + "collaborativeLink": "קישור לשיתוף פעולה", + "shareWithNonenteUsers": "שתף עם משתמשים שהם לא של ente", + "createPublicLink": "צור קישור ציבורי", + "sendLink": "שלח קישור", + "copyLink": "העתק קישור", + "linkHasExpired": "הקישור פג תוקף", + "publicLinkEnabled": "לינק ציבורי אופשר", + "shareALink": "שתף קישור", + "sharedAlbumSectionDescription": "צור אלבומים הניתנים לשיתוף ושיתוף פעולה עם משתמשי ente אחרים, כולל משתמשים בתוכניות החינמיות.", + "shareWithPeopleSectionTitle": "{numberOfPeople, plural, one {} two {שותף עם {numberOfPeople} אנשים} many {שותף עם {numberOfPeople} אנשים}=0 {שתף עם אנשים ספציפיים} =1 {שותף עם איש 1} other {שותף עם {numberOfPeople} אנשים}}", + "@shareWithPeopleSectionTitle": { + "placeholders": { + "numberOfPeople": { + "type": "int", + "example": "2" + } + } + }, + "thisIsYourVerificationId": "זה מזהה האימות שלך", + "someoneSharingAlbumsWithYouShouldSeeTheSameId": "מי שמשתף איתך אלבומים יוכל לראות את אותו המזהה במכשיר שלהם.", + "howToViewShareeVerificationID": "אנא בקש מהם ללחוץ לחיצה ארוכה על הכתובת אימייל שלהם בעמוד ההגדרות, וודא שהמזההים בשני המכשירים תואמים.", + "thisIsPersonVerificationId": "זה מזהה האימות של {email}", + "@thisIsPersonVerificationId": { + "placeholders": { + "email": { + "type": "String", + "example": "someone@ente.io" + } + } + }, + "verificationId": "מזהה אימות", + "verifyEmailID": "אמת {email}", + "emailNoEnteAccount": "לא נמצא חשבון ente ל-{email}.\n\nשלח להם הזמנה על מנת לשתף תמונות.", + "shareMyVerificationID": "הנה מזהה האימות שלי: {verificationID} עבור ente.io.", + "shareTextConfirmOthersVerificationID": "היי, תוכל לוודא שזה מזהה האימות שלך של ente.io: {verificationID}", + "somethingWentWrong": "משהו השתבש", + "sendInvite": "שלח הזמנה", + "shareTextRecommendUsingEnte": "הורד את ente על מנת שנוכל לשתף תמונות וסרטונים באיכות המקור באופן קל\n\nhttps://ente.io", + "done": "בוצע", + "applyCodeTitle": "החל קוד", + "enterCodeDescription": "הכנס את הקוד שנמסר לך מחברך בשביל לקבל מקום אחסון בחינם עבורך ועבורו", + "apply": "החל", + "failedToApplyCode": "נכשל בהחלת הקוד", + "enterReferralCode": "הזן קוד הפניה", + "codeAppliedPageTitle": "הקוד הוחל", + "storageInGB": "{storageAmountInGB} GB", + "claimed": "נתבע", + "@claimed": { + "description": "Used to indicate storage claimed, like 10GB Claimed" + }, + "details": "פרטים", + "claimMore": "תבע עוד!", + "theyAlsoGetXGb": "הם גם יקבלו {storageAmountInGB} GB", + "freeStorageOnReferralSuccess": "{storageAmountInGB} GB כל פעם שמישהו נרשם עבור תוכנית בתשלום ומחיל את הקוד שלך", + "claimFreeStorage": "תבע מקום אחסון בחינם", + "inviteYourFriends": "הזמן את חברייך", + "failedToFetchReferralDetails": "אחזור פרטי ההפניה נכשל. אנא נסה שוב מאוחר יותר.", + "referralStep1": "1. תמסור את הקוד הזה לחברייך", + "referralStep2": "2. הם נרשמים עבור תוכנית בתשלום", + "referralStep3": "3. שניכים מקבלים {storageInGB} GB* בחינם", + "referralsAreCurrentlyPaused": "הפניות כרגע מושהות", + "youCanAtMaxDoubleYourStorage": "* אתה יכול במקסימום להכפיל את מקום האחסון שלך", + "claimedStorageSoFar": "{isFamilyMember, select, true {קיבלת {storageAmountInGb} GB עד כה} false {קיבלת {storageAmountInGb} GB עד כה} other {קיבלת {storageAmountInGb} GB עד כה!}}", + "@claimedStorageSoFar": { + "placeholders": { + "isFamilyMember": { + "type": "String", + "example": "true" + }, + "storageAmountInGb": { + "type": "int", + "example": "10" + } + } + }, + "faq": "שאלות נפוצות", + "oopsSomethingWentWrong": "אופס, משהו השתבש", + "peopleUsingYourCode": "אנשים משתמשים בקוד שלך", + "eligible": "זכאי", + "total": "סך הכל", + "codeUsedByYou": "הקוד שומש על ידיך", + "freeStorageClaimed": "מקום אחסון בחינם נתבע", + "freeStorageUsable": "מקום אחסון שמיש", + "usableReferralStorageInfo": "כמות האחסון השמישה שלך מוגבלת בתוכנית הנוכחית. אחסון עודף יהפוך שוב לשמיש אחרי שתשדרג את התוכנית שלך.", + "removeFromAlbumTitle": "הסר מהאלבום?", + "removeFromAlbum": "הסר מהאלבום", + "itemsWillBeRemovedFromAlbum": "הפריטים שנבחרו יוסרו מהאלבום הזה", + "removeShareItemsWarning": "חלק מהפריטים שאתה מסיר הוספו על ידי אנשים אחרים, ואתה תאבד גישה אליהם", + "addingToFavorites": "מוסיף למועדפים...", + "removingFromFavorites": "מסיר מהמועדפים...", + "sorryCouldNotAddToFavorites": "סליחה, לא ניתן להוסיף למועדפים!", + "sorryCouldNotRemoveFromFavorites": "סליחה, לא ניתן להסיר מהמועדפים!", + "subscribeToEnableSharing": "נראה שהמנוי שלך עומד לפוג. אנא הירשם כדי לאפשר שיתוף.", + "subscribe": "הרשם", + "canOnlyRemoveFilesOwnedByYou": "יכול להסיר רק קבצים שבבעלותך", + "deleteSharedAlbum": "מחק את האלבום המשותף?", + "deleteAlbum": "מחק אלבום", + "deleteAlbumDialog": "גם להסיר תמונות (וסרטונים) שנמצאים באלבום הזה מכל שאר האלבומים שהם שייכים אליהם?", + "deleteSharedAlbumDialogBody": "האלבום הזה יימחק עבור כולם\n\nאתה תאבד גישה לתמונות משותפות באלבום הזה שבבעלות של אחרים", + "yesRemove": "כן, הסר", + "creatingLink": "יוצר קישור...", + "removeWithQuestionMark": "הסר?", + "removeParticipantBody": "{userEmail} יוסר מהאלבום המשותף הזה\n\nגם תמונות שנוספו על ידיהם יוסרו מהאלבום", + "keepPhotos": "השאר תמונות", + "deletePhotos": "מחק תמונות", + "removePublicLink": "הסר לינק ציבורי", + "disableLinkMessage": "זה יסיר את הלינק הפומבי שדרכו ניתן לגשת ל\"{albumName}\".", + "sharing": "משתף...", + "youCannotShareWithYourself": "אתה לא יכול לשתף עם עצמך", + "archive": "שמירה בארכיון", + "createAlbumActionHint": "לחץ לחיצה ארוכה על מנת לבחור תמונות ולחץ על + על מנת ליצור אלבום", + "importing": "מייבא....", + "failedToLoadAlbums": "נכשל בטעינת האלבומים", + "hidden": "מוסתר", + "authToViewYourHiddenFiles": "אנא התאמת על מנת לראות את הקבצים החבויים שלך", + "trash": "אשפה", + "uncategorized": "ללא קטגוריה", + "videoSmallCase": "וידאו", + "photoSmallCase": "תמונה", + "singleFileDeleteHighlight": "זה יימחק מכל האלבומים.", + "singleFileDeleteFromDevice": "{fileType} יימחק מהמכשיר שלך.", + "yesDelete": "כן, מחק", + "movedToTrash": "הועבר לאשפה", + "deleteFromDevice": "מחק מהמכשיר", + "deleteFromBoth": "מחק משניהם", + "newAlbum": "אלבום חדש", + "albums": "אלבומים", + "memoryCount": "{count, plural, one{{formattedCount} זכרון} two {{formattedCount} זכרונות} many {{formattedCount} זכרונות} other{{formattedCount} זכרונות}}", + "@memoryCount": { + "description": "The text to display the number of memories", + "type": "text", + "placeholders": { + "count": { + "example": "1", + "type": "int" + }, + "formattedCount": { + "type": "String", + "example": "11.513, 11,511" + } + } + }, + "selectedPhotos": "{count} נבחרו", + "@selectedPhotos": { + "description": "Display the number of selected photos", + "type": "text", + "placeholders": { + "count": { + "example": "5", + "type": "int" + } + } + }, + "selectedPhotosWithYours": "{count} נבחרו ({yourCount} שלך)", + "@selectedPhotosWithYours": { + "description": "Display the number of selected photos, including the number of selected photos owned by the user", + "type": "text", + "placeholders": { + "count": { + "example": "12", + "type": "int" + }, + "yourCount": { + "example": "2", + "type": "int" + } + } + }, + "advancedSettings": "מתקדם", + "@advancedSettings": { + "description": "The text to display in the advanced settings section" + }, + "photoGridSize": "גודל לוח של התמונה", + "manageDeviceStorage": "נהל את מקום אחסון המכשיר", + "selectFoldersForBackup": "בחר תיקיות לגיבוי", + "selectedFoldersWillBeEncryptedAndBackedUp": "התיקיות שנבחרו יוצפנו ויגובו", + "unselectAll": "בטל בחירה של הכל", + "selectAll": "בחר הכל", + "skip": "דלג", + "updatingFolderSelection": "מעדכן את בחירת התיקיות...", + "itemCount": "{count, plural, one{{count} פריט} two {{count} פריטים} many {{count} פריטים} other{{count} פריטים}}", + "deleteItemCount": "{count, plural, one {} two {מחק {count} פריטים} many {מחק {count} פריטים}=1 {מחק {count} פריט} other {מחק {count} פריטים}}", + "duplicateItemsGroup": "{count} קבצים, כל אחד {formattedSize}", + "@duplicateItemsGroup": { + "description": "Display the number of duplicate files and their size", + "type": "text", + "placeholders": { + "count": { + "example": "12", + "type": "int" + }, + "formattedSize": { + "example": "2.3 MB", + "type": "String" + } + } + }, + "showMemories": "הצג זכרונות", + "yearsAgo": "{count, plural, one{לפני {count} שנה} two {לפני {count} שנים} many {לפני {count} שנים} other{לפני {count} שנים}}", + "backupSettings": "הגדרות גיבוי", + "backupOverMobileData": "גבה על רשת סלולרית", + "backupVideos": "גבה סרטונים", + "disableAutoLock": "השבת נעילה אוטומטית", + "about": "אודות", + "weAreOpenSource": "הקוד שלנו פתוח!", + "privacy": "פרטיות", + "terms": "תנאים", + "checkForUpdates": "בדוק עדכונים", + "checking": "בודק...", + "youAreOnTheLatestVersion": "אתה על הגרסא הכי עדכנית", + "account": "חשבון", + "manageSubscription": "נהל מנוי", + "authToChangeYourEmail": "אנא אנא התאמת על מנת לשנות את הדוא\"ל שלך", + "changePassword": "שנה סיסמה", + "authToChangeYourPassword": "אנא התאמת על מנת לשנות את הסיסמא שלך", + "emailVerificationToggle": "אימות מייל", + "authToChangeEmailVerificationSetting": "אנא התאמת על מנת לשנות את הדוא\"ל שלך", + "exportYourData": "ייצוא הנתונים שלך", + "logout": "התנתק", + "authToInitiateAccountDeletion": "אנא התאמת על מנת להתחיל את מחיקת החשבון שלך", + "areYouSureYouWantToLogout": "אתה בטוח שאתה רוצה להתנתק?", + "yesLogout": "כן, התנתק", + "update": "עדכן", + "installManually": "התקן באופן ידני", + "criticalUpdateAvailable": "עדכון חשוב זמין", + "updateAvailable": "עדכון זמין", + "ignoreUpdate": "התעלם", + "downloading": "מוריד...", + "cannotDeleteSharedFiles": "לא ניתן למחוק את הקבצים המשותפים", + "theDownloadCouldNotBeCompleted": "לא ניתן להשלים את ההורדה", + "retry": "נסה שוב", + "backedUpFolders": "תיקיות שגובו", + "backup": "גיבוי", + "freeUpDeviceSpace": "פנה אחסון במכשיר", + "allClear": "✨ הכל נוקה", + "noDeviceThatCanBeDeleted": "אין לך קבצים במכשיר הזה שניתן למחוק אותם", + "removeDuplicates": "הסר כפילויות", + "noDuplicates": "✨ אין כפילויות", + "youveNoDuplicateFilesThatCanBeCleared": "אין לך קבצים כפולים שניתן לנקות אותם", + "success": "הצלחה", + "rateUs": "דרג אותנו", + "remindToEmptyDeviceTrash": "גם נקה \"נמחק לאחרונה\" מ-\"הגדרות\" -> \"אחסון\" על מנת לקבל המקום אחסון שהתפנה", + "youHaveSuccessfullyFreedUp": "הצלחת לפנות {storageSaved}!", + "@youHaveSuccessfullyFreedUp": { + "description": "The text to display when the user has successfully freed up storage", + "type": "text", + "placeholders": { + "storageSaved": { + "example": "1.2 GB", + "type": "String" + } + } + }, + "remindToEmptyEnteTrash": "גם נקה את ה-\"אשפה\" שלך על מנת לקבל את המקום אחסון שהתפנה", + "sparkleSuccess": "✨ הצלחה", + "familyPlans": "תוכניות משפחה", + "referrals": "הפניות", + "notifications": "התראות", + "sharedPhotoNotifications": "אלבומים משותפים חדשים", + "sharedPhotoNotificationsExplanation": "קבל התראות כשמישהו מוסיף תמונה לאלבום משותף שאתה חלק ממנו", + "advanced": "מתקדם", + "general": "כללי", + "security": "אבטחה", + "authToViewYourRecoveryKey": "אנא התאמת על מנת לראות את מפתח השחזור שלך", + "twofactor": "דו-גורמי", + "authToConfigureTwofactorAuthentication": "אנא התאמת כדי להגדיר את האימות הדו-גורמי", + "lockscreen": "מסך נעילה", + "authToChangeLockscreenSetting": "אנא התאמת כדי לשנות את הגדרות מסך הנעילה", + "viewActiveSessions": "צפה בחיבורים פעילים", + "authToViewYourActiveSessions": "אנא התאמת על מנת לראות את החיבורים הפעילים שלך", + "disableTwofactor": "השבת דו-גורמי", + "confirm2FADisable": "האם אתה בטוח שאתה רוצה להשבית את האימות הדו-גורמי?", + "no": "לא", + "yes": "כן", + "social": "חברתי", + "rateUsOnStore": "דרג אותנו ב-{storeName}", + "blog": "בלוג", + "merchandise": "סחורה", + "twitter": "Twitter", + "mastodon": "Mastodon", + "matrix": "Matrix", + "discord": "Discord", + "reddit": "Reddit", + "yourStorageDetailsCouldNotBeFetched": "לא ניתן לאחזר את פרטי מקום האחסון", + "reportABug": "דווח על באג", + "reportBug": "דווח על באג", + "suggestFeatures": "הציעו מאפיינים", + "support": "תמיכה", + "theme": "ערכת נושא", + "lightTheme": "בהיר", + "darkTheme": "כהה", + "systemTheme": "מערכת", + "freeTrial": "ניסיון חינמי", + "selectYourPlan": "בחר תוכנית", + "enteSubscriptionShareWithFamily": "אפשר להוסיף גם את המשפחה שלך לתוכנית.", + "currentUsageIs": "השימוש במקום האחסון כרגע הוא ", + "@currentUsageIs": { + "description": "This text is followed by storage usage", + "examples": { + "0": "Current usage is 1.2 GB" + }, + "type": "text" + }, + "faqs": "שאלות נפוצות", + "freeTrialValidTill": "ניסיון חינם בתוקף עד ל-{endDate}", + "subWillBeCancelledOn": "המנוי שלך יבוטל ב-{endDate}", + "subscription": "מנוי", + "paymentDetails": "פרטי תשלום", + "manageFamily": "נהל משפחה", + "contactToManageSubscription": "אנא צור איתנו קשר ב-support@ente.io על מנת לנהל את המנוי {provider}.", + "renewSubscription": "חדש מנוי", + "cancelSubscription": "בטל מנוי", + "areYouSureYouWantToRenew": "אתה בטוח שאתה רוצה לחדש?", + "yesRenew": "כן, חדש", + "areYouSureYouWantToCancel": "אתה בטוח שאתה רוצה לבטל?", + "yesCancel": "כן, בטל", + "failedToRenew": "החידוש נכשל", + "failedToCancel": "הביטול נכשל", + "twoMonthsFreeOnYearlyPlans": "חודשיים בחינם בתוכניות שנתיות", + "monthly": "חודשי", + "@monthly": { + "description": "The text to display for monthly plans", + "type": "text" + }, + "yearly": "שנתי", + "@yearly": { + "description": "The text to display for yearly plans", + "type": "text" + }, + "confirmPlanChange": "אשר שינוי תוכנית", + "areYouSureYouWantToChangeYourPlan": "אתה בטוח שאתה רוצה לשנות את התוכנית שלך?", + "youCannotDowngradeToThisPlan": "אתה לא יכול לשנמך לתוכנית הזו", + "cancelOtherSubscription": "אנא בטל את המנוי הקיים מ-{paymentProvider} קודם", + "@cancelOtherSubscription": { + "description": "The text to display when the user has an existing subscription from a different payment provider", + "type": "text", + "placeholders": { + "paymentProvider": { + "example": "Apple", + "type": "String" + } + } + }, + "optionalAsShortAsYouLike": "אופציונלי, קצר ככל שתרצה...", + "send": "שלח", + "askCancelReason": "המנוי שלך בוטל. תרצה לשתף את הסיבה?", + "thankYouForSubscribing": "תודה שנרשמת!", + "yourPurchaseWasSuccessful": "התשלום שלך עבר בהצלחה", + "yourPlanWasSuccessfullyUpgraded": "התוכנית שלך שודרגה בהצלחה", + "yourPlanWasSuccessfullyDowngraded": "התוכנית שלך שונמכה בהצלחה", + "yourSubscriptionWasUpdatedSuccessfully": "המנוי שלך עודכן בהצלחה", + "googlePlayId": "Google Play ID", + "appleId": "Apple ID", + "playstoreSubscription": "מנוי PlayStore", + "appstoreSubscription": "מנוי AppStore", + "visitWebToManage": "אנא בקר ב-web.ente.io על מנת לנהל את המנוי שלך", + "couldNotUpdateSubscription": "לא ניתן לעדכן את המנוי", + "pleaseContactSupportAndWeWillBeHappyToHelp": "אנא צור קשר עם support@ente.io ואנחנו נשמח לעזור!", + "paymentFailed": "התשלום נכשל", + "paymentFailedTalkToProvider": "אנא דבר עם התמיכה של {providerName} אם אתה חוייבת", + "@paymentFailedTalkToProvider": { + "description": "The text to display when the payment failed", + "type": "text", + "placeholders": { + "providerName": { + "example": "AppStore|PlayStore", + "type": "String" + } + } + }, + "continueOnFreeTrial": "המשך עם ניסיון חינמי", + "areYouSureYouWantToExit": "האם אתה בטוח שברצונך לצאת?", + "thankYou": "תודה", + "failedToVerifyPaymentStatus": "נכשל באימות סטטוס התשלום", + "pleaseWaitForSometimeBeforeRetrying": "אנא חכה מעט לפני שאתה מנסה שוב", + "youAreOnAFamilyPlan": "אתה על תוכנית משפחתית!", + "contactFamilyAdmin": "אנא צור קשר עם {familyAdminEmail} על מנת לנהל את המנוי שלך", + "leaveFamily": "עזוב משפחה", + "areYouSureThatYouWantToLeaveTheFamily": "אתה בטוח שאתה רוצה לעזוב את התוכנית המשפתחית?", + "leave": "עזוב", + "rateTheApp": "דרג את האפליקציה", + "startBackup": "התחל גיבוי", + "noPhotosAreBeingBackedUpRightNow": "אף תמונה אינה נמצאת בתהליך גיבוי כרגע", + "preserveMore": "שמור עוד", + "grantFullAccessPrompt": "נא לתת גישה לכל התמונות בתוך ההגדרות של הטלפון", + "openSettings": "פתח הגדרות", + "selectMorePhotos": "בחר תמונות נוספות", + "existingUser": "משתמש קיים", + "privateBackups": "גיבויים פרטיים", + "forYourMemories": "עבור הזכורונות שלך", + "endtoendEncryptedByDefault": "מוצפן מקצה אל קצה כברירת מחדל", + "safelyStored": "נשמר באופן בטוח", + "atAFalloutShelter": "במקלט גרעיני", + "designedToOutlive": "עוצב על מנת לשרוד", + "available": "זמין", + "everywhere": "בכל מקום", + "androidIosWebDesktop": "Android, iOS, דפדפן, שולחן עבודה", + "mobileWebDesktop": "פלאפון, דפדפן, שולחן עבודה", + "pleaseLoginAgain": "אנא התחבר שוב", + "yourSubscriptionHasExpired": "פג תוקף המנוי שלך", + "storageLimitExceeded": "גבול מקום האחסון נחרג", + "upgrade": "שדרג", + "raiseTicket": "צור ticket", + "@raiseTicket": { + "description": "Button text for raising a support tickets in case of unhandled errors during backup", + "type": "text" + }, + "backupFailed": "הגיבוי נכשל", + "couldNotBackUpTryLater": "לא יכולנו לגבות את המידע שלך.\nאנא נסה שוב מאוחר יותר.", + "pleaseGrantPermissions": "נא הענק את ההרשאות", + "grantPermission": "הענק הרשאה", + "privateSharing": "שיתוף פרטי", + "shareOnlyWithThePeopleYouWant": "שתף רק אם אנשים שאתה בוחר", + "allowPeopleToAddPhotos": "תן לאנשים להוסיף תמונות", + "shareAnAlbumNow": "שתף אלבום עכשיו", + "collectEventPhotos": "אסף תמונות מאירוע", + "sessionExpired": "פג תוקף החיבור", + "loggingOut": "מתנתק...", + "@onDevice": { + "description": "The text displayed above folders/albums stored on device", + "type": "text" + }, + "onDevice": "על המכשיר", + "@onEnte": { + "description": "The text displayed above albums backed up to Ente", + "type": "text" + }, + "onEnte": "באנטע", + "name": "שם", + "newest": "החדש ביותר", + "lastUpdated": "עדכון אחרון", + "deleteEmptyAlbums": "למחוק אלבומים ריקים", + "deleteEmptyAlbumsWithQuestionMark": "למחוק אלבומים ריקים?", + "deleteAlbumsDialogBody": "זה ימחק את כל האלבומים הריקים. זה שימושי כשאתה רוצה להפחית את כמות האי סדר ברשימת האלבומים שלך.", + "deleteProgress": "מוחק {currentlyDeleting} / {totalCount}", + "permanentlyDelete": "למחוק לצמיתות?", + "canOnlyCreateLinkForFilesOwnedByYou": "ניתן אך ורק ליצור קישור לקבצים שאתה בבעולתם", + "publicLinkCreated": "קישור ציבורי נוצר", + "youCanManageYourLinksInTheShareTab": "אתה יכול לנהת את הקישורים שלך בלשונית שיתוף.", + "linkCopiedToClipboard": "הקישור הועתק ללוח", + "restore": "שחזר", + "@restore": { + "description": "Display text for an action which triggers a restore of item from trash", + "type": "text" + }, + "moveToAlbum": "הזז לאלבום", + "unhide": "בטל הסתרה", + "unarchive": "הוצאה מארכיון", + "favorite": "מועדף", + "shareLink": "שתף קישור", + "createCollage": "צור קולז", + "saveCollage": "שמור קולז", + "collageSaved": "הקולז נשמר לגלריה", + "collageLayout": "פריסה", + "addToAlbum": "הוסף לאלבום", + "delete": "מחק", + "hide": "הסתר", + "share": "שתף", + "unhideToAlbum": "בטל הסתרה בחזרה לאלבום", + "restoreToAlbum": "שחזר לאלבום", + "moveItem": "{count, plural, one {הזז פריט} two {הזז פריטים} many {הזז פריטים} other {הזז פריטים}}", + "@moveItem": { + "description": "Page title while moving one or more items to an album" + }, + "addItem": "{count, plural, one {הוסף פריט} two {הוסף פריטים} many {הוסף פריטים} other {הוסף פריטים}}", + "@addItem": { + "description": "Page title while adding one or more items to album" + }, + "createOrSelectAlbum": "צור או בחר אלבום", + "selectAlbum": "בחר אלבום", + "searchByAlbumNameHint": "שם האלבום", + "albumTitle": "כותרת האלבום", + "enterAlbumName": "הזן שם אלבום", + "restoringFiles": "משחזר קבצים...", + "movingFilesToAlbum": "מעביר קבצים לאלבום...", + "unhidingFilesToAlbum": "מבטל הסתרת הקבצים לאלבום", + "canNotUploadToAlbumsOwnedByOthers": "לא ניתן להעלות לאלבומים שבבעלות אחרים", + "uploadingFilesToAlbum": "מעלה קבצים לאלבום...", + "invite": "הזמן", + "shareYourFirstAlbum": "שתף את האלבום הראשון שלך", + "sharedWith": "הושתף ע\"י {emailIDs}", + "sharedWithMe": "שותף איתי", + "sharedByMe": "שותף על ידי", + "deleteAll": "מחק הכל", + "setCover": "הגדר כרקע", + "@setCover": { + "description": "Text to set cover photo for an album" + }, + "sortAlbumsBy": "מיין לפי", + "sortOldestFirst": "הישן ביותר קודם", + "rename": "שנה שם", + "leaveSharedAlbum": "לעזוב את האלבום המשותף?", + "leaveAlbum": "צא מהאלבום", + "click": "• לחץ", + "exif": "EXIF", + "noResults": "אין תוצאות", + "close": "סגור", + "setAs": "הגדר בתור", + "fileSavedToGallery": "הקובץ נשמר לגלריה", + "fileFailedToSaveToGallery": "נכשל בעת שמירת הקובץ לגלריה", + "download": "הורד", + "pressAndHoldToPlayVideo": "לחץ והחזק על מנת להריץ את הסרטון", + "pressAndHoldToPlayVideoDetailed": "לחץ והחזק על התמונה על מנת להריץ את הסרטון", + "downloadFailed": "ההורדה נכשלה", + "deduplicateFiles": "הסר קבצים כפולים", + "deselectAll": "בטל בחירה של הכל", + "reviewDeduplicateItems": "אנא בחן והסר את הפריטים שאתה מאמין שהם כפלים.", + "clubByCaptureTime": "קבץ לפי זמן הצילום", + "clubByFileName": "קבץ לפי שם הקובץ", + "count": "כמות", + "totalSize": "גודל כולל", + "longpressOnAnItemToViewInFullscreen": "לחץ לחיצה ארוכה על פריט על מנת לראות אותו במסך מלא", + "decryptingVideo": "מפענח את הסרטון...", + "authToViewYourMemories": "אנא אמת על מנת לצפות בזכרונות שלך", + "unlock": "ביטול נעילה", + "freeUpSpace": "פנה מקום", + "allMemoriesPreserved": "כל הזכרונות נשמרו", + "syncing": "מסנכרן...", + "syncProgress": "{completed}/{total} זכרונות נשמרו", + "@syncProgress": { + "description": "Text to tell user how many memories have been preserved", + "placeholders": { + "completed": { + "type": "String" + }, + "total": { + "type": "String" + } + } + }, + "renameFile": "שנה שם הקובץ", + "empty": "ריק", + "error": "שגיאה", + "cachedData": "נתונים מוטמנים", + "viewLogs": "צפייה בלוגים", + "preparingLogs": "מכין לוגים...", + "exportLogs": "ייצוא לוגים", + "dismiss": "התעלם", + "location": "מקום", + "language": "שפה", + "kiloMeterUnit": "ק\"מ", + "addLocationButton": "הוסף", + "radius": "רדיוס", + "save": "שמור", + "edit": "ערוך", + "rotateLeft": "סובב שמאלה", + "flip": "הפוך", + "saveCopy": "שמירת עותק", + "light": "אור", + "color": "צבע", + "saving": "שומר...", + "distanceInKMUnit": "ק\"מ", + "@distanceInKMUnit": { + "description": "Unit for distance in km" + }, + "dayToday": "היום", + "dayYesterday": "אתמול", + "storage": "אחסון", + "usedSpace": "מקום בשימוש", + "storageBreakupFamily": "משפחה", + "storageBreakupYou": "אתה", + "@storageBreakupYou": { + "description": "Label to indicate how much storage you are using when you are part of a family plan" + }, + "verifyIDLabel": "אמת", + "setLabel": "הגדר", + "@setLabel": { + "description": "Label of confirm button to add a new custom radius to the radius selector of a location tag" + }, + "setRadius": "הגדר רדיוס", + "familyPlanPortalTitle": "משפחה", + "androidBiometricSuccess": "הצלחה", + "@androidBiometricSuccess": { + "description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters." + }, + "androidCancelButton": "בטל", + "@androidCancelButton": { + "description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters." + }, + "iOSOkButton": "אישור", + "@iOSOkButton": { + "description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters." + }, + "map": "מפה", + "@map": { + "description": "Label for the map view" + }, + "maps": "מפות", + "addPhotos": "הוסף תמונות", + "create": "צור", + "viewAll": "הצג הכל", + "hiding": "מחביא..." +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_hi.arb b/mobile/lib/l10n/intl_hi.arb new file mode 100644 index 0000000000..35f1e866b4 --- /dev/null +++ b/mobile/lib/l10n/intl_hi.arb @@ -0,0 +1,53 @@ +{ + "@@locale ": "en", + "enterYourEmailAddress": "अपना ईमेल ऐड्रेस डालें", + "accountWelcomeBack": "आपका पुनः स्वागत है", + "email": "ईमेल", + "cancel": "रद्द करें", + "verify": "सत्यापित करें", + "invalidEmailAddress": "अमान्य ईमेल ऐड्रेस", + "enterValidEmail": "कृपया वैद्य ईमेल ऐड्रेस डालें", + "deleteAccount": "अकाउंट डिलीट करें", + "askDeleteReason": "आपका अकाउंट हटाने का मुख्य कारण क्या है?", + "deleteAccountFeedbackPrompt": "आपको जाता हुए देख कर हमें खेद है। कृपया हमें बेहतर बनने में सहायता के लिए अपनी प्रतिक्रिया साझा करें।", + "feedback": "प्रतिपुष्टि", + "kindlyHelpUsWithThisInformation": "कृपया हमें इस जानकारी के लिए सहायता करें", + "confirmDeletePrompt": "हां, मैं इस अकाउंट और इसके सभी डेटा को स्थायी रूप से हटाना चाहता/चाहती हूं।", + "confirmAccountDeletion": "अकाउंट डिलीट करने की पुष्टि करें", + "deleteAccountPermanentlyButton": "अकाउंट स्थायी रूप से डिलीट करें", + "yourAccountHasBeenDeleted": "आपका अकाउंट डिलीट कर दिया गया है", + "selectReason": "कारण चुनें", + "deleteReason1": "इसमें एक मुख्य विशेषता गायब है जिसकी मुझे आवश्यकता है", + "deleteReason2": "यह ऐप या इसका कोई एक फीचर मेरे विचारानुसार काम नहीं करता है", + "deleteReason3": "मुझे कहीं और कोई दूरी सेवा मिली जो मुझे बेहतर लगी", + "deleteReason4": "मेरा कारण इस लिस्ट में नहीं है", + "sendEmail": "ईमेल भेजें", + "deleteRequestSLAText": "आपका अनुरोध 72 घंटों के भीतर संसाधित किया जाएगा।", + "deleteEmailRequest": "कृपया account-deletion@ente.io पर अपने पंजीकृत ईमेल एड्रेस से ईमेल भेजें।", + "entePhotosPerm": "Ente को आपकी तस्वीरों को संरक्षित करने के लिए अनुमति की आवश्यकता है", + "ok": "ठीक है", + "createAccount": "अकाउंट बनायें", + "createNewAccount": "नया अकाउंट बनाएँ", + "password": "पासवर्ड", + "confirmPassword": "पासवर्ड की पुष्टि करें", + "activeSessions": "एक्टिव सेशन", + "oops": "ओह!", + "somethingWentWrongPleaseTryAgain": "कुछ गड़बड़ हुई है। कृपया दोबारा प्रयास करें।", + "thisWillLogYouOutOfThisDevice": "इससे आप इस डिवाइस से लॉग आउट हो जाएँगे!", + "thisWillLogYouOutOfTheFollowingDevice": "इससे आप इन डिवाइसों से लॉग आउट हो जाएँगे:", + "terminateSession": "सेशन रद्द करें?", + "terminate": "रद्द करें", + "thisDevice": "यह डिवाइस", + "recoverButton": "पुनः प्राप्त", + "recoverySuccessful": "रिकवरी सफल हुई!", + "decrypting": "डिक्रिप्ट हो रहा है...", + "incorrectRecoveryKeyTitle": "रिकवरी कुंजी ग़लत है", + "incorrectRecoveryKeyBody": "आपके द्वारा दर्ज रिकवरी कुंजी ग़लत है", + "forgotPassword": "पासवर्ड भूल गए", + "enterYourRecoveryKey": "अपनी रिकवरी कुंजी दर्ज करें", + "noRecoveryKey": "रिकवरी कुंजी नहीं है?", + "sorry": "क्षमा करें!", + "noRecoveryKeyNoDecryption": "हमारे एंड-टू-एंड एन्क्रिप्शन प्रोटोकॉल की प्रकृति के कारण, आपके डेटा को आपके पासवर्ड या रिकवरी कुंजी के बिना डिक्रिप्ट नहीं किया जा सकता है", + "verifyEmail": "ईमेल सत्यापित करें", + "toResetVerifyEmail": "अपना पासवर्ड रीसेट करने के लिए, कृपया पहले अपना ईमेल सत्यापित करें।" +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_id.arb b/mobile/lib/l10n/intl_id.arb new file mode 100644 index 0000000000..0768a2d798 --- /dev/null +++ b/mobile/lib/l10n/intl_id.arb @@ -0,0 +1,1069 @@ +{ + "@@locale ": "en", + "enterYourEmailAddress": "Masukkan alamat email kamu", + "accountWelcomeBack": "Selamat datang kembali!", + "email": "Email", + "cancel": "Batal", + "verify": "Verifikasi", + "invalidEmailAddress": "Alamat email tidak sah", + "enterValidEmail": "Harap masukkan alamat email yang sah.", + "deleteAccount": "Hapus akun", + "askDeleteReason": "Apa alasan utama kamu dalam menghapus akun?", + "deleteAccountFeedbackPrompt": "Kami sedih kamu pergi. Silakan bagikan masukanmu agar kami bisa jadi lebih baik.", + "feedback": "Masukan", + "kindlyHelpUsWithThisInformation": "Harap bantu kami dengan informasi ini", + "confirmDeletePrompt": "Ya, saya ingin menghapus akun ini dan seluruh data yang terkait secara permanen.", + "confirmAccountDeletion": "Konfirmasi Penghapusan Akun", + "deleteAccountPermanentlyButton": "Hapus Akun Secara Permanen", + "yourAccountHasBeenDeleted": "Akunmu telah dihapus", + "selectReason": "Pilih alasan", + "deleteReason1": "Fitur penting yang saya perlukan tidak ada", + "deleteReason2": "App ini atau fitur tertentu tidak bekerja sesuai harapan saya", + "deleteReason3": "Saya menemukan layanan lain yang lebih baik", + "deleteReason4": "Alasan saya tidak ada di daftar", + "sendEmail": "Kirim email", + "deleteRequestSLAText": "Permintaan kamu akan diproses dalam waktu 72 jam.", + "deleteEmailRequest": "Silakan kirim email ke account-deletion@ente.io dari alamat email kamu yang terdaftar.", + "entePhotosPerm": "Ente memerlukan izin untuk menyimpan fotomu", + "ok": "Oke", + "createAccount": "Buat akun", + "createNewAccount": "Buat akun baru", + "password": "Sandi", + "confirmPassword": "Konfirmasi sandi", + "activeSessions": "Sesi aktif", + "oops": "Aduh", + "somethingWentWrongPleaseTryAgain": "Terjadi kesalahan, silakan coba lagi", + "thisWillLogYouOutOfThisDevice": "Ini akan mengeluarkan akunmu dari perangkat ini!", + "thisWillLogYouOutOfTheFollowingDevice": "Ini akan mengeluarkan akunmu dari perangkat berikut:", + "terminateSession": "Akhiri sesi?", + "terminate": "Akhiri", + "thisDevice": "Perangkat ini", + "recoverButton": "Pulihkan", + "recoverySuccessful": "Pemulihan berhasil!", + "decrypting": "Mendekripsi...", + "incorrectRecoveryKeyTitle": "Kunci pemulihan salah", + "incorrectRecoveryKeyBody": "Kunci pemulihan yang kamu masukkan salah", + "forgotPassword": "Lupa sandi", + "enterYourRecoveryKey": "Masukkan kunci pemulihan kamu", + "noRecoveryKey": "Tidak punya kunci pemulihan?", + "sorry": "Maaf", + "noRecoveryKeyNoDecryption": "Karena sifat protokol enkripsi ujung ke ujung kami, data kamu tidak dapat didekripsi tanpa sandi atau kunci pemulihan kamu", + "verifyEmail": "Verifikasi email", + "toResetVerifyEmail": "Untuk mengatur ulang sandimu, harap verifikasi email kamu terlebih dahulu.", + "checkInboxAndSpamFolder": "Silakan periksa kotak masuk (serta kotak spam) untuk menyelesaikan verifikasi", + "tapToEnterCode": "Ketuk untuk masukkan kode", + "resendEmail": "Kirim ulang email", + "weHaveSendEmailTo": "Kami telah mengirimkan email ke {email}", + "@weHaveSendEmailTo": { + "description": "Text to indicate that we have sent a mail to the user", + "placeholders": { + "email": { + "description": "The email address of the user", + "type": "String", + "example": "example@ente.io" + } + } + }, + "setPasswordTitle": "Buat kata sandi", + "changePasswordTitle": "Ubah sandi", + "resetPasswordTitle": "Atur ulang kata sandi", + "encryptionKeys": "Kunci enkripsi", + "passwordWarning": "Kami tidak menyimpan sandi ini, jadi jika kamu melupakannya, kami tidak akan bisa mendekripsi data kamu", + "enterPasswordToEncrypt": "Masukkan sandi yang bisa kami gunakan untuk mengenkripsi data kamu", + "enterNewPasswordToEncrypt": "Masukkan sandi baru yang bisa kami gunakan untuk mengenkripsi data kamu", + "weakStrength": "Lemah", + "strongStrength": "Kuat", + "moderateStrength": "Sedang", + "passwordStrength": "Keamanan sandi: {passwordStrengthValue}", + "@passwordStrength": { + "description": "Text to indicate the password strength", + "placeholders": { + "passwordStrengthValue": { + "description": "The strength of the password as a string", + "type": "String", + "example": "Weak or Moderate or Strong" + } + }, + "message": "Password Strength: {passwordStrengthText}" + }, + "passwordChangedSuccessfully": "Sandi berhasil diubah", + "generatingEncryptionKeys": "Menghasilkan kunci enkripsi...", + "pleaseWait": "Harap tunggu...", + "continueLabel": "Lanjut", + "insecureDevice": "Perangkat tidak aman", + "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": "Maaf, kami tidak dapat menghasilkan kunci yang aman di perangkat ini.\n\nHarap mendaftar dengan perangkat lain.", + "howItWorks": "Cara kerjanya", + "encryption": "Enkripsi", + "ackPasswordLostWarning": "Saya mengerti bahwa jika saya lupa sandi saya, data saya bisa hilang karena dienkripsi dari ujung ke ujung.", + "privacyPolicyTitle": "Kebijakan Privasi", + "termsOfServicesTitle": "Ketentuan", + "signUpTerms": "Saya menyetujui ketentuan layanan dan kebijakan privasi Ente", + "logInLabel": "Masuk akun", + "loginTerms": "Dengan mengklik masuk akun, saya menyetujui ketentuan layanan dan kebijakan privasi Ente", + "changeEmail": "Ubah email", + "enterYourPassword": "Masukkan sandi kamu", + "welcomeBack": "Selamat datang kembali!", + "contactSupport": "Hubungi dukungan", + "incorrectPasswordTitle": "Sandi salah", + "pleaseTryAgain": "Silakan coba lagi", + "recreatePasswordTitle": "Buat kembali kata sandi", + "useRecoveryKey": "Gunakan kunci pemulihan", + "recreatePasswordBody": "Perangkat ini tidak cukup kuat untuk memverifikasi kata sandi kamu, tapi kami dapat membuat ulang kata sandi kamu sehingga dapat digunakan di semua perangkat.\n\nSilahkan masuk menggunakan kunci pemulihan dan buat ulang kata sandi kamu (Kamu dapat menggunakan kata sandi yang sama lagi jika mau).", + "verifyPassword": "Verifikasi sandi", + "recoveryKey": "Kunci pemulihan", + "recoveryKeyOnForgotPassword": "Saat kamu lupa sandi, satu-satunya cara untuk memulihkan data kamu adalah dengan kunci ini.", + "recoveryKeySaveDescription": "Kami tidak menyimpan kunci ini, jadi harap simpan kunci yang berisi 24 kata ini dengan aman.", + "doThisLater": "Lakukan lain kali", + "saveKey": "Simpan kunci", + "recoveryKeyCopiedToClipboard": "Kunci pemulihan tersalin ke papan klip", + "recoverAccount": "Pulihkan akun", + "recover": "Pulihkan", + "dropSupportEmail": "Silakan kirimkan email ke {supportEmail} dari alamat email terdaftar kamu", + "@dropSupportEmail": { + "placeholders": { + "supportEmail": { + "description": "The support email address", + "type": "String", + "example": "support@ente.io" + } + } + }, + "twofactorSetup": "Penyiapan autentikasi dua langkah", + "enterCode": "Masukkan kode", + "scanCode": "Pindai kode", + "codeCopiedToClipboard": "Kode tersalin ke papan klip", + "copypasteThisCodentoYourAuthenticatorApp": "Salin lalu tempel kode ini\ndi app autentikator kamu", + "tapToCopy": "ketuk untuk salin", + "scanThisBarcodeWithnyourAuthenticatorApp": "Pindai barcode ini dengan\napp autentikator kamu", + "enterThe6digitCodeFromnyourAuthenticatorApp": "Masukkan kode 6 angka dari\napp autentikator kamu", + "confirm": "Konfirmasi", + "setupComplete": "Penyiapan selesai", + "saveYourRecoveryKeyIfYouHaventAlready": "Jika belum, simpan kunci pemulihan kamu", + "thisCanBeUsedToRecoverYourAccountIfYou": "Ini dapat digunakan untuk memulihkan akun kamu jika kehilangan faktor kedua kamu", + "twofactorAuthenticationPageTitle": "Autentikasi dua langkah", + "lostDevice": "Perangkat hilang?", + "verifyingRecoveryKey": "Memverifikasi kunci pemulihan...", + "recoveryKeyVerified": "Kunci pemulihan terverifikasi", + "recoveryKeySuccessBody": "Bagus! Kunci pemulihan kamu sah. Terima kasih telah melakukan verifikasi.\n\nHarap simpan selalu kunci pemulihan kamu dengan aman.", + "invalidRecoveryKey": "Kunci pemulihan yang kamu masukkan tidak sah. Pastikan kunci tersebut berisi 24 kata, dan teliti ejaan masing-masing kata.\n\nJika kamu memasukkan kode pemulihan lama, pastikan kode tersebut berisi 64 karakter, dan teliti setiap karakter yang ada.", + "invalidKey": "Kunci tidak sah", + "tryAgain": "Coba lagi", + "viewRecoveryKey": "Lihat kunci pemulihan", + "confirmRecoveryKey": "Konfirmasi kunci pemulihan", + "recoveryKeyVerifyReason": "Kunci pemulihan kamu adalah satu-satunya cara untuk memulihkan foto-foto kamu jika kamu lupa kata sandi. Kamu bisa lihat kunci pemulihan kamu di Pengaturan > Keamanan.\n\nHarap masukkan kunci pemulihan kamu di sini untuk memastikan bahwa kamu telah menyimpannya dengan baik.", + "confirmYourRecoveryKey": "Konfirmasi kunci pemulihan kamu", + "addViewer": "Tambahkan pemirsa", + "addCollaborator": "Tambah kolaborator", + "addANewEmail": "Tambah email baru", + "orPickAnExistingOne": "Atau pilih yang sudah ada", + "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": "Kolaborator bisa menambahkan foto dan video ke album bersama ini.", + "enterEmail": "Masukkan email", + "albumOwner": "Pemilik", + "@albumOwner": { + "description": "Role of the album owner" + }, + "you": "Kamu", + "collaborator": "Kolaborator", + "addMore": "Tambah lagi", + "@addMore": { + "description": "Button text to add more collaborators/viewers" + }, + "viewer": "Pemirsa", + "remove": "Hapus", + "removeParticipant": "Hapus peserta", + "@removeParticipant": { + "description": "menuSectionTitle for removing a participant" + }, + "manage": "Atur", + "addedAs": "Ditambahkan sebagai", + "changePermissions": "Ubah izin?", + "yesConvertToViewer": "Ya, ubah ke pemirsa", + "cannotAddMorePhotosAfterBecomingViewer": "{user} tidak akan dapat menambahkan foto lagi di album ini\n\nMereka masih dapat menghapus foto yang sudah ada yang ditambahkan oleh mereka", + "allowAddingPhotos": "Izinkan menambah foto", + "@allowAddingPhotos": { + "description": "Switch button to enable uploading photos to a public link" + }, + "allowAddPhotosDescription": "Izinkan orang yang memiliki link untuk menambahkan foto ke album berbagi ini.", + "passwordLock": "Kunci dengan sandi", + "disableDownloadWarningTitle": "Harap dicatat", + "disableDownloadWarningBody": "Orang yang melihat masih bisa mengambil tangkapan layar atau menyalin foto kamu menggunakan alat eksternal", + "allowDownloads": "Izinkan pengunduhan", + "linkDeviceLimit": "Batas perangkat", + "noDeviceLimit": "Tidak ada", + "@noDeviceLimit": { + "description": "Text to indicate that there is limit on number of devices" + }, + "linkExpiry": "Waktu kedaluwarsa link", + "linkExpired": "Kedaluwarsa", + "linkEnabled": "Aktif", + "linkNeverExpires": "Tidak pernah", + "expiredLinkInfo": "Link ini telah kedaluwarsa. Silakan pilih waktu kedaluwarsa baru atau nonaktifkan waktu kedaluwarsa.", + "setAPassword": "Atur sandi", + "lockButtonLabel": "Kunci", + "enterPassword": "Masukkan sandi", + "removeLink": "Hapus link", + "manageLink": "Atur link", + "linkExpiresOn": "Link akan kedaluwarsa pada {expiryTime}", + "albumUpdated": "Album diperbarui", + "never": "Tidak pernah", + "custom": "Kustom", + "@custom": { + "description": "Label for setting custom value for link expiry" + }, + "after1Hour": "Setelah 1 jam", + "after1Day": "Setelah 1 hari", + "after1Week": "Setelah 1 minggu", + "after1Month": "Setelah 1 bulan", + "after1Year": "Setelah 1 tahun", + "manageParticipants": "Atur", + "albumParticipantsCount": "{count, plural, =0 {0 Peserta} =1 {1 Peserta} other {{count} Peserta}}", + "@albumParticipantsCount": { + "placeholders": { + "count": { + "type": "int", + "example": "5" + } + }, + "description": "Number of participants in an album, including the album owner." + }, + "collabLinkSectionDescription": "Buat link untuk memungkinkan orang lain menambahkan dan melihat foto yang ada pada album bersama kamu tanpa memerlukan app atau akun Ente. Ideal untuk mengumpulkan foto pada suatu acara.", + "collectPhotos": "Kumpulkan foto", + "collaborativeLink": "Link kolaborasi", + "shareWithNonenteUsers": "Bagikan ke pengguna non-Ente", + "createPublicLink": "Buat link publik", + "sendLink": "Kirim link", + "copyLink": "Salin link", + "linkHasExpired": "Link telah kedaluwarsa", + "publicLinkEnabled": "Link publik aktif", + "shareALink": "Bagikan link", + "sharedAlbumSectionDescription": "Buat album bersama dan kolaborasi dengan pengguna Ente lain, termasuk pengguna paket gratis.", + "shareWithPeopleSectionTitle": "{numberOfPeople, plural, =0 {Bagikan dengan orang tertentu} =1 {Berbagi dengan 1 orang} other {Berbagi dengan {numberOfPeople} orang}}", + "@shareWithPeopleSectionTitle": { + "placeholders": { + "numberOfPeople": { + "type": "int", + "example": "2" + } + } + }, + "thisIsYourVerificationId": "Ini adalah ID Verifikasi kamu", + "someoneSharingAlbumsWithYouShouldSeeTheSameId": "Orang yang membagikan album denganmu bisa melihat ID yang sama di perangkat mereka.", + "howToViewShareeVerificationID": "Silakan minta dia untuk menekan lama alamat email-nya di layar pengaturan, dan pastikan bahwa ID di perangkatnya sama.", + "thisIsPersonVerificationId": "Ini adalah ID Verifikasi milik {email}", + "@thisIsPersonVerificationId": { + "placeholders": { + "email": { + "type": "String", + "example": "someone@ente.io" + } + } + }, + "verificationId": "ID Verifikasi", + "verifyEmailID": "Verifikasi {email}", + "emailNoEnteAccount": "{email} tidak punya akun Ente.\n\nUndang dia untuk berbagi foto.", + "shareMyVerificationID": "Ini ID Verifikasi saya di ente.io: {verificationID}.", + "shareTextConfirmOthersVerificationID": "Halo, bisakah kamu pastikan bahwa ini adalah ID Verifikasi ente.io milikmu: {verificationID}", + "somethingWentWrong": "Terjadi kesalahan", + "sendInvite": "Kirim undangan", + "shareTextRecommendUsingEnte": "Unduh Ente agar kita bisa berbagi foto dan video kualitas asli dengan mudah\n\nhttps://ente.io", + "done": "Selesai", + "applyCodeTitle": "Terapkan kode", + "enterCodeDescription": "Masukkan kode yang diberikan temanmu untuk memperoleh kuota gratis untuk kalian berdua", + "apply": "Terapkan", + "failedToApplyCode": "Gagal menerapkan kode", + "enterReferralCode": "Masukkan kode rujukan", + "codeAppliedPageTitle": "Kode diterapkan", + "changeYourReferralCode": "Ganti kode rujukan kamu", + "change": "Ganti", + "unavailableReferralCode": "Maaf, kode ini tidak tersedia.", + "codeChangeLimitReached": "Maaf, anda telah mencapai batas rubah kode.", + "onlyFamilyAdminCanChangeCode": "Harap hubungi {familyAdminEmail} untuk mengubah kode kamu.", + "storageInGB": "{storageAmountInGB} GB", + "claimed": "Diperoleh", + "@claimed": { + "description": "Used to indicate storage claimed, like 10GB Claimed" + }, + "details": "Rincian", + "claimMore": "Peroleh lebih banyak!", + "theyAlsoGetXGb": "Ia juga mendapat {storageAmountInGB} GB", + "freeStorageOnReferralSuccess": "{storageAmountInGB} GB setiap kali orang mendaftar dengan paket berbayar lalu menerapkan kode milikmu", + "shareTextReferralCode": "Kode rujukan Ente: {referralCode} \n\nTerapkan pada Pengaturan → Umum → Rujukan untuk mendapatkan {referralStorageInGB} GB gratis setelah kamu mendaftar paket berbayar\n\nhttps://ente.io", + "claimFreeStorage": "Peroleh kuota gratis", + "inviteYourFriends": "Undang teman-temanmu", + "failedToFetchReferralDetails": "Tidak dapat mengambil kode rujukan. Harap ulang lagi nanti.", + "referralStep1": "1. Berikan kode ini ke teman kamu", + "referralStep2": "2. Ia perlu daftar ke paket berbayar", + "referralStep3": "3. Kalian berdua mendapat {storageInGB} GB* gratis", + "referralsAreCurrentlyPaused": "Rujukan sedang dijeda", + "youCanAtMaxDoubleYourStorage": "* Maksimal dua kali lipat dari kuota penyimpananmu", + "claimedStorageSoFar": "{isFamilyMember, select, true {Keluargamu saat ini telah memperoleh {storageAmountInGb} GB} false {Kamu saat ini telah memperoleh {storageAmountInGb} GB} other {Kamu saat ini telah memperoleh {storageAmountInGb} GB!}}", + "@claimedStorageSoFar": { + "placeholders": { + "isFamilyMember": { + "type": "String", + "example": "true" + }, + "storageAmountInGb": { + "type": "int", + "example": "10" + } + } + }, + "faq": "Tanya Jawab Umum", + "help": "Bantuan", + "oopsSomethingWentWrong": "Aduh, terjadi kesalahan", + "peopleUsingYourCode": "Orang yang telah menggunakan kodemu", + "eligible": "memenuhi syarat", + "total": "jumlah total", + "codeUsedByYou": "Kode yang telah kamu gunakan", + "freeStorageClaimed": "Kuota gratis diperoleh", + "freeStorageUsable": "Kuota gratis yang dapat digunakan", + "usableReferralStorageInfo": "Kuota yang dapat digunakan dibatasi oleh paket kamu saat ini. Kelebihan kuota yang diklaim, akan secara otomatis dapat digunakan saat kamu meningkatkan paket kamu.", + "removeFromAlbumTitle": "Hapus dari album?", + "removeFromAlbum": "Hapus dari album", + "itemsWillBeRemovedFromAlbum": "Item yang dipilih akan dihapus dari album ini", + "removeShareItemsWarning": "Beberapa item yang kamu hapus ditambahkan oleh orang lain, dan kamu akan kehilangan akses ke item tersebut", + "addingToFavorites": "Menambahkan ke favorit...", + "removingFromFavorites": "Menghapus dari favorit...", + "sorryCouldNotAddToFavorites": "Maaf, tidak dapat menambahkan ke favorit!", + "sorryCouldNotRemoveFromFavorites": "Maaf, tidak dapat menghapus dari favorit!", + "subscribeToEnableSharing": "Langgananmu telah berakhir. Silakan langganan kembali untuk berbagi.", + "subscribe": "Berlangganan", + "canOnlyRemoveFilesOwnedByYou": "Hanya dapat menghapus berkas yang dimiliki oleh mu", + "deleteSharedAlbum": "Hapus album bersama?", + "deleteAlbum": "Hapus album", + "deleteAlbumDialog": "Hapus foto (dan video) yang ada dalam album ini dari semua album lain yang juga menampungnya?", + "deleteSharedAlbumDialogBody": "Album ini akan di hapus untuk semua\n\nKamu akan kehilangan akses ke foto yang di bagikan dalam album ini yang di miliki oleh pengguna lain", + "yesRemove": "Ya, hapus", + "creatingLink": "Membuat link...", + "removeWithQuestionMark": "Hapus?", + "removeParticipantBody": "{userEmail} akan dikeluarkan dari album berbagi ini\n\nSemua foto yang ia tambahkan juga akan dihapus dari album ini", + "keepPhotos": "Simpan foto", + "deletePhotos": "Hapus foto", + "inviteToEnte": "Undang ke Ente", + "removePublicLink": "Hapus link publik", + "disableLinkMessage": "Ini akan menghapus link publik yang digunakan untuk mengakses \"{albumName}\".", + "sharing": "Membagikan...", + "youCannotShareWithYourself": "Kamu tidak bisa berbagi dengan dirimu sendiri", + "archive": "Arsip", + "createAlbumActionHint": "Tekan dan tahan foto lalu klik + untuk membuat album baru", + "importing": "Mengimpor....", + "failedToLoadAlbums": "Gagal memuat album", + "hidden": "Tersembunyi", + "authToViewYourHiddenFiles": "Harap autentikasi untuk melihat file tersembunyi kamu", + "trash": "Sampah", + "uncategorized": "Tak Berkategori", + "videoSmallCase": "video", + "photoSmallCase": "foto", + "singleFileDeleteHighlight": "Ia akan dihapus dari semua album.", + "singleFileInBothLocalAndRemote": "{fileType} ini tersimpan di Ente dan juga di perangkat ini.", + "singleFileInRemoteOnly": "{fileType} ini akan dihapus dari Ente.", + "singleFileDeleteFromDevice": "{fileType} ini akan dihapus dari perangkat ini.", + "deleteFromEnte": "Hapus dari Ente", + "yesDelete": "Ya, hapus", + "movedToTrash": "Pindah ke sampah", + "deleteFromDevice": "Hapus dari perangkat ini", + "deleteFromBoth": "Hapus dari keduanya", + "newAlbum": "Album baru", + "albums": "Album", + "memoryCount": "{count, plural, zero{tanpa kenangan} one{{formattedCount} kenangan} other{{formattedCount} kenangan}}", + "@memoryCount": { + "description": "The text to display the number of memories", + "type": "text", + "placeholders": { + "count": { + "example": "1", + "type": "int" + }, + "formattedCount": { + "type": "String", + "example": "11.513, 11,511" + } + } + }, + "selectedPhotos": "{count} terpilih", + "@selectedPhotos": { + "description": "Display the number of selected photos", + "type": "text", + "placeholders": { + "count": { + "example": "5", + "type": "int" + } + } + }, + "selectedPhotosWithYours": "{count} dipilih ({yourCount} milikmu)", + "@selectedPhotosWithYours": { + "description": "Display the number of selected photos, including the number of selected photos owned by the user", + "type": "text", + "placeholders": { + "count": { + "example": "12", + "type": "int" + }, + "yourCount": { + "example": "2", + "type": "int" + } + } + }, + "advancedSettings": "Lanjutan", + "@advancedSettings": { + "description": "The text to display in the advanced settings section" + }, + "photoGridSize": "Ukuran kotak foto", + "manageDeviceStorage": "Atur penyimpanan perangkat", + "machineLearning": "Pemelajaran mesin", + "mlConsent": "Aktifkan pemelajaran mesin", + "mlConsentTitle": "Aktifkan pemelajaran mesin?", + "mlConsentDescription": "Jika kamu mengaktifkan pemelajaran mesin, maka Ente akan mengambil informasi seperti geometri wajah dari berkas, termasuk berkas yg dibagikan kepada mu.\n\nIni akan dilakukan pada perangkat kamu, dan setiap informasi geometrik yang di buat akan ter enskripsi ujung ke ujung.", + "mlConsentPrivacy": "Klik di sini untuk detail lebih lanjut tentang fitur ini pada kebijakan privasi kami", + "mlConsentConfirmation": "Saya memahami, dan bersedia mengaktifkan pemelajaran mesin", + "magicSearch": "Penelusuran ajaib", + "mlIndexingDescription": "Harap diperhatikan bahwa pemelajaran mesin dapat meningkatkan penggunaan data dan baterai perangkat hingga seluruh items terindeks kan. Dianjurkan menggunakan aplikasi dekstop untuk pengindeksan lebih cepat, seluruh hasil akan tersinkronkan secara otomatis.", + "loadingModel": "Mengunduh model...", + "waitingForWifi": "Menunggu WiFi...", + "status": "Status", + "indexedItems": "Item terindeks", + "pendingItems": "Item menunggu", + "selectFoldersForBackup": "Pilih folder yang perlu dicadangkan", + "selectedFoldersWillBeEncryptedAndBackedUp": "Folder yang terpilih akan dienkripsi dan dicadangkan", + "unselectAll": "Batalkan semua pilihan", + "selectAll": "Pilih semua", + "skip": "Lewati", + "updatingFolderSelection": "Memperbaharui pilihan folder...", + "itemCount": "{count, plural, other{{count} item}}", + "deleteItemCount": "{count, plural, =1 {Hapus {count} item} other {Hapus {count} item}}", + "showMemories": "Lihat kenangan", + "yearsAgo": "{count, plural, other{{count} tahun lalu}}", + "backupSettings": "Pengaturan pencadangan", + "backupOverMobileData": "Cadangkan dengan data seluler", + "backupVideos": "Cadangkan video", + "disableAutoLock": "Nonaktifkan kunci otomatis", + "privacy": "Privasi", + "terms": "Ketentuan", + "checking": "Memeriksa...", + "youAreOnTheLatestVersion": "Kamu menggunakan versi terbaru", + "account": "Akun", + "manageSubscription": "Atur langganan", + "authToChangeYourEmail": "Harap autentikasi untuk mengubah email kamu", + "changePassword": "Ubah sandi", + "authToChangeYourPassword": "Harap autentikasi untuk mengubah sandi kamu", + "emailVerificationToggle": "Verifikasi email", + "authToChangeEmailVerificationSetting": "Harap autentikasi untuk mengatur verifikasi email", + "exportYourData": "Ekspor data kamu", + "logout": "Keluar akun", + "authToInitiateAccountDeletion": "Harap autentikasi untuk mulai penghapusan akun", + "areYouSureYouWantToLogout": "Apakah kamu yakin ingin keluar akun?", + "yesLogout": "Ya, keluar", + "aNewVersionOfEnteIsAvailable": "Versi baru dari Ente telah tersedia.", + "update": "Perbarui", + "criticalUpdateAvailable": "Pembaruan penting tersedia", + "updateAvailable": "Pembaruan tersedia", + "ignoreUpdate": "Abaikan", + "downloading": "Mengunduh...", + "retry": "Coba lagi", + "backedUpFolders": "Folder yang dicadangkan", + "backup": "Pencadangan", + "freeUpDeviceSpace": "Bersihkan penyimpanan perangkat", + "freeUpDeviceSpaceDesc": "Hemat ruang penyimpanan di perangkatmu dengan membersihkan file yang sudah tercadangkan.", + "allClear": "✨ Sudah bersih", + "noDeviceThatCanBeDeleted": "Tidak ada file yang perlu dihapus dari perangkat ini", + "removeDuplicates": "Hapus duplikat", + "removeDuplicatesDesc": "Lihat dan hapus file yang sama persis.", + "viewLargeFiles": "File berukuran besar", + "noDuplicates": "✨ Tak ada file duplikat", + "success": "Berhasil", + "youHaveSuccessfullyFreedUp": "Kamu telah berhasil membersihkan {storageSaved}!", + "@youHaveSuccessfullyFreedUp": { + "description": "The text to display when the user has successfully freed up storage", + "type": "text", + "placeholders": { + "storageSaved": { + "example": "1.2 GB", + "type": "String" + } + } + }, + "sparkleSuccess": "✨ Berhasil", + "duplicateFileCountWithStorageSaved": "Kamu telah menghapus {count, plural, other{{count} file duplikat}} dan membersihkan ({storageSaved}!)", + "@duplicateFileCountWithStorageSaved": { + "description": "The text to display when the user has successfully cleaned up duplicate files", + "type": "text", + "placeholders": { + "count": { + "example": "1", + "type": "int" + }, + "storageSaved": { + "example": "1.2 GB", + "type": "String" + } + } + }, + "familyPlans": "Paket keluarga", + "notifications": "Notifikasi", + "sharedPhotoNotifications": "Foto terbagi baru", + "advanced": "Lanjutan", + "general": "Umum", + "security": "Keamanan", + "authToViewYourRecoveryKey": "Harap autentikasi untuk melihat kunci pemulihan kamu", + "twofactor": "Autentikasi dua langkah", + "authToConfigureTwofactorAuthentication": "Harap autentikasi untuk mengatur autentikasi dua langkah", + "viewActiveSessions": "Lihat sesi aktif", + "authToViewYourActiveSessions": "Harap autentikasi untuk melihat sesi aktif kamu", + "disableTwofactor": "Nonaktifkan autentikasi dua langkah", + "confirm2FADisable": "Apakah kamu yakin ingin menonaktifkan autentikasi dua langkah?", + "no": "Tidak", + "yes": "Ya", + "social": "Sosial", + "rateUsOnStore": "Beri nilai di {storeName}", + "blog": "Blog", + "twitter": "Twitter", + "mastodon": "Mastodon", + "matrix": "Matrix", + "discord": "Discord", + "reddit": "Reddit", + "yourStorageDetailsCouldNotBeFetched": "Rincian penyimpananmu tidak dapat dimuat", + "reportABug": "Laporkan bug", + "reportBug": "Laporkan bug", + "suggestFeatures": "Sarankan fitur", + "support": "Dukungan", + "theme": "Tema", + "lightTheme": "Cerah", + "darkTheme": "Gelap", + "systemTheme": "Sistem", + "freeTrial": "Percobaan gratis", + "selectYourPlan": "Pilih paket kamu", + "enteSubscriptionPitch": "Ente memelihara kenanganmu, sehingga ia selalu tersedia untukmu, bahkan jika kamu kehilangan perangkatmu.", + "enteSubscriptionShareWithFamily": "Anggota keluargamu juga bisa ditambahkan ke paketmu.", + "currentUsageIs": "Pemakaian saat ini sebesar ", + "@currentUsageIs": { + "description": "This text is followed by storage usage", + "examples": { + "0": "Current usage is 1.2 GB" + }, + "type": "text" + }, + "faqs": "Tanya Jawab Umum", + "renewsOn": "Langganan akan diperpanjang pada {endDate}", + "freeTrialValidTill": "Percobaan gratis berlaku hingga {endDate}", + "validTill": "Berlaku hingga {endDate}", + "playStoreFreeTrialValidTill": "Percobaan gratis berlaku hingga {endDate}.\nKamu dapat memilih paket berbayar setelahnya.", + "subWillBeCancelledOn": "Langganan kamu akan dibatalkan pada {endDate}", + "subscription": "Langganan", + "paymentDetails": "Rincian pembayaran", + "manageFamily": "Atur Keluarga", + "contactToManageSubscription": "Silakan hubungi kami di support@ente.io untuk mengatur langganan {provider} kamu.", + "renewSubscription": "Perpanjang langganan", + "cancelSubscription": "Batalkan langganan", + "areYouSureYouWantToRenew": "Apakah kamu yakin ingin memperpanjang?", + "yesRenew": "Ya, Perpanjang", + "areYouSureYouWantToCancel": "Apakah kamu yakin ingin membatalkan?", + "yesCancel": "Ya, batalkan", + "failedToRenew": "Gagal memperpanjang", + "failedToCancel": "Gagal membatalkan", + "twoMonthsFreeOnYearlyPlans": "2 bulan gratis dengan paket tahunan", + "monthly": "Bulanan", + "@monthly": { + "description": "The text to display for monthly plans", + "type": "text" + }, + "yearly": "Tahunan", + "@yearly": { + "description": "The text to display for yearly plans", + "type": "text" + }, + "confirmPlanChange": "Konfirmasi perubahan paket", + "areYouSureYouWantToChangeYourPlan": "Apakah kamu yakin ingin mengubah paket kamu?", + "optionalAsShortAsYouLike": "Opsional, pendek pun tak apa...", + "send": "Kirim", + "askCancelReason": "Langganan kamu telah dibatalkan. Apakah kamu ingin membagikan alasannya?", + "thankYouForSubscribing": "Terima kasih telah berlangganan!", + "yourPurchaseWasSuccessful": "Pembelianmu berhasil", + "yourSubscriptionWasUpdatedSuccessfully": "Langgananmu telah berhasil diperbarui", + "googlePlayId": "ID Google Play", + "appleId": "ID Apple", + "subAlreadyLinkedErrMessage": "{id} kamu telah terhubung dengan akun Ente lain.\nJika kamu ingin menggunakan {id} kamu untuk akun ini, silahkan hubungi tim bantuan kami", + "visitWebToManage": "Silakan buka web.ente.io untuk mengatur langgananmu", + "pleaseContactSupportAndWeWillBeHappyToHelp": "Silakan hubungi support@ente.io dan kami akan dengan senang hati membantu!", + "paymentFailed": "Pembayaran gagal", + "continueOnFreeTrial": "Lanjut dengan percobaan gratis", + "areYouSureYouWantToExit": "Apakah kamu yakin ingin keluar?", + "thankYou": "Terima kasih", + "failedToVerifyPaymentStatus": "Gagal memeriksa status pembayaran", + "pleaseWaitForSometimeBeforeRetrying": "Harap tunggu beberapa saat sebelum mencoba lagi", + "paymentFailedMessage": "Sayangnya, pembayaranmu gagal. Silakan hubungi tim bantuan agar dapat kami bantu!", + "youAreOnAFamilyPlan": "Kamu menggunakan paket keluarga!", + "contactFamilyAdmin": "Silakan hubungi {familyAdminEmail} untuk mengatur langgananmu", + "leaveFamily": "Tinggalkan keluarga", + "areYouSureThatYouWantToLeaveTheFamily": "Apakah kamu yakin ingin meninggalkan paket keluarga ini?", + "leave": "Tinggalkan", + "rateTheApp": "Nilai app ini", + "startBackup": "Mulai pencadangan", + "grantFullAccessPrompt": "Harap berikan akses ke semua foto di app Pengaturan", + "openSettings": "Buka Pengaturan", + "existingUser": "Masuk", + "privateBackups": "Cadangan pribadi", + "forYourMemories": "untuk kenanganmu", + "endtoendEncryptedByDefault": "Dirancang dengan enkripsi ujung ke ujung", + "safelyStored": "Tersimpan aman", + "atAFalloutShelter": "di tempat pengungsian", + "designedToOutlive": "Dibuat untuk melestarikan", + "available": "Tersedia", + "everywhere": "di mana saja", + "androidIosWebDesktop": "Android, iOS, Web, Desktop", + "mobileWebDesktop": "Seluler, Web, Desktop", + "pleaseLoginAgain": "Silakan masuk akun lagi", + "autoLogoutMessage": "Akibat kesalahan teknis, kamu telah keluar dari akunmu. Kami mohon maaf atas ketidaknyamanannya.", + "yourSubscriptionHasExpired": "Langgananmu telah berakhir", + "backupFailed": "Pencadangan gagal", + "couldNotBackUpTryLater": "Kami tidak dapat mencadangkan data kamu.\nKami akan coba lagi nanti.", + "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": "Ente hanya dapat mengenkripsi dan menyimpan file jika kamu berikan izin", + "pleaseGrantPermissions": "Harap berikan izin", + "grantPermission": "Berikan izin", + "shareOnlyWithThePeopleYouWant": "Bagikan hanya dengan orang yang kamu inginkan", + "usePublicLinksForPeopleNotOnEnte": "Bagikan link publik ke orang yang tidak menggunakan Ente", + "allowPeopleToAddPhotos": "Izinkan orang lain menambahkan foto", + "shareAnAlbumNow": "Bagikan album sekarang", + "collectEventPhotos": "Kumpulkan foto acara", + "loggingOut": "Mengeluarkan akun...", + "@onDevice": { + "description": "The text displayed above folders/albums stored on device", + "type": "text" + }, + "onDevice": "Di perangkat ini", + "@onEnte": { + "description": "The text displayed above albums backed up to Ente", + "type": "text" + }, + "onEnte": "Di ente", + "deleteEmptyAlbums": "Hapus album kosong", + "deleteEmptyAlbumsWithQuestionMark": "Hapus album yang kosong?", + "deleteProgress": "Menghapus {currentlyDeleting} / {totalCount}", + "genericProgress": "Memproses {currentlyProcessing} / {totalCount}", + "@genericProgress": { + "description": "Generic progress text to display when processing multiple items", + "type": "text", + "placeholders": { + "currentlyProcessing": { + "example": "1", + "type": "int" + }, + "totalCount": { + "example": "10", + "type": "int" + } + } + }, + "permanentlyDelete": "Hapus secara permanen", + "publicLinkCreated": "Link publik dibuat", + "youCanManageYourLinksInTheShareTab": "Kamu bisa atur link yang telah kamu buat di tab berbagi.", + "linkCopiedToClipboard": "Link tersalin ke papan klip", + "restore": "Pulihkan", + "@restore": { + "description": "Display text for an action which triggers a restore of item from trash", + "type": "text" + }, + "unarchive": "Keluarkan dari arsip", + "shareLink": "Bagikan link", + "addToEnte": "Tambah ke Ente", + "addToAlbum": "Tambah ke album", + "delete": "Hapus", + "hide": "Sembunyikan", + "share": "Bagikan", + "moveItem": "{count, plural, other {Pindahkan item}}", + "@moveItem": { + "description": "Page title while moving one or more items to an album" + }, + "addItem": "{count, plural, other {Tambahkan item}}", + "@addItem": { + "description": "Page title while adding one or more items to album" + }, + "createOrSelectAlbum": "Buat atau pilih album", + "selectAlbum": "Pilih album", + "searchByAlbumNameHint": "Nama album", + "albumTitle": "Judul album", + "enterAlbumName": "Masukkan nama album", + "restoringFiles": "Memulihkan file...", + "movingFilesToAlbum": "Memindahkan file ke album...", + "uploadingFilesToAlbum": "Mengunggah file ke album...", + "addedSuccessfullyTo": "Berhasil ditambahkan ke {albumName}", + "movedSuccessfullyTo": "Berhasil dipindahkan ke {albumName}", + "thisAlbumAlreadyHDACollaborativeLink": "Link kolaborasi untuk album ini sudah terbuat", + "collaborativeLinkCreatedFor": "Link kolaborasi terbuat untuk {albumName}", + "invite": "Undang", + "shareYourFirstAlbum": "Bagikan album pertamamu", + "sharedWith": "Dibagikan dengan {emailIDs}", + "sharedWithMe": "Dibagikan dengan saya", + "sharedByMe": "Dibagikan oleh saya", + "doubleYourStorage": "Gandakan kuota kamu", + "shareAlbumHint": "Buka album lalu ketuk tombol bagikan di sudut kanan atas untuk berbagi.", + "trashDaysLeft": "{count, plural, =0 {} =1 {1 hari} other {{count} hari}}", + "@trashDaysLeft": { + "description": "Text to indicate number of days remaining before permanent deletion", + "placeholders": { + "count": { + "example": "1|2|3", + "type": "int" + } + } + }, + "deleteAll": "Hapus Semua", + "renameAlbum": "Ubah nama album", + "convertToAlbum": "Ubah menjadi album", + "setCover": "Ubah sampul", + "@setCover": { + "description": "Text to set cover photo for an album" + }, + "sortAlbumsBy": "Urut berdasarkan", + "sortNewestFirst": "Terbaru dulu", + "sortOldestFirst": "Terlama dulu", + "rename": "Ubah nama", + "leaveSharedAlbum": "Tinggalkan album bersama?", + "leaveAlbum": "Tinggalkan album", + "photosAddedByYouWillBeRemovedFromTheAlbum": "Foto yang telah kamu tambahkan akan dihapus dari album ini", + "youDontHaveAnyArchivedItems": "Kamu tidak memiliki item di arsip.", + "ignoredFolderUploadReason": "Sejumlah file di album ini tidak terunggah karena telah dihapus sebelumnya dari Ente.", + "deviceFilesAutoUploading": "File yang ditambahkan ke album perangkat ini akan diunggah ke Ente secara otomatis.", + "turnOnBackupForAutoUpload": "Aktifkan pencadangan untuk mengunggah file yang ditambahkan ke folder ini ke Ente secara otomatis.", + "noHiddenPhotosOrVideos": "Tidak ada foto atau video tersembunyi", + "toHideAPhotoOrVideo": "Untuk menyembunyikan foto atau video", + "openTheItem": "• Buka item-nya", + "click": "• Click", + "nothingToSeeHere": "Tidak ada apa-apa di sini! 👀", + "unarchiveAlbum": "Keluarkan album dari arsip", + "archiveAlbum": "Arsipkan album", + "calculating": "Menghitung...", + "pleaseWaitDeletingAlbum": "Harap tunggu, sedang menghapus album", + "searchByExamples": "• Nama album (cth. \"Kamera\")\n• Jenis file (cth. \"Video\", \".gif\")\n• Tahun atau bulan (cth. \"2022\", \"Januari\")\n• Musim liburan (cth. \"Natal\")\n• Keterangan foto (cth. “#seru”)", + "noResultsFound": "Tidak ditemukan hasil", + "addedBy": "Ditambahkan oleh {emailOrName}", + "loadingExifData": "Memuat data EXIF...", + "viewAllExifData": "Lihat seluruh data EXIF", + "noExifData": "Tidak ada data EXIF", + "thisImageHasNoExifData": "Gambar ini tidak memiliki data exif", + "exif": "EXIF", + "noResults": "Tidak ada hasil", + "failedToFetchOriginalForEdit": "Gagal memuat file asli untuk mengedit", + "close": "Tutup", + "setAs": "Pasang sebagai", + "fileSavedToGallery": "File tersimpan ke galeri", + "filesSavedToGallery": "File tersimpan ke galeri", + "fileFailedToSaveToGallery": "Gagal menyimpan file ke galeri", + "download": "Unduh", + "pressAndHoldToPlayVideo": "Tekan dan tahan untuk memutar video", + "pressAndHoldToPlayVideoDetailed": "Tekan dan tahan gambar untuk memutar video", + "downloadFailed": "Gagal mengunduh", + "reviewDeduplicateItems": "Silakan lihat dan hapus item yang merupakan duplikat.", + "count": "Jumlah", + "decryptingVideo": "Mendekripsi video...", + "authToViewYourMemories": "Harap autentikasi untuk melihat kenanganmu", + "unlock": "Buka", + "freeUpSpace": "Bersihkan ruang", + "freeUpSpaceSaving": "{count, plural, other {File tersebut bisa dihapus dari perangkat ini untuk membersihkan {formattedSize}}}", + "filesBackedUpInAlbum": "{count, plural, other {{formattedNumber} file}} dalam album ini telah berhasil dicadangkan", + "@filesBackedUpInAlbum": { + "description": "Text to tell user how many files have been backed up in the album", + "placeholders": { + "count": { + "example": "1", + "type": "int" + }, + "formattedNumber": { + "content": "{formattedNumber}", + "example": "1,000", + "type": "String" + } + } + }, + "filesBackedUpFromDevice": "{count, plural, other {{formattedNumber} file}} di perangkat ini telah berhasil dicadangkan", + "@filesBackedUpFromDevice": { + "description": "Text to tell user how many files have been backed up from this device", + "placeholders": { + "count": { + "example": "1", + "type": "int" + }, + "formattedNumber": { + "content": "{formattedNumber}", + "example": "1,000", + "type": "String" + } + } + }, + "@freeUpSpaceSaving": { + "description": "Text to tell user how much space they can free up by deleting items from the device" + }, + "freeUpAccessPostDelete": "Kamu masih bisa mengakses {count, plural, other {filenya}} di Ente selama kamu masih berlangganan", + "@freeUpAccessPostDelete": { + "placeholders": { + "count": { + "example": "1", + "type": "int" + } + } + }, + "freeUpAmount": "Bersihkan {sizeInMBorGB}", + "thisEmailIsAlreadyInUse": "Email ini telah digunakan", + "incorrectCode": "Kode salah", + "authenticationFailedPleaseTryAgain": "Autentikasi gagal, silakan coba lagi", + "verificationFailedPleaseTryAgain": "Verifikasi gagal, silakan coba lagi", + "authenticationSuccessful": "Autentikasi berhasil!", + "incorrectRecoveryKey": "Kunci pemulihan salah", + "theRecoveryKeyYouEnteredIsIncorrect": "Kunci pemulihan yang kamu masukkan salah", + "twofactorAuthenticationSuccessfullyReset": "Autentikasi dua langkah berhasil direset", + "pleaseVerifyTheCodeYouHaveEntered": "Harap periksa kode yang kamu masukkan", + "pleaseContactSupportIfTheProblemPersists": "Silakan hubungi tim bantuan jika masalah terus terjadi", + "twofactorAuthenticationHasBeenDisabled": "Autentikasi dua langkah telah dinonaktifkan", + "sorryTheCodeYouveEnteredIsIncorrect": "Maaf, kode yang kamu masukkan salah", + "yourVerificationCodeHasExpired": "Kode verifikasi kamu telah kedaluwarsa", + "emailChangedTo": "Email diubah menjadi {newEmail}", + "disablingTwofactorAuthentication": "Menonaktifkan autentikasi dua langkah...", + "allMemoriesPreserved": "Semua kenangan terpelihara", + "loadingGallery": "Memuat galeri...", + "syncing": "Menyinkronkan...", + "encryptingBackup": "Mengenkripsi cadangan...", + "syncStopped": "Sinkronisasi terhenti", + "archiving": "Mengarsipkan...", + "unarchiving": "Mengeluarkan dari arsip...", + "successfullyArchived": "Berhasil diarsipkan", + "successfullyUnarchived": "Berhasil dikeluarkan dari arsip", + "renameFile": "Ubah nama file", + "enterFileName": "Masukkan nama file", + "filesDeleted": "File terhapus", + "selectedFilesAreNotOnEnte": "File terpilih tidak tersimpan di Ente", + "thisActionCannotBeUndone": "Tindakan ini tidak dapat dibatalkan", + "emptyTrash": "Kosongkan sampah?", + "permDeleteWarning": "Semua item di sampah akan dihapus secara permanen\n\nTindakan ini tidak dapat dibatalkan", + "empty": "Kosongkan", + "couldNotFreeUpSpace": "Tidak dapat membersihkan ruang", + "permanentlyDeleteFromDevice": "Hapus dari perangkat secara permanen?", + "someItemsAreInBothEnteAndYourDevice": "Sejumlah item tersimpan di Ente serta di perangkat ini.", + "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": "Item terpilih akan dihapus dari semua album dan dipindahkan ke sampah.", + "theseItemsWillBeDeletedFromYourDevice": "Item ini akan dihapus dari perangkat ini.", + "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Sepertinya terjadi kesalahan. Silakan coba lagi setelah beberapa saat. Jika kesalahan terus terjadi, silakan hubungi tim dukungan kami.", + "error": "Kesalahan", + "tempErrorContactSupportIfPersists": "Sepertinya terjadi kesalahan. Silakan coba lagi setelah beberapa saat. Jika kesalahan terus terjadi, silakan hubungi tim dukungan kami.", + "networkHostLookUpErr": "Tidak dapat terhubung dengan Ente, harap periksa pengaturan jaringan kamu dan hubungi dukungan jika masalah berlanjut.", + "networkConnectionRefusedErr": "Tidak dapat terhubung dengan Ente, silakan coba lagi setelah beberapa saat. Jika masalah berlanjut, harap hubungi dukungan.", + "cachedData": "Data cache", + "todaysLogs": "Log hari ini", + "viewLogs": "Lihat log", + "preparingLogs": "Menyiapkan log...", + "pleaseSendTheLogsTo": "Silakan kirim log-nya ke \n{toEmail}", + "copyEmailAddress": "Salin alamat email", + "exportLogs": "Ekspor log", + "pleaseEmailUsAt": "Silakan kirimi kami email di {toEmail}", + "didYouKnow": "Tahukah kamu?", + "loadingMessage": "Memuat fotomu...", + "loadMessage1": "Kamu bisa membagikan langgananmu dengan keluarga", + "loadMessage2": "Kami telah memelihara lebih dari 30 juta kenangan saat ini", + "loadMessage3": "Kami menyimpan 3 salinan dari data kamu, salah satunya di tempat pengungsian bawah tanah", + "loadMessage7": "App seluler kami berjalan di latar belakang untuk mengenkripsi dan mencadangkan foto yang kamu potret", + "loadMessage8": "web.ente.io menyediakan alat pengunggah yang bagus", + "loadMessage9": "Kami menggunakan Xchacha20Poly1305 untuk mengenkripsi data-mu dengan aman", + "photoDescriptions": "Keterangan foto", + "fileTypesAndNames": "Nama dan jenis file", + "moments": "Momen", + "searchFaceEmptySection": "Orang akan ditampilkan di sini setelah pengindeksan selesai", + "searchDatesEmptySection": "Telusuri dengan tanggal, bulan, atau tahun", + "searchAlbumsEmptySection": "Album", + "searchFileTypesAndNamesEmptySection": "Nama dan jenis file", + "searchCaptionEmptySection": "Tambah keterangan seperti \"#trip\" pada info foto agar mudah ditemukan di sini", + "language": "Bahasa", + "selectLanguage": "Pilih Bahasa", + "locationName": "Nama tempat", + "addLocation": "Tambah tempat", + "groupNearbyPhotos": "Kelompokkan foto yang berdekatan", + "kiloMeterUnit": "km", + "addLocationButton": "Tambah", + "radius": "Radius", + "save": "Simpan", + "useSelectedPhoto": "Gunakan foto terpilih", + "edit": "Edit", + "rotateLeft": "Putar ke kiri", + "flip": "Balik", + "rotateRight": "Putar ke kanan", + "light": "Cahaya", + "color": "Warna", + "yesDiscardChanges": "Ya, buang perubahan", + "doYouWantToDiscardTheEditsYouHaveMade": "Apakah kamu ingin membuang edit yang telah kamu buat?", + "saving": "Menyimpan...", + "editsSaved": "Perubahan tersimpan", + "oopsCouldNotSaveEdits": "Aduh, tidak dapat menyimpan perubahan", + "distanceInKMUnit": "km", + "@distanceInKMUnit": { + "description": "Unit for distance in km" + }, + "dayToday": "Hari Ini", + "dayYesterday": "Kemarin", + "storage": "Penyimpanan", + "storageBreakupFamily": "Keluarga", + "storageBreakupYou": "Kamu", + "@storageBreakupYou": { + "description": "Label to indicate how much storage you are using when you are part of a family plan" + }, + "storageUsageInfo": "{usedAmount} {usedStorageUnit} dari {totalAmount} {totalStorageUnit} terpakai", + "@storageUsageInfo": { + "description": "Example: 1.2 GB of 2 GB used or 100 GB or 2TB used" + }, + "availableStorageSpace": "{freeAmount} {storageUnit} tersedia", + "appVersion": "Versi: {versionValue}", + "fileInfoAddDescHint": "Tambahkan keterangan...", + "editLocationTagTitle": "Edit lokasi", + "familyPlanPortalTitle": "Keluarga", + "familyPlanOverview": "Tambahkan 5 anggota keluarga ke paket kamu tanpa perlu bayar lebih.\n\nSetiap anggota mendapat ruang pribadi mereka sendiri, dan tidak dapat melihat file orang lain kecuali dibagikan.\n\nPaket keluarga tersedia bagi pelanggan yang memiliki langganan berbayar Ente.\n\nLangganan sekarang untuk mulai!", + "androidBiometricHint": "Verifikasi identitas", + "@androidBiometricHint": { + "description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters." + }, + "androidBiometricNotRecognized": "Tidak dikenal. Coba lagi.", + "@androidBiometricNotRecognized": { + "description": "Message to let the user know that authentication was failed. It is used on Android side. Maximum 60 characters." + }, + "androidBiometricSuccess": "Berhasil", + "@androidBiometricSuccess": { + "description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters." + }, + "androidCancelButton": "Batal", + "@androidCancelButton": { + "description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters." + }, + "androidSignInTitle": "Autentikasi diperlukan", + "@androidSignInTitle": { + "description": "Message showed as a title in a dialog which indicates the user that they need to scan biometric to continue. It is used on Android side. Maximum 60 characters." + }, + "androidBiometricRequiredTitle": "Biometrik diperlukan", + "@androidBiometricRequiredTitle": { + "description": "Message showed as a title in a dialog which indicates the user has not set up biometric authentication on their device. It is used on Android side. Maximum 60 characters." + }, + "goToSettings": "Buka pengaturan", + "@goToSettings": { + "description": "Message showed on a button that the user can click to go to settings pages from the current dialog. It is used on both Android and iOS side. Maximum 30 characters." + }, + "androidGoToSettingsDescription": "Autentikasi biometrik belum aktif di perangkatmu. Buka 'Setelan > Keamanan' untuk mengaktifkan autentikasi biometrik.", + "@androidGoToSettingsDescription": { + "description": "Message advising the user to go to the settings and configure biometric on their device. It shows in a dialog on Android side." + }, + "iOSGoToSettingsDescription": "Autentikasi biometrik belum aktif di perangkatmu. Silakan aktifkan Touch ID atau Face ID pada ponselmu.", + "@iOSGoToSettingsDescription": { + "description": "Message advising the user to go to the settings and configure Biometrics for their device. It shows in a dialog on iOS side." + }, + "iOSOkButton": "OK", + "@iOSOkButton": { + "description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters." + }, + "openstreetmapContributors": "Kontributor OpenStreetMap", + "hostedAtOsmFrance": "Dihosting oleh OSM France", + "map": "Peta", + "@map": { + "description": "Label for the map view" + }, + "maps": "Peta", + "enableMaps": "Aktifkan Peta", + "selectItemsToAdd": "Pilih item untuk ditambahkan", + "addSelected": "Tambahkan yang dipilih", + "addFromDevice": "Tambahkan dari perangkat", + "addPhotos": "Tambah foto", + "noPhotosFoundHere": "Tidak ada foto di sini", + "zoomOutToSeePhotos": "Perkecil peta untuk melihat foto lainnya", + "create": "Buat", + "viewAll": "Lihat semua", + "nothingSharedWithYouYet": "Belum ada yang dibagikan denganmu", + "noAlbumsSharedByYouYet": "Belum ada album yang kamu bagikan", + "sharedWithYou": "Dibagikan dengan kamu", + "sharedByYou": "Dibagikan oleh kamu", + "inviteYourFriendsToEnte": "Undang temanmu ke Ente", + "failedToDownloadVideo": "Gagal mengunduh video", + "hiding": "Menyembunyikan...", + "successfullyHid": "Berhasil disembunyikan", + "crashReporting": "Pelaporan crash", + "addToHiddenAlbum": "Tambah ke album tersembunyi", + "moveToHiddenAlbum": "Pindahkan ke album tersembunyi", + "fileTypes": "Jenis file", + "hearUsWhereTitle": "Dari mana Anda menemukan Ente? (opsional)", + "yourMap": "Peta kamu", + "blackFridaySale": "Penawaran Black Friday", + "upto50OffUntil4thDec": "Potongan hingga 50%, sampai 4 Des.", + "photos": "Foto", + "videos": "Video", + "searchHint2": "Tanggal, keterangan foto", + "searchHint3": "Album, nama dan jenis file", + "searchHint5": "Segera tiba: Penelusuran wajah & ajaib ✨", + "searchResultCount": "{count, plural, other{{count} hasil ditemukan}}", + "@searchResultCount": { + "description": "Text to tell user how many results were found for their search query", + "placeholders": { + "count": { + "example": "1|2|3", + "type": "int" + } + } + }, + "faces": "Wajah", + "people": "Orang", + "contacts": "Kontak", + "noInternetConnection": "Tidak ada koneksi internet", + "pleaseCheckYourInternetConnectionAndTryAgain": "Silakan periksa koneksi internet kamu, lalu coba lagi.", + "signOutFromOtherDevices": "Keluarkan akun dari perangkat lain", + "signOutOtherBody": "Jika kamu merasa ada yang mengetahui sandimu, kamu bisa mengeluarkan akunmu secara paksa dari perangkat lain.", + "signOutOtherDevices": "Keluar di perangkat lain", + "doNotSignOut": "Jangan keluarkan akun", + "editLocation": "Edit lokasi", + "selectALocation": "Pilih lokasi", + "selectALocationFirst": "Pilih lokasi terlebih dahulu", + "changeLocationOfSelectedItems": "Ubah lokasi pada item terpilih?", + "editsToLocationWillOnlyBeSeenWithinEnte": "Perubahan lokasi hanya akan terlihat di Ente", + "waitingForVerification": "Menunggu verifikasi...", + "passkey": "Passkey", + "passkeyAuthTitle": "Verifikasi passkey", + "loginSessionExpired": "Sesi berakhir", + "loginSessionExpiredDetails": "Sesi kamu telah berakhir. Silakan masuk akun kembali.", + "verifyPasskey": "Verifikasi passkey", + "playOnTv": "Putar album di TV", + "pair": "Tautkan", + "deviceNotFound": "Perangkat tidak ditemukan", + "castInstruction": "Buka cast.ente.io pada perangkat yang ingin kamu tautkan.\n\nMasukkan kode yang ditampilkan untuk memutar album di TV.", + "deviceCodeHint": "Masukkan kode", + "joinDiscord": "Bergabung ke Discord", + "descriptions": "Keterangan", + "addAName": "Tambahkan nama", + "findPeopleByName": "Telusuri orang dengan mudah menggunakan nama", + "addCollaborators": "{count, plural, other {Tambahkan kolaborator}}", + "longPressAnEmailToVerifyEndToEndEncryption": "Tekan dan tahan email untuk membuktikan enkripsi ujung ke ujung.", + "developerSettingsWarning": "Apakah kamu yakin ingin mengubah pengaturan pengembang?", + "developerSettings": "Pengaturan pengembang", + "serverEndpoint": "Endpoint server", + "invalidEndpoint": "Endpoint tidak sah", + "invalidEndpointMessage": "Maaf, endpoint yang kamu masukkan tidak sah. Harap masukkan endpoint yang sah dan coba lagi.", + "endpointUpdatedMessage": "Endpoint berhasil diubah", + "customEndpoint": "Terhubung ke {endpoint}", + "createCollaborativeLink": "Buat link kolaborasi", + "search": "Telusuri", + "enterPersonName": "Masukkan nama orang", + "removePersonLabel": "Hapus label orang", + "autoPairDesc": "Taut otomatis hanya tersedia di perangkat yang mendukung Chromecast.", + "manualPairDesc": "Tautkan dengan PIN berfungsi di layar mana pun yang kamu inginkan.", + "connectToDevice": "Hubungkan ke perangkat", + "autoCastDialogBody": "Perangkat Cast yang tersedia akan ditampilkan di sini.", + "autoCastiOSPermission": "Pastikan izin Jaringan Lokal untuk app Ente Foto aktif di Pengaturan.", + "noDeviceFound": "Tidak ditemukan perangkat", + "stopCastingTitle": "Hentikan transmisi", + "stopCastingBody": "Apakah kamu ingin menghentikan transmisi?", + "castIPMismatchTitle": "Gagal mentransmisikan album", + "castIPMismatchBody": "Harap pastikan kamu berada pada jaringan yang sama dengan TV-nya.", + "pairingComplete": "Penautan berhasil", + "savingEdits": "Menyimpan edit...", + "autoPair": "Taut otomatis", + "pairWithPin": "Tautkan dengan PIN", + "faceRecognition": "Pengenalan wajah", + "foundFaces": "Wajah yang ditemukan", + "indexingIsPaused": "Proses indeks dijeda, dan akan otomatis dilanjutkan saat perangkat siap.", + "trim": "Pangkas", + "crop": "Potong", + "rotate": "Putar", + "left": "Kiri", + "right": "Kanan", + "whatsNew": "Hal yang baru" +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_it.arb b/mobile/lib/l10n/intl_it.arb index f7116668e6..ac66ecca17 100644 --- a/mobile/lib/l10n/intl_it.arb +++ b/mobile/lib/l10n/intl_it.arb @@ -1,4 +1,5 @@ { + "@@locale ": "en", "enterYourEmailAddress": "Inserisci il tuo indirizzo email", "accountWelcomeBack": "Bentornato!", "email": "Email", @@ -23,7 +24,6 @@ "sendEmail": "Invia email", "deleteRequestSLAText": "La tua richiesta verrà elaborata entro 72 ore.", "deleteEmailRequest": "Invia un'email a account-deletion@ente.io dal tuo indirizzo email registrato.", - "entePhotosPerm": "ente necessita del permesso per preservare le tue foto", "ok": "Ok", "createAccount": "Crea account", "createNewAccount": "Crea un nuovo account", @@ -225,17 +225,14 @@ }, "description": "Number of participants in an album, including the album owner." }, - "collabLinkSectionDescription": "Crea un link per consentire alle persone di aggiungere e visualizzare foto nel tuo album condiviso senza bisogno di un'applicazione o di un account ente. Ottimo per raccogliere foto di un evento.", "collectPhotos": "Raccogli le foto", "collaborativeLink": "Link collaborativo", - "shareWithNonenteUsers": "Condividi con utenti che non hanno un account ente", "createPublicLink": "Crea link pubblico", "sendLink": "Invia link", "copyLink": "Copia link", "linkHasExpired": "Il link è scaduto", "publicLinkEnabled": "Link pubblico abilitato", "shareALink": "Condividi un link", - "sharedAlbumSectionDescription": "Crea album condivisi e collaborativi con altri utenti ente, inclusi utenti su piani gratuiti.", "shareWithPeopleSectionTitle": "{numberOfPeople, plural, =0 {Condividi con persone specifiche} =1 {Condividi con una persona} other {Condividi con {numberOfPeople} persone}}", "@shareWithPeopleSectionTitle": { "placeholders": { @@ -259,12 +256,10 @@ }, "verificationId": "ID di verifica", "verifyEmailID": "Verifica {email}", - "emailNoEnteAccount": "{email} non ha un account su ente.\n\nInvia un invito per condividere foto.", "shareMyVerificationID": "Ecco il mio ID di verifica: {verificationID} per ente.io.", "shareTextConfirmOthersVerificationID": "Hey, puoi confermare che questo è il tuo ID di verifica: {verificationID} su ente.io", "somethingWentWrong": "Qualcosa è andato storto", "sendInvite": "Invita", - "shareTextRecommendUsingEnte": "Scarica ente in modo da poter facilmente condividere foto e video senza perdita di qualità\n\nhttps://ente.io", "done": "Completato", "applyCodeTitle": "Applica codice", "enterCodeDescription": "Inserisci il codice fornito dal tuo amico per richiedere spazio gratuito per entrambi", @@ -281,7 +276,6 @@ "claimMore": "Richiedine di più!", "theyAlsoGetXGb": "Anche loro riceveranno {storageAmountInGB} GB", "freeStorageOnReferralSuccess": "{storageAmountInGB} GB ogni volta che qualcuno si iscrive a un piano a pagamento e applica il tuo codice", - "shareTextReferralCode": "ente referral code: {referralCode} \n\nApplicalo in Impostazioni → Generale → Referral per ottenere {referralStorageInGB} GB gratis dopo la registrazione di un piano a pagamento\n\nhttps://ente.io", "claimFreeStorage": "Richiedi spazio gratuito", "inviteYourFriends": "Invita i tuoi amici", "failedToFetchReferralDetails": "Impossibile recuperare i dettagli. Per favore, riprova più tardi.", @@ -333,7 +327,6 @@ "removeParticipantBody": "{userEmail} verrà rimosso da questo album condiviso\n\nQualsiasi foto aggiunta dall'utente verrà rimossa dall'album", "keepPhotos": "Mantieni foto", "deletePhotos": "Elimina foto", - "inviteToEnte": "Invita su ente", "removePublicLink": "Rimuovi link pubblico", "disableLinkMessage": "Questo rimuoverà il link pubblico per accedere a \"{albumName}\".", "sharing": "Condivisione in corso...", @@ -349,10 +342,7 @@ "videoSmallCase": "video", "photoSmallCase": "foto", "singleFileDeleteHighlight": "Verrà eliminato da tutti gli album.", - "singleFileInBothLocalAndRemote": "Questo {fileType} è sia su ente che sul tuo dispositivo.", - "singleFileInRemoteOnly": "Questo {fileType} verrà eliminato su ente.", "singleFileDeleteFromDevice": "Questo {fileType} verrà eliminato dal tuo dispositivo.", - "deleteFromEnte": "Elimina da ente", "yesDelete": "Sì, elimina", "movedToTrash": "Spostato nel cestino", "deleteFromDevice": "Elimina dal dispositivo", @@ -406,6 +396,11 @@ }, "photoGridSize": "Dimensione griglia foto", "manageDeviceStorage": "Gestisci memoria dispositivo", + "waitingForWifi": "In attesa del WiFi...", + "status": "Stato", + "indexedItems": "Elementi indicizzati", + "pendingItems": "Elementi in sospeso", + "clearIndexes": "Cancella indici", "selectFoldersForBackup": "Seleziona cartelle per il backup", "selectedFoldersWillBeEncryptedAndBackedUp": "Le cartelle selezionate verranno crittografate e salvate su ente", "unselectAll": "Deseleziona tutto", @@ -435,7 +430,6 @@ "backupOverMobileData": "Backup su dati mobili", "backupVideos": "Backup dei video", "disableAutoLock": "Disabilita blocco automatico", - "deviceLockExplanation": "Disabilita il blocco schermo del dispositivo quando ente è in primo piano e c'è un backup in corso. Questo normalmente non è necessario, ma può aiutare durante grossi caricamenti e le importazioni iniziali di grandi librerie si completano più velocemente.", "about": "Info", "weAreOpenSource": "Siamo open source!", "privacy": "Privacy", @@ -455,7 +449,6 @@ "authToInitiateAccountDeletion": "Autenticati per avviare l'eliminazione dell'account", "areYouSureYouWantToLogout": "Sei sicuro di volerti disconnettere?", "yesLogout": "Sì, disconnetti", - "aNewVersionOfEnteIsAvailable": "Una nuova versione di ente è disponibile.", "update": "Aggiorna", "installManually": "Installa manualmente", "criticalUpdateAvailable": "Un aggiornamento importante è disponibile", @@ -543,11 +536,10 @@ "systemTheme": "Sistema", "freeTrial": "Prova gratuita", "selectYourPlan": "Seleziona un piano", - "enteSubscriptionPitch": "ente conserva i tuoi ricordi, in modo che siano sempre a disposizione, anche se perdi il dispositivo.", "enteSubscriptionShareWithFamily": "Aggiungi la tua famiglia al tuo piano.", "currentUsageIs": "Spazio attualmente utilizzato ", "@currentUsageIs": { - "description": "This text is followed by storage usaged", + "description": "This text is followed by storage usage", "examples": { "0": "Current usage is 1.2 GB" }, @@ -557,7 +549,6 @@ "renewsOn": "Si rinnova il {endDate}", "freeTrialValidTill": "La prova gratuita termina il {endDate}", "validTill": "Valido fino al {endDate}", - "playStoreFreeTrialValidTill": "Prova gratuita valida fino al {endDate}.\nPuoi scegliere un piano a pagamento in seguito.", "subWillBeCancelledOn": "L'abbonamento verrà cancellato il {endDate}", "subscription": "Abbonamento", "paymentDetails": "Dettagli di Pagamento", @@ -608,7 +599,6 @@ "appleId": "Apple ID", "playstoreSubscription": "Abbonamento su PlayStore", "appstoreSubscription": "abbonamento AppStore", - "subAlreadyLinkedErrMessage": "Il tuo {id} è già collegato ad un altro account ente.\nSe desideri utilizzare il tuo {id} con questo account, contatta il nostro supporto''", "visitWebToManage": "Visita web.ente.io per gestire il tuo abbonamento", "couldNotUpdateSubscription": "Impossibile aggiornare l'abbonamento", "pleaseContactSupportAndWeWillBeHappyToHelp": "Contatta support@ente.io e saremo felici di aiutarti!", @@ -629,7 +619,6 @@ "thankYou": "Grazie", "failedToVerifyPaymentStatus": "Impossibile verificare lo stato del pagamento", "pleaseWaitForSometimeBeforeRetrying": "Riprova tra qualche minuto", - "paymentFailedWithReason": "Purtroppo il tuo pagamento non è riuscito a causa di {reason}", "youAreOnAFamilyPlan": "Sei un utente con piano famiglia!", "contactFamilyAdmin": "Contatta {familyAdminEmail} per gestire il tuo abbonamento", "leaveFamily": "Abbandona il piano famiglia", @@ -653,9 +642,7 @@ "everywhere": "ovunque", "androidIosWebDesktop": "Android, iOS, Web, Desktop", "mobileWebDesktop": "Mobile, Web, Desktop", - "newToEnte": "Nuovo utente", "pleaseLoginAgain": "Effettua nuovamente l'accesso", - "devAccountChanged": "L'account sviluppatore che utilizziamo per pubblicare ente su App Store è cambiato. Per questo motivo dovrai effettuare nuovamente il login.\n\nCi dispiace per il disagio, ma era inevitabile.", "yourSubscriptionHasExpired": "Il tuo abbonamento è scaduto", "storageLimitExceeded": "Limite d'archiviazione superato", "upgrade": "Acquista altro spazio", @@ -666,12 +653,10 @@ }, "backupFailed": "Backup fallito", "couldNotBackUpTryLater": "Impossibile eseguire il backup dei tuoi dati.\nRiproveremo più tardi.", - "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": "ente può criptare e preservare i file solo se concedi l'accesso alle foto e ai video", "pleaseGrantPermissions": "Concedi i permessi", "grantPermission": "Concedi il permesso", "privateSharing": "Condivisioni private", "shareOnlyWithThePeopleYouWant": "Condividi solo con le persone che vuoi", - "usePublicLinksForPeopleNotOnEnte": "Usa link pubblici per persone non registrate su ente", "allowPeopleToAddPhotos": "Permetti alle persone di aggiungere foto", "shareAnAlbumNow": "Condividi un album", "collectEventPhotos": "Raccogli le foto di un evento", @@ -683,7 +668,7 @@ }, "onDevice": "Sul dispositivo", "@onEnte": { - "description": "The text displayed above albums backed up to ente", + "description": "The text displayed above albums backed up to Ente", "type": "text" }, "onEnte": "Su ente", @@ -708,13 +693,11 @@ "unhide": "Mostra", "unarchive": "Rimuovi dall'archivio", "favorite": "Preferito", - "removeFromFavorite": "Rimuovi dai preferiti", "shareLink": "Condividi link", "createCollage": "Crea un collage", "saveCollage": "Salva il collage", "collageSaved": "Collage salvato nella galleria", "collageLayout": "Disposizione", - "addToEnte": "Aggiungi su ente", "addToAlbum": "Aggiungi all'album", "delete": "Cancella", "hide": "Nascondi", @@ -779,10 +762,7 @@ "photosAddedByYouWillBeRemovedFromTheAlbum": "Le foto aggiunte da te verranno rimosse dall'album", "youveNoFilesInThisAlbumThatCanBeDeleted": "Non hai file in questo album che possono essere eliminati", "youDontHaveAnyArchivedItems": "Non hai nulla di archiviato.", - "ignoredFolderUploadReason": "Alcuni file in questo album vengono ignorati dal caricamento perché erano stati precedentemente cancellati da ente.", "resetIgnoredFiles": "Ripristina i file ignorati", - "deviceFilesAutoUploading": "I file aggiunti in questa cartella del dispositivo verranno automaticamente caricati su ente.", - "turnOnBackupForAutoUpload": "Attiva il backup per caricare automaticamente i file aggiunti in questa cartella del dispositivo su ente.", "noHiddenPhotosOrVideos": "Nessuna foto o video nascosti", "toHideAPhotoOrVideo": "Per nascondere una foto o un video", "openTheItem": "• Apri la foto o il video", @@ -820,7 +800,6 @@ "clubByFileName": "Unisci per nome file", "count": "Conteggio", "totalSize": "Dimensioni totali", - "time": "Ora", "longpressOnAnItemToViewInFullscreen": "Premi a lungo su un elemento per visualizzarlo a schermo intero", "decryptingVideo": "Decifratura video...", "authToViewYourMemories": "Autenticati per visualizzare le tue foto", @@ -897,10 +876,10 @@ "description": "Text to tell user how many memories have been preserved", "placeholders": { "completed": { - "type": "int" + "type": "String" }, "total": { - "type": "int" + "type": "String" } } }, @@ -911,7 +890,6 @@ "renameFile": "Rinomina file", "enterFileName": "Inserisci un nome per il file", "filesDeleted": "File eliminati", - "selectedFilesAreNotOnEnte": "I file selezionati non sono su ente", "thisActionCannotBeUndone": "Questa azione non può essere annullata", "emptyTrash": "Vuoi svuotare il cestino?", "permDeleteWarning": "Tutti gli elementi nel cestino verranno eliminati definitivamente\n\nQuesta azione non può essere annullata", @@ -920,12 +898,13 @@ "permanentlyDeleteFromDevice": "Eliminare definitivamente dal dispositivo?", "someOfTheFilesYouAreTryingToDeleteAre": "Alcuni dei file che si sta tentando di eliminare sono disponibili solo sul dispositivo e non possono essere recuperati se cancellati", "theyWillBeDeletedFromAllAlbums": "Verranno eliminati da tutti gli album.", - "someItemsAreInBothEnteAndYourDevice": "Alcuni elementi sono sia su ente che sul tuo dispositivo.", "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": "Gli elementi selezionati verranno eliminati da tutti gli album e spostati nel cestino.", "theseItemsWillBeDeletedFromYourDevice": "Questi file verranno eliminati dal tuo dispositivo.", "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Sembra che qualcosa sia andato storto. Riprova tra un po'. Se l'errore persiste, contatta il nostro team di supporto.", "error": "Errore", "tempErrorContactSupportIfPersists": "Sembra che qualcosa sia andato storto. Riprova tra un po'. Se l'errore persiste, contatta il nostro team di supporto.", + "networkHostLookUpErr": "Impossibile connettersi a Ente, controlla le impostazioni di rete e contatta l'assistenza se l'errore persiste.", + "networkConnectionRefusedErr": "Impossibile connettersi a Ente, riprova tra un po' di tempo. Se l'errore persiste, contatta l'assistenza.", "cachedData": "Dati nella cache", "clearCaches": "Svuota cache", "remoteImages": "Immagini remote", @@ -954,12 +933,16 @@ "loadMessage7": "Le nostre app per smartphone vengono eseguite in background per crittografare e eseguire il backup di qualsiasi nuova foto o video", "loadMessage8": "web.ente.io ha un uploader intuitivo", "loadMessage9": "Usiamo Xchacha20Poly1305 per crittografare in modo sicuro i tuoi dati", + "location": "Luogo", + "searchDatesEmptySection": "Ricerca per data, mese o anno", + "searchLocationEmptySection": "Raggruppa foto scattate entro un certo raggio da una foto", + "searchPeopleEmptySection": "Invita persone e vedrai qui tutte le foto condivise da loro", + "searchAlbumsEmptySection": "Album", "language": "Lingua", "selectLanguage": "Seleziona una lingua", "locationName": "Nome della località", "addLocation": "Aggiungi luogo", "groupNearbyPhotos": "Raggruppa foto nelle vicinanze", - "location": "Luogo", "kiloMeterUnit": "km", "addLocationButton": "Aggiungi", "radius": "Raggio", @@ -1003,7 +986,6 @@ "@storageUsageInfo": { "description": "Example: 1.2 GB of 2 GB used or 100 GB or 2TB used" }, - "availableStorageSpace": "{freeAmount} {storageUnit} liberi", "appVersion": "Versione: {versionValue}", "verifyIDLabel": "Verifica", "fileInfoAddDescHint": "Aggiungi descrizione...", @@ -1014,7 +996,6 @@ }, "setRadius": "Imposta raggio", "familyPlanPortalTitle": "Famiglia", - "familyPlanOverview": "Aggiungi 5 membri della famiglia al tuo piano esistente senza pagare extra.\n\nOgni membro ottiene il proprio spazio privato e non può vedere i file dell'altro a meno che non siano condivisi.\n\nI piani familiari sono disponibili per i clienti che hanno un abbonamento ente a pagamento.\n\nIscriviti ora per iniziare!", "androidBiometricHint": "Verifica l'identità", "@androidBiometricHint": { "description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters." @@ -1092,7 +1073,6 @@ "noAlbumsSharedByYouYet": "Ancora nessun album condiviso da te", "sharedWithYou": "Condivise con te", "sharedByYou": "Condivise da te", - "inviteYourFriendsToEnte": "Invita i tuoi amici a ente", "failedToDownloadVideo": "Download del video non riuscito", "hiding": "Nascondendo...", "unhiding": "Rimuovendo dal nascondiglio...", @@ -1101,71 +1081,27 @@ "crashReporting": "Segnalazione di crash", "addToHiddenAlbum": "Aggiungi ad album nascosto", "moveToHiddenAlbum": "Sposta in album nascosto", - "deleteConfirmDialogBody": "Questo account è collegato ad altre app di ente, se ne utilizzi.\\n\\nI tuoi dati caricati, su tutte le app di ente, saranno pianificati per la cancellazione e il tuo account verrà eliminato definitivamente.", "hearUsWhereTitle": "Come hai sentito parlare di Ente? (opzionale)", "hearUsExplanation": "Non teniamo traccia del numero di installazioni dell'app. Sarebbe utile se ci dicesse dove ci ha trovato!", "viewAddOnButton": "Visualizza componenti aggiuntivi", "addOns": "Componenti aggiuntivi", "addOnPageSubtitle": "Dettagli dei componenti aggiuntivi", - "yourMap": "Your map", - "modifyYourQueryOrTrySearchingFor": "Modify your query, or try searching for", - "contacts": "Contacts", - "editLocation": "Edit location", - "selectALocation": "Select a location", - "selectALocationFirst": "Select a location first", - "changeLocationOfSelectedItems": "Change location of selected items?", - "editsToLocationWillOnlyBeSeenWithinEnte": "Edits to location will only be seen within Ente", - "joinDiscord": "Join Discord", - "locations": "Locations", - "descriptions": "Descriptions", - "addViewers": "{count, plural, zero {Add viewer} one {Add viewer} other {Add viewers}}", - "addCollaborators": "{count, plural, zero {Add collaborator} one {Add collaborator} other {Add collaborators}}", - "longPressAnEmailToVerifyEndToEndEncryption": "Long press an email to verify end to end encryption.", - "createCollaborativeLink": "Create collaborative link", - "search": "Search", - "enterPersonName": "Enter person name", - "removePersonLabel": "Remove person label", - "faceRecognition": "Face recognition", - "faceRecognitionIndexingDescription": "Please note that this will result in a higher bandwidth and battery usage until all items are indexed.", - "foundFaces": "Found faces", - "clusteringProgress": "Clustering progress", - "indexingIsPaused": "Indexing is paused, will automatically resume when device is ready", - "reenterPassword": "Re-enter password", - "mlFunctions": "ML functions", - "reenterPin": "Re-enter PIN", - "deviceLock": "Device lock", - "pinLock": "PIN lock", - "next": "Next", - "setNewPassword": "Set new password", - "enterPin": "Enter PIN", - "setNewPin": "Set new PIN", - "appLock": "App lock", - "noSystemLockFound": "No system lock found", - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "To enable app lock, please setup device passcode or screen lock in your system settings.", - "tapToUnlock": "Tap to unlock", - "tooManyIncorrectAttempts": "Too many incorrect attempts", - "appLockDescription": "Choose between your device\\'s default lock screen and a custom lock screen with a PIN or password.", - "swipeLockEnablePreSteps": "To enable swipe lock, please setup device passcode or screen lock in your system settings.", - "autoLock": "Auto lock", - "immediately": "Immediately", - "autoLockFeatureDescription": "Time after which the app locks after being put in the background", - "hideContent": "Hide content", - "hideContentDescriptionAndroid": "Hides app content in the app switcher and disables screenshots", - "hideContentDescriptionIos": "Hides app content in the app switcher", - "passwordStrengthInfo": "Password strength is calculated considering the length of the password, used characters, and whether or not the password appears in the top 10,000 most used passwords", - "noQuickLinksSelected": "No quick links selected", - "pleaseSelectQuickLinksToRemove": "Please select quick links to remove", - "removePublicLinks": "Remove public links", - "thisWillRemovePublicLinksOfAllSelectedQuickLinks": "This will remove public links of all selected quick links.", - "guestView": "Guest view", - "guestViewEnablePreSteps": "To enable guest view, please setup device passcode or screen lock in your system settings.", - "cl_guest_view_title": "Vista Ospite", - "cl_guest_view_description": "Mostri le foto a un amico? Non preoccuparti che scorrano troppo lontano. La vista ospite bloccherà le foto che selezioni.", - "cl_guest_view_call_to_action": "Seleziona le foto e prova la \"Vista Ospite\".", - "cl_panorama_viewer_title": "Visualizzatore Panoramico", - "cl_panorama_viewer_description": "Abbiamo aggiunto il supporto per visualizzare foto panoramiche con viste a 360 gradi. L'esperienza è immersiva con la navigazione basata sul movimento!", - "cl_video_player_title": "Lettore Video", - "cl_video_player_description": "Presentiamo un nuovo lettore video, con controlli di riproduzione migliorati e supporto per video HDR.", - "appLockDescriptions": "Choose between your device's default lock screen and a custom lock screen with a PIN or password.", - "authToViewPasskey": "Please authenticate to view your passkey" + "searchHint3": "Album, nomi di file e tipi", + "searchHint4": "Luogo", + "addNew": "Aggiungi nuovo", + "@addNew": { + "description": "Text to add a new item (location tag, album, caption etc)" + }, + "contacts": "Contatti", + "noInternetConnection": "Nessuna connessione internet", + "pleaseCheckYourInternetConnectionAndTryAgain": "Si prega di verificare la propria connessione Internet e riprovare.", + "signOutFromOtherDevices": "Esci dagli altri dispositivi", + "signOutOtherBody": "Se pensi che qualcuno possa conoscere la tua password, puoi forzare tutti gli altri dispositivi che usano il tuo account ad uscire.", + "signOutOtherDevices": "Esci dagli altri dispositivi", + "doNotSignOut": "Non uscire", + "editLocation": "Modifica luogo", + "selectALocation": "Seleziona un luogo", + "selectALocationFirst": "Scegli prima una posizione", + "changeLocationOfSelectedItems": "Cambiare la posizione degli elementi selezionati?", + "editsToLocationWillOnlyBeSeenWithinEnte": "Le modifiche alla posizione saranno visibili solo all'interno di Ente" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ja.arb b/mobile/lib/l10n/intl_ja.arb new file mode 100644 index 0000000000..c8494661c6 --- /dev/null +++ b/mobile/lib/l10n/intl_ja.arb @@ -0,0 +1,3 @@ +{ + "@@locale ": "en" +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_km.arb b/mobile/lib/l10n/intl_km.arb new file mode 100644 index 0000000000..c8494661c6 --- /dev/null +++ b/mobile/lib/l10n/intl_km.arb @@ -0,0 +1,3 @@ +{ + "@@locale ": "en" +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ko.arb b/mobile/lib/l10n/intl_ko.arb index 49563ff49d..06c81195f7 100644 --- a/mobile/lib/l10n/intl_ko.arb +++ b/mobile/lib/l10n/intl_ko.arb @@ -1,61 +1,16 @@ { - "addToHiddenAlbum": "Add to hidden album", - "moveToHiddenAlbum": "Move to hidden album", - "fileTypes": "File types", - "deleteConfirmDialogBody": "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted.", - "yourMap": "Your map", - "modifyYourQueryOrTrySearchingFor": "Modify your query, or try searching for", - "contacts": "Contacts", - "editLocation": "Edit location", - "selectALocation": "Select a location", - "selectALocationFirst": "Select a location first", - "changeLocationOfSelectedItems": "Change location of selected items?", - "editsToLocationWillOnlyBeSeenWithinEnte": "Edits to location will only be seen within Ente", - "joinDiscord": "Join Discord", - "locations": "Locations", - "descriptions": "Descriptions", - "addViewers": "{count, plural, zero {Add viewer} one {Add viewer} other {Add viewers}}", - "addCollaborators": "{count, plural, zero {Add collaborator} one {Add collaborator} other {Add collaborators}}", - "longPressAnEmailToVerifyEndToEndEncryption": "Long press an email to verify end to end encryption.", - "createCollaborativeLink": "Create collaborative link", - "search": "Search", - "enterPersonName": "Enter person name", - "removePersonLabel": "Remove person label", - "faceRecognition": "Face recognition", - "faceRecognitionIndexingDescription": "Please note that this will result in a higher bandwidth and battery usage until all items are indexed.", - "foundFaces": "Found faces", - "clusteringProgress": "Clustering progress", - "indexingIsPaused": "Indexing is paused, will automatically resume when device is ready", - "reenterPassword": "Re-enter password", - "mlFunctions": "ML functions", - "reenterPin": "Re-enter PIN", - "deviceLock": "Device lock", - "pinLock": "PIN lock", - "passwordLock": "Password lock", - "next": "Next", - "setNewPassword": "Set new password", - "enterPin": "Enter PIN", - "setNewPin": "Set new PIN", - "appLock": "App lock", - "noSystemLockFound": "No system lock found", - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "To enable app lock, please setup device passcode or screen lock in your system settings.", - "tapToUnlock": "Tap to unlock", - "tooManyIncorrectAttempts": "Too many incorrect attempts", - "appLockDescription": "Choose between your device\\'s default lock screen and a custom lock screen with a PIN or password.", - "swipeLockEnablePreSteps": "To enable swipe lock, please setup device passcode or screen lock in your system settings.", - "autoLock": "Auto lock", - "immediately": "Immediately", - "autoLockFeatureDescription": "Time after which the app locks after being put in the background", - "hideContent": "Hide content", - "hideContentDescriptionAndroid": "Hides app content in the app switcher and disables screenshots", - "hideContentDescriptionIos": "Hides app content in the app switcher", - "passwordStrengthInfo": "Password strength is calculated considering the length of the password, used characters, and whether or not the password appears in the top 10,000 most used passwords", - "noQuickLinksSelected": "No quick links selected", - "pleaseSelectQuickLinksToRemove": "Please select quick links to remove", - "removePublicLinks": "Remove public links", - "thisWillRemovePublicLinksOfAllSelectedQuickLinks": "This will remove public links of all selected quick links.", - "guestView": "Guest view", - "guestViewEnablePreSteps": "To enable guest view, please setup device passcode or screen lock in your system settings.", - "appLockDescriptions": "Choose between your device's default lock screen and a custom lock screen with a PIN or password.", - "authToViewPasskey": "Please authenticate to view your passkey" + "@@locale ": "en", + "enterYourEmailAddress": "이메일을 입력하세요", + "accountWelcomeBack": "다시 오신 것을 환영합니다!", + "email": "이메일", + "cancel": "닫기", + "verify": "인증", + "invalidEmailAddress": "잘못된 이메일 주소", + "enterValidEmail": "올바른 이메일 주소를 입력하세요.", + "deleteAccount": "계정 삭제", + "askDeleteReason": "계정을 삭제하는 가장 큰 이유가 무엇인가요?", + "feedback": "피드백", + "confirmAccountDeletion": "계정 삭제 확인", + "deleteAccountPermanentlyButton": "계정을 영구적으로 삭제", + "yourAccountHasBeenDeleted": "계정이 삭제되었습니다." } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_nl.arb b/mobile/lib/l10n/intl_nl.arb index 8acd3f01cb..62dc45e844 100644 --- a/mobile/lib/l10n/intl_nl.arb +++ b/mobile/lib/l10n/intl_nl.arb @@ -273,6 +273,11 @@ "failedToApplyCode": "Code toepassen mislukt", "enterReferralCode": "Voer verwijzingscode in", "codeAppliedPageTitle": "Code toegepast", + "changeYourReferralCode": "Wijzig uw verwijzingscode", + "change": "Wijzigen", + "unavailableReferralCode": "Deze code is helaas niet beschikbaar.", + "codeChangeLimitReached": "Sorry, u heeft de limiet van het aantal codewijzigingen bereikt.", + "onlyFamilyAdminCanChangeCode": "Neem contact op met {familyAdminEmail} om uw code te wijzigen.", "storageInGB": "{storageAmountInGB} GB", "claimed": "Geclaimd", "@claimed": { @@ -409,8 +414,13 @@ "photoGridSize": "Foto raster grootte", "manageDeviceStorage": "Apparaatopslag beheren", "machineLearning": "Machine Learning", + "mlConsent": "Schakel machine learning in", + "mlConsentTitle": "Machine learning inschakelen?", + "mlConsentDescription": "Als u machine learning inschakelt, zal Ente informatie zoals gezichtsgeometrie uit bestanden extraheren, inclusief degenen die met u gedeeld worden.\n\nDit gebeurt op uw apparaat, en alle gegenereerde biometrische informatie zal end-to-end versleuteld worden.", + "mlConsentPrivacy": "Klik hier voor meer details over deze functie in ons privacybeleid.", + "mlConsentConfirmation": "Ik begrijp het, en wil machine learning inschakelen", "magicSearch": "Magische zoekfunctie", - "mlIndexingDescription": "Houd er rekening mee dat dit zal resulteren in een hoger internet- en batterijverbruik totdat alle items zijn geïndexeerd.", + "mlIndexingDescription": "Houd er rekening mee dat machine learning zal leiden tot hoger bandbreedte- en batterijgebruik totdat alle items geïndexeerd zijn. Overweeg het gebruik van de desktop app voor snellere indexering. Alle resultaten worden automatisch gesynchroniseerd.", "loadingModel": "Modellen downloaden...", "waitingForWifi": "Wachten op WiFi...", "status": "Status", @@ -486,7 +496,6 @@ "removeDuplicates": "Duplicaten verwijderen", "removeDuplicatesDesc": "Controleer en verwijder bestanden die exacte kopieën zijn.", "viewLargeFiles": "Grote bestanden", - "viewLargeFilesDesc": "Bekijk bestanden die de meeste opslagruimte verbruiken", "noDuplicates": "✨ Geen duplicaten", "youveNoDuplicateFilesThatCanBeCleared": "Je hebt geen dubbele bestanden die kunnen worden gewist", "success": "Succes", @@ -740,7 +749,7 @@ "unhide": "Zichtbaar maken", "unarchive": "Uit archief halen", "favorite": "Toevoegen aan favorieten", - "removeFromFavorite": "Verwijderen uit favorieten", + "removeFromFavorite": "Verwijder van favorieten", "shareLink": "Link delen", "createCollage": "Creëer collage", "saveCollage": "Sla collage op", @@ -1143,6 +1152,7 @@ "successfullyHid": "Succesvol verborgen", "successfullyUnhid": "Met succes zichtbaar gemaakt", "crashReporting": "Crash rapportering", + "resumableUploads": "Hervatbare uploads", "addToHiddenAlbum": "Toevoegen aan verborgen album", "moveToHiddenAlbum": "Verplaatsen naar verborgen album", "fileTypes": "Bestandstype", @@ -1238,28 +1248,13 @@ "castIPMismatchTitle": "Album casten mislukt", "castIPMismatchBody": "Zorg ervoor dat je op hetzelfde netwerk zit als de tv.", "pairingComplete": "Koppeling voltooid", - "faceRecognition": "Gezichtsherkenning", - "faceRecognitionIndexingDescription": "Please note that this will result in a higher bandwidth and battery usage until all items are indexed.", - "foundFaces": "Gezichten gevonden", - "clusteringProgress": "Voortgang clusteren", - "indexingIsPaused": "Indexeren is gepauzeerd. Het zal automatisch hervatten wanneer het apparaat klaar is.", - "reenterPassword": "Wachtwoord opnieuw invoeren", - "reenterPin": "PIN opnieuw invoeren", - "deviceLock": "Apparaat vergrendeld", - "pinLock": "PIN vergrendeling", - "next": "Volgende", - "setNewPassword": "Nieuw wachtwoord instellen", - "enterPin": "PIN invoeren", - "setNewPin": "Nieuwe PIN instellen", - "appLock": "App-vergrendeling", - "noSystemLockFound": "Geen systeemvergrendeling gevonden", - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Om vergrendelscherm in te schakelen, moet u een toegangscode of schermvergrendeling instellen in uw systeeminstellingen.", - "tapToUnlock": "Tik om te ontgrendelen", - "tooManyIncorrectAttempts": "Te veel onjuiste pogingen", - "mlFunctions": "ML functions", "savingEdits": "Bewerken opslaan...", "autoPair": "Automatisch koppelen", "pairWithPin": "Koppelen met PIN", + "faceRecognition": "Gezichtsherkenning", + "foundFaces": "Gezichten gevonden", + "clusteringProgress": "Voortgang clusteren", + "indexingIsPaused": "Indexeren is gepauzeerd. Het zal automatisch hervatten wanneer het apparaat klaar is.", "trim": "Knippen", "crop": "Bijsnijden", "rotate": "Roteren", @@ -1278,10 +1273,25 @@ } } }, + "enable": "Inschakelen", + "enabled": "Ingeschakeld", + "moreDetails": "Meer details", + "enableMLIndexingDesc": "Ente ondersteunt on-device machine learning voor gezichtsherkenning, magisch zoeken en andere geavanceerde zoekfuncties", + "magicSearchHint": "Magisch zoeken maakt het mogelijk om foto's op hun inhoud worden gezocht, bijvoorbeeld \"bloem\", \"rode auto\", \"identiteitsdocumenten\"", "panorama": "Panorama", + "reenterPassword": "Wachtwoord opnieuw invoeren", + "reenterPin": "PIN opnieuw invoeren", + "deviceLock": "Apparaat vergrendeld", + "pinLock": "PIN vergrendeling", + "next": "Volgende", + "setNewPassword": "Nieuw wachtwoord instellen", + "enterPin": "PIN invoeren", + "setNewPin": "Nieuwe PIN instellen", + "appLock": "App-vergrendeling", + "noSystemLockFound": "Geen systeemvergrendeling gevonden", + "tapToUnlock": "Tik om te ontgrendelen", + "tooManyIncorrectAttempts": "Te veel onjuiste pogingen", "videoInfo": "Video-info", - "appLockDescription": "Kies tussen het standaard vergrendelingsscherm van uw apparaat en een aangepast vergrendelingsscherm met een pincode of wachtwoord.", - "swipeLockEnablePreSteps": "Om swipe-vergrendeling in te schakelen, stelt u de toegangscode van het apparaat of schermvergrendeling in uw systeeminstellingen in.", "autoLock": "Automatische vergrendeling", "immediately": "Onmiddellijk", "autoLockFeatureDescription": "Tijd waarna de app wordt vergrendeld wanneer deze in achtergrond-modus is gezet", @@ -1289,19 +1299,19 @@ "hideContentDescriptionAndroid": "Verbergt app-inhoud in de app-schakelaar en schakelt schermopnamen uit", "hideContentDescriptionIos": "Verbergt de inhoud van de app in de app-schakelaar", "passwordStrengthInfo": "De wachtwoordsterkte wordt berekend aan de hand van de lengte van het wachtwoord, de gebruikte tekens en of het wachtwoord al dan niet in de top 10.000 van meest gebruikte wachtwoorden staat", - "noQuickLinksSelected": "No quick links selected", - "pleaseSelectQuickLinksToRemove": "Please select quick links to remove", - "removePublicLinks": "Remove public links", - "thisWillRemovePublicLinksOfAllSelectedQuickLinks": "This will remove public links of all selected quick links.", - "guestView": "Guest view", - "guestViewEnablePreSteps": "To enable guest view, please setup device passcode or screen lock in your system settings.", + "noQuickLinksSelected": "Geen snelle links geselecteerd", + "pleaseSelectQuickLinksToRemove": "Selecteer snelle links om te verwijderen", + "removePublicLinks": "Verwijder publieke link", + "thisWillRemovePublicLinksOfAllSelectedQuickLinks": "Hiermee worden openbare links van alle geselecteerde snelle links verwijderd.", + "guestView": "Gasten weergave", + "guestViewEnablePreSteps": "Om gasten weergave in te schakelen, moet u een toegangscode of schermvergrendeling instellen in uw systeeminstellingen.", "cl_guest_view_title": "Gastweergave", - "cl_guest_view_description": "Geef je je telefoon aan een vriend om foto's te laten zien? Maak je geen zorgen dat ze te ver swipen. Gastweergave vergrendelt ze op de foto's die je selecteert.", - "cl_guest_view_call_to_action": "Selecteer foto's en bekijk de \"Gastweergave\".", - "cl_panorama_viewer_title": "Panorama Viewer", - "cl_panorama_viewer_description": "We hebben ondersteuning toegevoegd voor het bekijken van panoramafoto's met 360 graden weergaven. De ervaring is meeslepend met bewegingsgestuurde navigatie!", + "cl_guest_view_description": "Geeft u een vriend uw telefoon om foto's te laten zien? Maakt u zich geen zorgen dat ze te ver swipen. Gastweergave zal diegene beperken tot de foto's die u selecteert.", + "cl_guest_view_call_to_action": "Selecteer foto's en bekijk \"Gastweergave\".", + "cl_panorama_viewer_title": "Panoramakijker", + "cl_panorama_viewer_description": "We hebben ondersteuning toegevoegd voor het bekijken van panoramafoto's met 360 graden weergave. De ervaring is immersief met op beweging gebaseerde navigatie!", "cl_video_player_title": "Videospeler", - "cl_video_player_description": "We introduceren een nieuwe videospeler met betere afspeelbediening en ondersteuning voor HDR-video's.", - "appLockDescriptions": "Choose between your device's default lock screen and a custom lock screen with a PIN or password.", - "authToViewPasskey": "Please authenticate to view your passkey" + "cl_video_player_description": "Een verfrissende nieuwe videospeler, met betere afspeelknoppen en ondersteuning voor HDR-video's.", + "appLockDescriptions": "Kies tussen het standaard vergrendelscherm van uw apparaat en een aangepast vergrendelscherm met een pincode of wachtwoord.", + "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Om appvergrendeling in te schakelen, moet u een toegangscode of schermvergrendeling instellen in uw systeeminstellingen." } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_no.arb b/mobile/lib/l10n/intl_no.arb index f22ec4f7d0..9bf690cd30 100644 --- a/mobile/lib/l10n/intl_no.arb +++ b/mobile/lib/l10n/intl_no.arb @@ -1,4 +1,5 @@ { + "@@locale ": "en", "enterYourEmailAddress": "Skriv inn e-postadressen din", "accountWelcomeBack": "Velkommen tilbake!", "email": "E-post", @@ -13,63 +14,364 @@ "kindlyHelpUsWithThisInformation": "Vær vennlig og hjelp oss med denne informasjonen", "confirmDeletePrompt": "Ja, jeg ønsker å slette denne kontoen og all dataen dens permanent.", "confirmAccountDeletion": "Bekreft sletting av konto", - "addToHiddenAlbum": "Add to hidden album", - "moveToHiddenAlbum": "Move to hidden album", - "fileTypes": "File types", - "deleteConfirmDialogBody": "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted.", - "yourMap": "Your map", - "modifyYourQueryOrTrySearchingFor": "Modify your query, or try searching for", - "contacts": "Contacts", - "editLocation": "Edit location", - "selectALocation": "Select a location", - "selectALocationFirst": "Select a location first", - "changeLocationOfSelectedItems": "Change location of selected items?", - "editsToLocationWillOnlyBeSeenWithinEnte": "Edits to location will only be seen within Ente", - "joinDiscord": "Join Discord", - "locations": "Locations", - "descriptions": "Descriptions", - "addViewers": "{count, plural, zero {Add viewer} one {Add viewer} other {Add viewers}}", - "addCollaborators": "{count, plural, zero {Add collaborator} one {Add collaborator} other {Add collaborators}}", - "longPressAnEmailToVerifyEndToEndEncryption": "Long press an email to verify end to end encryption.", - "createCollaborativeLink": "Create collaborative link", - "search": "Search", - "enterPersonName": "Enter person name", - "removePersonLabel": "Remove person label", - "faceRecognition": "Face recognition", - "faceRecognitionIndexingDescription": "Please note that this will result in a higher bandwidth and battery usage until all items are indexed.", - "foundFaces": "Found faces", - "clusteringProgress": "Clustering progress", - "indexingIsPaused": "Indexing is paused, will automatically resume when device is ready", - "reenterPassword": "Re-enter password", - "mlFunctions": "ML functions", - "reenterPin": "Re-enter PIN", - "deviceLock": "Device lock", - "pinLock": "PIN lock", - "passwordLock": "Password lock", - "next": "Next", - "setNewPassword": "Set new password", - "enterPin": "Enter PIN", - "setNewPin": "Set new PIN", - "appLock": "App lock", - "noSystemLockFound": "No system lock found", - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "To enable app lock, please setup device passcode or screen lock in your system settings.", - "tapToUnlock": "Tap to unlock", - "tooManyIncorrectAttempts": "Too many incorrect attempts", - "appLockDescription": "Choose between your device\\'s default lock screen and a custom lock screen with a PIN or password.", - "swipeLockEnablePreSteps": "To enable swipe lock, please setup device passcode or screen lock in your system settings.", - "autoLock": "Auto lock", - "immediately": "Immediately", - "autoLockFeatureDescription": "Time after which the app locks after being put in the background", - "hideContent": "Hide content", - "hideContentDescriptionAndroid": "Hides app content in the app switcher and disables screenshots", - "hideContentDescriptionIos": "Hides app content in the app switcher", - "passwordStrengthInfo": "Password strength is calculated considering the length of the password, used characters, and whether or not the password appears in the top 10,000 most used passwords", - "noQuickLinksSelected": "No quick links selected", - "pleaseSelectQuickLinksToRemove": "Please select quick links to remove", - "removePublicLinks": "Remove public links", - "thisWillRemovePublicLinksOfAllSelectedQuickLinks": "This will remove public links of all selected quick links.", - "guestView": "Guest view", - "guestViewEnablePreSteps": "To enable guest view, please setup device passcode or screen lock in your system settings.", - "appLockDescriptions": "Choose between your device's default lock screen and a custom lock screen with a PIN or password.", - "authToViewPasskey": "Please authenticate to view your passkey" + "deleteAccountPermanentlyButton": "Slett bruker for altid", + "yourAccountHasBeenDeleted": "Brukeren din har blitt slettet", + "selectReason": "Velg grunn", + "deleteReason1": "Det mangler en hovedfunksjon jeg trenger", + "deleteReason2": "Appen, eller en bestemt funksjon, fungerer ikke slik jeg tror den skal", + "deleteReason3": "Jeg fant en annen tjeneste jeg liker bedre", + "deleteReason4": "Grunnen min er ikke listet", + "sendEmail": "Send e-post", + "deleteRequestSLAText": "Forespørselen din vil bli behandlet innen 72 timer.", + "deleteEmailRequest": "Vennligst send en e-post til account-deletion@ente.io fra din registrerte e-postadresse.", + "entePhotosPerm": "Ente trenger tillatelse for å bevare bildene dine", + "ok": "Ok", + "createAccount": "Opprett konto", + "createNewAccount": "Opprett ny konto", + "password": "Passord", + "confirmPassword": "Bekreft passordet", + "activeSessions": "Aktive økter", + "oops": "Oisann", + "somethingWentWrongPleaseTryAgain": "Noe gikk galt. Vennligst prøv igjen", + "thisWillLogYouOutOfThisDevice": "Dette vil logge deg ut av denne enheten!", + "thisWillLogYouOutOfTheFollowingDevice": "Dette vil logge deg ut av følgende enhet:", + "terminateSession": "Avslutte økten?", + "terminate": "Avslutte", + "thisDevice": "Denne enheten", + "recoverButton": "Gjenopprett", + "recoverySuccessful": "Gjenopprettingen var vellykket!", + "decrypting": "Dekrypterer...", + "incorrectRecoveryKeyTitle": "Feil gjenopprettingsnøkkel", + "incorrectRecoveryKeyBody": "Gjennopprettingsnøkkelen du skrev inn er feil", + "forgotPassword": "Glemt passord", + "enterYourRecoveryKey": "Skriv inn din gjenopprettingsnøkkel", + "noRecoveryKey": "Ingen gjenopprettingsnøkkel?", + "sorry": "Beklager", + "noRecoveryKeyNoDecryption": "Grunnet vår type ente-til-ende-krypteringsprotokoll kan ikke dine data dekrypteres uten passordet ditt eller gjenopprettingsnøkkelen din", + "verifyEmail": "Bekreft e-postadresse", + "toResetVerifyEmail": "For å tilbakestille passordet ditt, vennligt bekreft e-posten din først.", + "checkInboxAndSpamFolder": "Sjekk innboksen din (og spam) for å fullføre verifikasjonen", + "tapToEnterCode": "Trykk for å angi kode", + "resendEmail": "Send e-posten på nytt", + "weHaveSendEmailTo": "Vi har sendt en e-post til {email}", + "@weHaveSendEmailTo": { + "description": "Text to indicate that we have sent a mail to the user", + "placeholders": { + "email": { + "description": "The email address of the user", + "type": "String", + "example": "example@ente.io" + } + } + }, + "setPasswordTitle": "Lag et passord", + "changePasswordTitle": "Bytt passord", + "resetPasswordTitle": "Tilbakestill passord", + "encryptionKeys": "Krypteringsnøkkel", + "passwordWarning": "Vi lagrer ikke dette passordet, så hvis du glemmer det, kan vi ikke dekryptere dataene dine", + "enterPasswordToEncrypt": "Angi et passord vi kan bruke til å kryptere dataene dine", + "enterNewPasswordToEncrypt": "Angi et nytt passord vi kan bruke til å kryptere dataene dine", + "weakStrength": "Svakt", + "strongStrength": "Sterkt", + "moderateStrength": "Moderat", + "passwordStrength": "Passordstyrke: {passwordStrengthValue}", + "@passwordStrength": { + "description": "Text to indicate the password strength", + "placeholders": { + "passwordStrengthValue": { + "description": "The strength of the password as a string", + "type": "String", + "example": "Weak or Moderate or Strong" + } + }, + "message": "Password Strength: {passwordStrengthText}" + }, + "passwordChangedSuccessfully": "Passordet ble endret", + "generatingEncryptionKeys": "Genererer krypteringsnøkler...", + "pleaseWait": "Vennligst vent...", + "continueLabel": "Fortsett", + "insecureDevice": "Usikker enhet", + "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": "Beklager, vi kunne ikke generere sikre nøkler på denne enheten.\n\nvennligst registrer deg fra en annen enhet.", + "howItWorks": "Hvordan det fungerer", + "encryption": "Kryptering", + "ackPasswordLostWarning": "Jeg forstår at dersom jeg mister passordet mitt, kan jeg miste dataen min, siden daten er ende-til-ende-kryptert.", + "privacyPolicyTitle": "Personvernserklæring", + "termsOfServicesTitle": "Vilkår", + "signUpTerms": "Jeg godtar bruksvilkårene og personvernreglene", + "logInLabel": "Logg inn", + "loginTerms": "Ved å klikke Logg inn, godtar jeg brukervilkårene og personvernreglene", + "changeEmail": "Endre e-postadresse", + "enterYourPassword": "Angi passordet ditt", + "welcomeBack": "Velkommen tilbake!", + "contactSupport": "Kontakt kundestøtte", + "incorrectPasswordTitle": "Feil passord", + "pleaseTryAgain": "Vennligst prøv igjen", + "recreatePasswordTitle": "Gjenopprett passord", + "useRecoveryKey": "Bruk gjenopprettingsnøkkel", + "recreatePasswordBody": "Den gjeldende enheten er ikke kraftig nok til å verifisere passordet ditt, men vi kan regenerere på en måte som fungerer på alle enheter.\n\nVennligst logg inn med gjenopprettingsnøkkelen og regenerer passordet (du kan bruke den samme igjen om du vil).", + "verifyPassword": "Bekreft passord", + "recoveryKey": "Gjenopprettingsnøkkel", + "recoveryKeyOnForgotPassword": "Hvis du glemmer passordet ditt er den eneste måten du kan gjenopprette dataene dine på med denne nøkkelen.", + "recoveryKeySaveDescription": "Vi lagrer ikke denne nøkkelen, vennligst lagre denne 24-ords nøkkelen på et trygt sted.", + "doThisLater": "Gjør dette senere", + "saveKey": "Lagre nøkkel", + "recoveryKeyCopiedToClipboard": "Gjenopprettingsnøkkel kopiert til utklippstavlen", + "recoverAccount": "Gjenopprett konto", + "recover": "Gjenopprett", + "dropSupportEmail": "Vennligst send en e-post til {supportEmail} fra din registrerte e-postadresse", + "@dropSupportEmail": { + "placeholders": { + "supportEmail": { + "description": "The support email address", + "type": "String", + "example": "support@ente.io" + } + } + }, + "twofactorSetup": "Oppsett av to-faktor", + "enterCode": "Angi kode", + "scanCode": "Skann kode", + "codeCopiedToClipboard": "Kode kopiert til utklippstavlen", + "copypasteThisCodentoYourAuthenticatorApp": "Kopier og lim inn denne koden\ntil autentiseringsappen din", + "tapToCopy": "trykk for å kopiere", + "scanThisBarcodeWithnyourAuthenticatorApp": "Skann denne strekkoden med\nautentiseringsappen din", + "enterThe6digitCodeFromnyourAuthenticatorApp": "Skriv inn den 6-sifrede koden fra\ndin autentiseringsapp", + "confirm": "Bekreft", + "setupComplete": "Oppsett fullført", + "saveYourRecoveryKeyIfYouHaventAlready": "Lagre gjenopprettingsnøkkelen hvis du ikke allerede har gjort det", + "thisCanBeUsedToRecoverYourAccountIfYou": "Dette kan brukes til å gjenopprette kontoen din hvis du mister din andre faktor", + "twofactorAuthenticationPageTitle": "Tofaktorautentisering", + "lostDevice": "Mistet enhet?", + "verifyingRecoveryKey": "Verifiserer gjenopprettingsnøkkel...", + "recoveryKeyVerified": "Gjenopprettingsnøkkel bekreftet", + "recoveryKeySuccessBody": "Flott! Din gjenopprettingsnøkkel er gyldig. Takk for bekreftelsen.\n\nVennligst husk å holde gjenopprettingsnøkkelen din trygt sikkerhetskopiert.", + "invalidRecoveryKey": "Gjenopprettingsnøkkelen du har skrevet inn er ikke gyldig. Kontroller at den inneholder 24 ord og kontroller stavemåten av hvert ord.\n\nHvis du har angitt en eldre gjenopprettingskode, må du kontrollere at den er 64 tegn lang, og kontrollere hvert av dem.", + "invalidKey": "Ugyldig nøkkel", + "tryAgain": "Prøv igjen", + "viewRecoveryKey": "Vis gjenopprettingsnøkkel", + "confirmRecoveryKey": "Bekreft gjenopprettingsnøkkel", + "recoveryKeyVerifyReason": "Gjenopprettings nøkkelen er den eneste måten å gjenopprette bildene dine hvis du glemmer passordet ditt. Du kan finne gjenopprettingsnøkkelen din i Innstillinger > Sikkerhet.\n\nVennligst skriv inn gjenopprettingsnøkkelen din her for å bekrefte at du har lagret den riktig.", + "confirmYourRecoveryKey": "Bekreft din gjenopprettingsnøkkel", + "addViewer": "Legg til seer", + "addCollaborator": "Legg til samarbeidspartner", + "addANewEmail": "Legg til ny e-post", + "orPickAnExistingOne": "Eller velg en eksisterende", + "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": "Samarbeidspartnere kan legge til bilder og videoer i det delte albumet.", + "enterEmail": "Skriv inn e-post", + "albumOwner": "Eier", + "@albumOwner": { + "description": "Role of the album owner" + }, + "you": "Deg", + "collaborator": "Samarbeidspartner", + "addMore": "Legg til flere", + "@addMore": { + "description": "Button text to add more collaborators/viewers" + }, + "viewer": "Seer", + "remove": "Fjern", + "removeParticipant": "Fjern deltaker", + "@removeParticipant": { + "description": "menuSectionTitle for removing a participant" + }, + "manage": "Administrer", + "addedAs": "Lagt til som", + "changePermissions": "Endre tillatelser?", + "yesConvertToViewer": "Ja, konverter til seer", + "cannotAddMorePhotosAfterBecomingViewer": "{user} vil ikke kunne legge til flere bilder til dette albumet\n\nDe vil fortsatt kunne fjerne eksisterende bilder lagt til av dem", + "allowAddingPhotos": "Tillat å legge til bilder", + "@allowAddingPhotos": { + "description": "Switch button to enable uploading photos to a public link" + }, + "allowAddPhotosDescription": "Tillat folk med lenken å også legge til bilder til det delte albumet.", + "passwordLock": "Passordlås", + "disableDownloadWarningTitle": "Vær oppmerksom på", + "disableDownloadWarningBody": "Seere kan fremdeles ta skjermbilder eller lagre en kopi av bildene dine ved bruk av eksterne verktøy", + "allowDownloads": "Tillat nedlastinger", + "linkDeviceLimit": "Enhetsgrense", + "noDeviceLimit": "Ingen", + "@noDeviceLimit": { + "description": "Text to indicate that there is limit on number of devices" + }, + "linkExpiry": "Lenkeutløp", + "linkExpired": "Utløpt", + "linkEnabled": "Aktivert", + "linkNeverExpires": "Aldri", + "expiredLinkInfo": "Denne lenken er utløpt. Vennligst velg en ny utløpstid eller deaktiver lenkeutløp.", + "setAPassword": "Lag et passord", + "lockButtonLabel": "Lås", + "enterPassword": "Angi passord", + "removeLink": "Fjern lenke", + "manageLink": "Administrer lenke", + "linkExpiresOn": "Lenken utløper på {expiryTime}", + "albumUpdated": "Album oppdatert", + "never": "Aldri", + "custom": "Egendefinert", + "@custom": { + "description": "Label for setting custom value for link expiry" + }, + "after1Hour": "Etter 1 time", + "after1Day": "Etter 1 dag", + "after1Week": "Etter 1 uke", + "after1Month": "Etter 1 måned", + "after1Year": "Etter 1 år", + "manageParticipants": "Administrer", + "albumParticipantsCount": "{count, plural, one {}=0 {Ingen deltakere} =1 {1 Deltaker} other {{count} Deltakere}}", + "@albumParticipantsCount": { + "placeholders": { + "count": { + "type": "int", + "example": "5" + } + }, + "description": "Number of participants in an album, including the album owner." + }, + "collectPhotos": "Samle bilder", + "collaborativeLink": "Samarbeidslenke", + "createPublicLink": "Opprett offentlig lenke", + "sendLink": "Send lenke", + "copyLink": "Kopier lenke", + "linkHasExpired": "Lenken har utløpt", + "publicLinkEnabled": "Offentlig lenke aktivert", + "shareALink": "Del en lenke", + "shareWithPeopleSectionTitle": "{numberOfPeople, plural, one {}=0 {Del med bestemte personer} =1 {Delt med 1 person} other {Delt med {numberOfPeople} personer}}", + "@shareWithPeopleSectionTitle": { + "placeholders": { + "numberOfPeople": { + "type": "int", + "example": "2" + } + } + }, + "thisIsYourVerificationId": "Dette er din bekreftelses-ID", + "someoneSharingAlbumsWithYouShouldSeeTheSameId": "Folk som deler album med deg bør se den samme ID-en på deres enhet.", + "howToViewShareeVerificationID": "Vennligst be dem om å trykke og holde inne på e-postadressen sin på innstillingsskjermen, og bekreft at ID-ene på begge enhetene er like.", + "thisIsPersonVerificationId": "Dette er {email} sin verifiserings-ID", + "@thisIsPersonVerificationId": { + "placeholders": { + "email": { + "type": "String", + "example": "someone@ente.io" + } + } + }, + "verificationId": "Verifiserings-ID", + "verifyEmailID": "Verifiser {email}", + "shareMyVerificationID": "Her er min verifiserings-ID: {verificationID} for ente.io.", + "shareTextConfirmOthersVerificationID": "Hei, kan du bekrefte at dette er din ente.io verifiserings-ID: {verificationID}", + "somethingWentWrong": "Noe gikk galt", + "sendInvite": "Send invitasjon", + "done": "Ferdig", + "enterCodeDescription": "Angi koden fra vennen din for å få gratis lagringsplass for dere begge", + "apply": "Anvend", + "enterReferralCode": "Angi vervekode", + "keepPhotos": "Behold Bilder", + "deletePhotos": "Slett bilder", + "removePublicLink": "Fjern offentlig lenke", + "disableLinkMessage": "Dette fjerner den offentlige lenken for tilgang til \"{albumName}\".", + "sharing": "Deler...", + "youCannotShareWithYourself": "Du kan ikke dele med deg selv", + "createAlbumActionHint": "Trykk og holde inne for å velge bilder, og trykk på + for å lage et album", + "importing": "Importerer....", + "failedToLoadAlbums": "Kunne ikke laste inn album", + "hidden": "Skjult", + "authToViewYourHiddenFiles": "Vennligst autentiser deg for å se dine skjulte filer", + "trash": "Papirkurv", + "uncategorized": "Ukategorisert", + "videoSmallCase": "video", + "photoSmallCase": "bilde", + "singleFileDeleteHighlight": "Den vil bli slettet fra alle album.", + "yesDelete": "Ja, slett", + "movedToTrash": "Flyttet til papirkurven", + "deleteFromDevice": "Slett fra enhet", + "deleteFromBoth": "Slett fra begge", + "newAlbum": "Nytt album", + "albums": "Album", + "memoryCount": "{count, plural, zero{ingen minner} one{{formattedCount} minne} other{{formattedCount} minner}}", + "@memoryCount": { + "description": "The text to display the number of memories", + "type": "text", + "placeholders": { + "count": { + "example": "1", + "type": "int" + }, + "formattedCount": { + "type": "String", + "example": "11.513, 11,511" + } + } + }, + "selectedPhotos": "{count} valgt", + "@selectedPhotos": { + "description": "Display the number of selected photos", + "type": "text", + "placeholders": { + "count": { + "example": "5", + "type": "int" + } + } + }, + "selectedPhotosWithYours": "{count} valgt ({yourCount} dine)", + "@selectedPhotosWithYours": { + "description": "Display the number of selected photos, including the number of selected photos owned by the user", + "type": "text", + "placeholders": { + "count": { + "example": "12", + "type": "int" + }, + "yourCount": { + "example": "2", + "type": "int" + } + } + }, + "advancedSettings": "Avansert", + "@advancedSettings": { + "description": "The text to display in the advanced settings section" + }, + "photoGridSize": "Bilderutenettstørrelse", + "manageDeviceStorage": "Behandle enhetslagring", + "machineLearning": "Maskinlæring", + "magicSearch": "Magisk søk", + "status": "Status", + "indexedItems": "Indekserte elementer", + "pendingItems": "Ventende elementer", + "clearIndexes": "Tøm indekser", + "selectFoldersForBackup": "Velg mapper for sikkerhetskopiering", + "selectedFoldersWillBeEncryptedAndBackedUp": "Valgte mapper vil bli kryptert og sikkerhetskopiert", + "unselectAll": "Velg bort alle", + "selectAll": "Velg alle", + "skip": "Hopp over", + "updatingFolderSelection": "Oppdaterer mappevalg...", + "itemCount": "{count, plural, one{{count} element} other{{count} elementer}}", + "deleteItemCount": "{count, plural, =1 {Slett {count} element} other {Slett {count} elementer}}", + "duplicateItemsGroup": "{count} filer, {formattedSize} hver", + "@duplicateItemsGroup": { + "description": "Display the number of duplicate files and their size", + "type": "text", + "placeholders": { + "count": { + "example": "12", + "type": "int" + }, + "formattedSize": { + "example": "2.3 MB", + "type": "String" + } + } + }, + "remindToEmptyEnteTrash": "Du kan også tømme \"Papirkurven\" for å få den frigjorte lagringsplassen", + "sparkleSuccess": "✨ Suksess", + "familyPlans": "Familieabonnementer", + "referrals": "Vervinger", + "notifications": "Varslinger", + "sharedPhotoNotifications": "Nye delte bilder", + "sharedPhotoNotificationsExplanation": "Motta varsler når noen legger til et bilde i et delt album som du er en del av", + "advanced": "Avansert", + "general": "Generelt", + "security": "Sikkerhet", + "authToViewYourRecoveryKey": "Vennligst autentiser deg for å se gjennopprettingsnøkkelen din" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ru.arb b/mobile/lib/l10n/intl_ru.arb index fead2aae50..2bf2d4efc1 100644 --- a/mobile/lib/l10n/intl_ru.arb +++ b/mobile/lib/l10n/intl_ru.arb @@ -1,4 +1,5 @@ { + "@@locale ": "en", "enterYourEmailAddress": "Введите свою электронную почту", "accountWelcomeBack": "С возвращением!", "email": "Электронная почта", @@ -272,6 +273,8 @@ "failedToApplyCode": "Не удалось применить код", "enterReferralCode": "Введите реферальный код", "codeAppliedPageTitle": "Код применён", + "changeYourReferralCode": "Изменить ваш реферальный код", + "change": "Изменить", "storageInGB": "{storageAmountInGB} Гигабайт", "claimed": "Получено", "@claimed": { @@ -409,7 +412,6 @@ "manageDeviceStorage": "Управление хранилищем устройства", "machineLearning": "Machine learning", "magicSearch": "Волшебный поиск", - "mlIndexingDescription": "Пожалуйста, обратите внимание, что машинное обучение приведет к увеличению затрат интернета и энергопотребления до тех пор, пока не будут индексированы все элементы.", "loadingModel": "Загрузка моделей...", "waitingForWifi": "Ожидание WiFi...", "status": "Статус", @@ -485,7 +487,6 @@ "removeDuplicates": "Удаление дубликатов", "removeDuplicatesDesc": "Просмотрите и удалите точные дубликаты.", "viewLargeFiles": "Большие файлы", - "viewLargeFilesDesc": "Просмотр файлов, которые потребляют наибольшее количество памяти", "noDuplicates": "✨ Дубликатов нет", "youveNoDuplicateFilesThatCanBeCleared": "У вас нет дубликатов файлов, которые можно очистить", "success": "Успешно", @@ -1250,42 +1251,49 @@ "left": "Влево", "right": "Вправо", "whatsNew": "Что нового", - "reenterPassword": "Re-enter password", - "mlFunctions": "ML functions", - "reenterPin": "Re-enter PIN", - "deviceLock": "Device lock", - "pinLock": "PIN lock", - "next": "Next", - "setNewPassword": "Set new password", - "enterPin": "Enter PIN", - "setNewPin": "Set new PIN", - "appLock": "App lock", - "noSystemLockFound": "No system lock found", - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "To enable app lock, please setup device passcode or screen lock in your system settings.", - "tapToUnlock": "Tap to unlock", - "tooManyIncorrectAttempts": "Too many incorrect attempts", - "appLockDescription": "Choose between your device\\'s default lock screen and a custom lock screen with a PIN or password.", - "swipeLockEnablePreSteps": "To enable swipe lock, please setup device passcode or screen lock in your system settings.", - "autoLock": "Auto lock", - "immediately": "Immediately", - "autoLockFeatureDescription": "Time after which the app locks after being put in the background", - "hideContent": "Hide content", - "hideContentDescriptionAndroid": "Hides app content in the app switcher and disables screenshots", - "hideContentDescriptionIos": "Hides app content in the app switcher", - "passwordStrengthInfo": "Password strength is calculated considering the length of the password, used characters, and whether or not the password appears in the top 10,000 most used passwords", - "noQuickLinksSelected": "No quick links selected", - "pleaseSelectQuickLinksToRemove": "Please select quick links to remove", - "removePublicLinks": "Remove public links", - "thisWillRemovePublicLinksOfAllSelectedQuickLinks": "This will remove public links of all selected quick links.", - "guestView": "Guest view", - "guestViewEnablePreSteps": "To enable guest view, please setup device passcode or screen lock in your system settings.", - "cl_guest_view_title": "Режим гостя", - "cl_guest_view_description": "Показываете фото другу? Не переживайте, что он листнет слишком далеко. Режим гостя заблокирует те фото, которые вы выбрали.", - "cl_guest_view_call_to_action": "Выберите фото и попробуйте \"Режим гостя\".", + "reviewSuggestions": "Посмотреть предложения", + "useAsCover": "Использовать для обложки", + "notPersonLabel": "Не {name}?", + "@notPersonLabel": { + "description": "Label to indicate that the person in the photo is not the person whose name is mentioned", + "placeholders": { + "name": { + "content": "{name}", + "type": "String" + } + } + }, + "enable": "Включить", + "enabled": "Включено", + "moreDetails": "Подробнее", + "panorama": "Панорама", + "reenterPassword": "Подтвердите пароль", + "reenterPin": "Введите PIN-код ещё раз", + "deviceLock": "Блокировка устройства", + "pinLock": "Блокировка PIN-кодом", + "next": "Далее", + "setNewPassword": "Задать новый пароль", + "enterPin": "Введите PIN", + "setNewPin": "Установите новый PIN", + "appLock": "Блокировка приложения", + "noSystemLockFound": "Системная блокировка не найдена", + "tapToUnlock": "Нажмите для разблокировки", + "tooManyIncorrectAttempts": "Слишком много неудачных попыток", + "videoInfo": "Информация о видео", + "autoLock": "Автоблокировка", + "immediately": "Немедленно", + "autoLockFeatureDescription": "Время в фоне, после которого приложение блокируется", + "hideContent": "Скрыть содержимое", + "hideContentDescriptionAndroid": "Скрывает содержимое приложения в переключателе приложений и отключает скриншоты", + "hideContentDescriptionIos": "Скрывает содержимое приложения в переключателе приложений", + "passwordStrengthInfo": "Надежность пароля рассчитывается с учетом длины пароля, используемых символов, и появлением пароля в 10 000 наиболее используемых", + "noQuickLinksSelected": "Не выбрано быстрых ссылок", + "pleaseSelectQuickLinksToRemove": "Пожалуйста, выберите быстрые ссылки для удаления", + "removePublicLinks": "Удалить публичные ссылки", + "thisWillRemovePublicLinksOfAllSelectedQuickLinks": "Это удалит публичные ссылки на все выбранные быстрые ссылки.", + "guestView": "Гостевой вид", + "guestViewEnablePreSteps": "Чтобы включить гостевой вид, настройте пароль устройства или блокировку экрана в настройках системы.", + "cl_guest_view_title": "Гостевой вид", "cl_panorama_viewer_title": "Просмотр Панорамы", - "cl_panorama_viewer_description": "Мы добавили поддержку просмотра панорамных фотографий с углом обзора 360 градусов. Погружение обеспечивается навигацией на основе движения!", - "cl_video_player_title": "Видеоплеер", - "cl_video_player_description": "Представляем новый видеоплеер с улучшенными элементами управления воспроизведением и поддержкой HDR видео.", - "appLockDescriptions": "Choose between your device's default lock screen and a custom lock screen with a PIN or password.", - "authToViewPasskey": "Please authenticate to view your passkey" + "cl_video_player_title": "Видеоплеер" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_sv.arb b/mobile/lib/l10n/intl_sv.arb new file mode 100644 index 0000000000..3c51f175e0 --- /dev/null +++ b/mobile/lib/l10n/intl_sv.arb @@ -0,0 +1,427 @@ +{ + "@@locale ": "en", + "enterYourEmailAddress": "Ange din e-postadress", + "accountWelcomeBack": "Välkommen tillbaka!", + "email": "E-post", + "cancel": "Avbryt", + "verify": "Bekräfta", + "invalidEmailAddress": "Ogiltig e-postadress", + "enterValidEmail": "Ange en giltig e-postadress.", + "deleteAccount": "Radera konto", + "askDeleteReason": "Vad är den främsta anledningen till att du raderar ditt konto?", + "deleteAccountFeedbackPrompt": "Vi är ledsna att se dig lämna oss. Vänligen dela dina synpunkter för att hjälpa oss att förbättra.", + "feedback": "Feedback", + "kindlyHelpUsWithThisInformation": "Vänligen hjälp oss med denna information", + "confirmDeletePrompt": "Ja, jag vill ta bort detta konto och all data permanent.", + "confirmAccountDeletion": "Bekräfta radering av konto", + "deleteAccountPermanentlyButton": "Radera kontot permanent", + "yourAccountHasBeenDeleted": "Ditt konto har raderats", + "selectReason": "Välj anledning", + "deleteReason1": "Det saknas en viktig funktion som jag behöver", + "deleteReason2": "Appen eller en viss funktion beter sig inte som jag tycker det ska", + "deleteReason3": "Jag hittade en annan tjänst som jag gillar bättre", + "deleteReason4": "Min orsak finns inte med", + "sendEmail": "Skicka e-post", + "deleteRequestSLAText": "Din begäran kommer att hanteras inom 72 timmar.", + "deleteEmailRequest": "Vänligen skicka ett e-postmeddelande till account-deletion@ente.io från din registrerade e-postadress.", + "entePhotosPerm": "Ente behöver tillåtelse att bevara dina foton", + "ok": "OK", + "createAccount": "Skapa konto", + "createNewAccount": "Skapa nytt konto", + "password": "Lösenord", + "confirmPassword": "Bekräfta lösenord", + "activeSessions": "Aktiva sessioner", + "oops": "Hoppsan", + "somethingWentWrongPleaseTryAgain": "Något gick fel, vänligen försök igen", + "thisWillLogYouOutOfThisDevice": "Detta kommer att logga ut dig från denna enhet!", + "thisWillLogYouOutOfTheFollowingDevice": "Detta kommer att logga ut dig från följande enhet:", + "terminateSession": "Avsluta sessionen?", + "terminate": "Avsluta", + "thisDevice": "Den här enheten", + "recoverButton": "Återställ", + "recoverySuccessful": "Återställning lyckades!", + "decrypting": "Dekrypterar...", + "incorrectRecoveryKeyTitle": "Felaktig återställningsnyckel", + "incorrectRecoveryKeyBody": "Återställningsnyckeln du angav är felaktig", + "forgotPassword": "Glömt lösenord", + "enterYourRecoveryKey": "Ange din återställningsnyckel", + "noRecoveryKey": "Ingen återställningsnyckel?", + "sorry": "Förlåt", + "noRecoveryKeyNoDecryption": "På grund av vårt punkt-till-punkt-krypteringssystem så kan dina data inte avkrypteras utan ditt lösenord eller återställningsnyckel", + "verifyEmail": "Bekräfta e-postadress", + "toResetVerifyEmail": "För att återställa ditt lösenord måste du först bekräfta din e-postadress.", + "checkInboxAndSpamFolder": "Kontrollera din inkorg (och skräppost) för att slutföra verifieringen", + "tapToEnterCode": "Tryck för att ange kod", + "resendEmail": "Skicka e-postmeddelandet igen", + "weHaveSendEmailTo": "Vi har skickat ett e-postmeddelande till {email}", + "@weHaveSendEmailTo": { + "description": "Text to indicate that we have sent a mail to the user", + "placeholders": { + "email": { + "description": "The email address of the user", + "type": "String", + "example": "example@ente.io" + } + } + }, + "setPasswordTitle": "Välj lösenord", + "changePasswordTitle": "Ändra lösenord", + "resetPasswordTitle": "Återställ lösenord", + "encryptionKeys": "Krypteringsnycklar", + "passwordWarning": "Vi lagrar inte detta lösenord, så om du glömmer bort det, kan vi inte dekryptera dina data", + "enterPasswordToEncrypt": "Ange ett lösenord som vi kan använda för att kryptera din data", + "enterNewPasswordToEncrypt": "Ange ett nytt lösenord som vi kan använda för att kryptera din data", + "weakStrength": "Svagt", + "strongStrength": "Starkt", + "moderateStrength": "Måttligt", + "passwordStrength": "Lösenordsstyrka: {passwordStrengthValue}", + "@passwordStrength": { + "description": "Text to indicate the password strength", + "placeholders": { + "passwordStrengthValue": { + "description": "The strength of the password as a string", + "type": "String", + "example": "Weak or Moderate or Strong" + } + }, + "message": "Password Strength: {passwordStrengthText}" + }, + "passwordChangedSuccessfully": "Lösenordet har ändrats", + "generatingEncryptionKeys": "Skapar krypteringsnycklar...", + "pleaseWait": "Var god vänta...", + "continueLabel": "Fortsätt", + "insecureDevice": "Osäker enhet", + "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": "Tyvärr, vi kunde inte generera säkra nycklar på den här enheten.\n\nVänligen registrera dig från en annan enhet.", + "howItWorks": "Så här fungerar det", + "encryption": "Kryptering", + "ackPasswordLostWarning": "Jag förstår att om jag förlorar mitt lösenord kan jag förlora mina data eftersom min data är end-to-end-krypterad.", + "privacyPolicyTitle": "Integritetspolicy", + "termsOfServicesTitle": "Villkor", + "signUpTerms": "Jag samtycker till användarvillkoren och integritetspolicyn", + "logInLabel": "Logga in", + "loginTerms": "Genom att klicka på logga in godkänner jag användarvillkoren och våran integritetspolicy", + "changeEmail": "Ändra e-postadress", + "enterYourPassword": "Ange ditt lösenord", + "welcomeBack": "Välkommen tillbaka!", + "contactSupport": "Kontakta support", + "incorrectPasswordTitle": "Felaktigt lösenord", + "pleaseTryAgain": "Försök igen", + "recreatePasswordTitle": "Återskapa lösenord", + "useRecoveryKey": "Använd återställningsnyckel", + "recreatePasswordBody": "Denna enhet är inte tillräckligt kraftfull för att verifiera ditt lösenord, men vi kan återskapa det på ett sätt som fungerar med alla enheter.\n\nLogga in med din återställningsnyckel och återskapa ditt lösenord (du kan använda samma igen om du vill).", + "verifyPassword": "Bekräfta lösenord", + "recoveryKey": "Återställningsnyckel", + "recoveryKeyOnForgotPassword": "Om du glömmer ditt lösenord är det enda sättet du kan återställa dina data med denna nyckel.", + "recoveryKeySaveDescription": "Vi lagrar inte och har därför inte åtkomst till denna nyckel, vänligen spara denna 24 ords nyckel på en säker plats.", + "doThisLater": "Gör detta senare", + "saveKey": "Spara nyckel", + "recoveryKeyCopiedToClipboard": "Återställningsnyckel kopierad till urklipp", + "recoverAccount": "Återställ konto", + "recover": "Återställ", + "dropSupportEmail": "Vänligen skicka ett e-postmeddelande till {supportEmail} från din registrerade e-postadress", + "@dropSupportEmail": { + "placeholders": { + "supportEmail": { + "description": "The support email address", + "type": "String", + "example": "support@ente.io" + } + } + }, + "twofactorSetup": "Tvåfaktorskonfiguration", + "enterCode": "Ange kod", + "scanCode": "Skanna kod", + "codeCopiedToClipboard": "Koden har kopierats till urklipp", + "copypasteThisCodentoYourAuthenticatorApp": "Kopiera-klistra in den här koden\ntill din autentiseringsapp", + "tapToCopy": "tryck för att kopiera", + "scanThisBarcodeWithnyourAuthenticatorApp": "Skanna denna streckkod med\ndin autentiseringsapp", + "enterThe6digitCodeFromnyourAuthenticatorApp": "Ange den 6-siffriga koden från din autentiseringsapp", + "confirm": "Bekräfta", + "setupComplete": "Konfiguration slutförd", + "saveYourRecoveryKeyIfYouHaventAlready": "Spara din återställningsnyckel om du inte redan har gjort det", + "thisCanBeUsedToRecoverYourAccountIfYou": "Detta kan användas för att återställa ditt konto om du förlorar din andra faktor", + "twofactorAuthenticationPageTitle": "Tvåfaktorsautentisering", + "lostDevice": "Förlorad enhet?", + "verifyingRecoveryKey": "Verifierar återställningsnyckel...", + "recoveryKeyVerified": "Återställningsnyckel verifierad", + "recoveryKeySuccessBody": "Grymt! Din återställningsnyckel är giltig. Tack för att du verifierade.\n\nKom ihåg att hålla din återställningsnyckel säker med backups.", + "invalidRecoveryKey": "Återställningsnyckeln du angav är inte giltig. Kontrollera att den innehåller 24 ord och kontrollera stavningen av varje ord.\n\nOm du har angett en äldre återställnings kod, se till att den är 64 tecken lång, och kontrollera var och en av bokstäverna.", + "invalidKey": "Ogiltig nyckel", + "tryAgain": "Försök igen", + "viewRecoveryKey": "Visa återställningsnyckel", + "confirmRecoveryKey": "Bekräfta återställningsnyckel", + "recoveryKeyVerifyReason": "Din återställningsnyckel är det enda sättet att återställa dina foton om du glömmer ditt lösenord. Du hittar din återställningsnyckel i Inställningar > Säkerhet.\n\nAnge din återställningsnyckel här för att verifiera att du har sparat den ordentligt.", + "confirmYourRecoveryKey": "Bekräfta din återställningsnyckel", + "addViewer": "Lägg till bildvy", + "addCollaborator": "Lägg till samarbetspartner", + "addANewEmail": "Lägg till en ny e-postadress", + "orPickAnExistingOne": "Eller välj en befintlig", + "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": "Samarbetspartner kan lägga till foton och videor till det delade albumet.", + "enterEmail": "Ange e-post", + "albumOwner": "Ägare", + "@albumOwner": { + "description": "Role of the album owner" + }, + "you": "Du", + "collaborator": "Samarbetspartner", + "addMore": "Lägg till fler", + "@addMore": { + "description": "Button text to add more collaborators/viewers" + }, + "viewer": "Bildvy", + "remove": "Ta bort", + "removeParticipant": "Ta bort användaren", + "@removeParticipant": { + "description": "menuSectionTitle for removing a participant" + }, + "manage": "Hantera", + "addedAs": "Lades till som", + "changePermissions": "Ändra behörighet?", + "yesConvertToViewer": "Ja, konvertera till bildvy", + "cannotAddMorePhotosAfterBecomingViewer": "{user} kommer inte att kunna lägga till fler foton till detta album\n\nDe kommer fortfarande att kunna ta bort befintliga foton som lagts till av dem", + "allowAddingPhotos": "Tillåt lägga till foton", + "@allowAddingPhotos": { + "description": "Switch button to enable uploading photos to a public link" + }, + "allowAddPhotosDescription": "Tillåt personer med länken att även lägga till foton i det delade albumet.", + "passwordLock": "Lösenordskydd", + "disableDownloadWarningTitle": "Vänligen notera:", + "disableDownloadWarningBody": "Besökare kan fortfarande ta skärmdumpar eller spara en kopia av dina foton med hjälp av externa verktyg", + "allowDownloads": "Tillåt nedladdningar", + "linkDeviceLimit": "Enhetsgräns", + "noDeviceLimit": "Ingen", + "@noDeviceLimit": { + "description": "Text to indicate that there is limit on number of devices" + }, + "linkExpiry": "Länken upphör", + "linkExpired": "Upphört", + "linkEnabled": "Aktiverat", + "linkNeverExpires": "Aldrig", + "expiredLinkInfo": "Denna länk har upphört att gälla. Välj ett nytt datum eller inaktivera tidsbegränsningen.", + "setAPassword": "Ange ett lösenord", + "lockButtonLabel": "Lås", + "enterPassword": "Ange lösenord", + "removeLink": "Radera länk", + "manageLink": "Hantera länk", + "linkExpiresOn": "Länken upphör att gälla {expiryTime}", + "albumUpdated": "Album uppdaterat", + "never": "Aldrig", + "custom": "Anpassad", + "@custom": { + "description": "Label for setting custom value for link expiry" + }, + "after1Hour": "Om en timme", + "after1Day": "Om en dag", + "after1Week": "Om en vecka", + "after1Month": "Om en månad", + "after1Year": "Om ett år", + "manageParticipants": "Hantera", + "albumParticipantsCount": "{count, plural, =0 {Inga deltagare} =1 {1 deltagare} other {{count} deltagare}}", + "@albumParticipantsCount": { + "placeholders": { + "count": { + "type": "int", + "example": "5" + } + }, + "description": "Number of participants in an album, including the album owner." + }, + "collabLinkSectionDescription": "Skapa en länk så att personer kan lägga till och visa foton i ditt delade album utan att behöva en Ente app eller konto. Perfekt för att samla in bilder från evenemang.", + "collectPhotos": "Samla in foton", + "collaborativeLink": "Samarbetslänk", + "shareWithNonenteUsers": "Dela med icke-Ente användare", + "createPublicLink": "Skapa offentlig länk", + "sendLink": "Skicka länk", + "copyLink": "Kopiera länk", + "linkHasExpired": "Länk har upphört att gälla", + "publicLinkEnabled": "Offentlig länk aktiverad", + "shareALink": "Dela en länk", + "sharedAlbumSectionDescription": "Skapa delade och samarbetande album med andra Ente användare, inklusive användare med gratisnivån.", + "shareWithPeopleSectionTitle": "{numberOfPeople, plural, one {}=0 {Dela med specifika personer} =1 {Delad med en person} other {Delad med {numberOfPeople} personer}}", + "@shareWithPeopleSectionTitle": { + "placeholders": { + "numberOfPeople": { + "type": "int", + "example": "2" + } + } + }, + "thisIsYourVerificationId": "Detta är ditt verifierings-ID", + "someoneSharingAlbumsWithYouShouldSeeTheSameId": "Någon som delar album med dig bör se samma ID på deras enhet.", + "howToViewShareeVerificationID": "Be dem att långtrycka på sin e-postadress på inställningsskärmen och verifiera att ID:n på båda enheterna matchar.", + "thisIsPersonVerificationId": "Detta är {email}s verifierings-ID", + "@thisIsPersonVerificationId": { + "placeholders": { + "email": { + "type": "String", + "example": "someone@ente.io" + } + } + }, + "verificationId": "Verifierings-ID", + "verifyEmailID": "Bekräfta {email}", + "emailNoEnteAccount": "{email} har inte ett Ente-konto.\n\nSkicka dem en inbjudan för att dela bilder.", + "shareMyVerificationID": "Här är mitt verifierings-ID: {verificationID} för ente.io.", + "shareTextConfirmOthersVerificationID": "Hallå, kan du bekräfta att detta är ditt ente.io verifierings-ID: {verificationID}", + "somethingWentWrong": "Något gick fel", + "sendInvite": "Skicka inbjudan", + "shareTextRecommendUsingEnte": "Ladda ner Ente så att vi enkelt kan dela bilder och videor med originell kvalitet\n\nhttps://ente.io", + "done": "Klar", + "applyCodeTitle": "Använd kod", + "enterCodeDescription": "Ange koden som din vän har angett för att få gratis lagring för er båda", + "apply": "Verkställ", + "failedToApplyCode": "Det gick inte att använda koden", + "enterReferralCode": "Ange hänvisningskod", + "codeAppliedPageTitle": "Kod tillämpad", + "change": "Ändra", + "onlyFamilyAdminCanChangeCode": "Kontakta {familyAdminEmail} för att ändra din kod.", + "storageInGB": "{storageAmountInGB} GB", + "claimed": "Nyttjad", + "@claimed": { + "description": "Used to indicate storage claimed, like 10GB Claimed" + }, + "inviteYourFriends": "Bjud in dina vänner", + "subscribe": "Prenumerera", + "trash": "Papperskorg", + "photoSmallCase": "foto", + "yesDelete": "Ja, radera", + "deleteFromDevice": "Radera från enhet", + "newAlbum": "Nytt album", + "albums": "Album", + "mlConsent": "Aktivera maskininlärning", + "mlConsentTitle": "Aktivera maskininlärning?", + "status": "Status", + "itemCount": "{count, plural, one{{count} objekt} other{{count} objekt}}", + "deleteItemCount": "{count, plural, =1 {Radera {count} objekt} other {Radera {count} objekt}}", + "yearsAgo": "{count, plural, one{{count} år sedan} other{{count} år sedan}}", + "about": "Om", + "terms": "Villkor", + "account": "Konto", + "manageSubscription": "Hantera prenumeration", + "changePassword": "Ändra lösenord", + "exportYourData": "Exportera din data", + "logout": "Logga ut", + "areYouSureYouWantToLogout": "Är du säker på att du vill logga ut?", + "yesLogout": "Ja, logga ut", + "aNewVersionOfEnteIsAvailable": "En ny version av Ente är tillgänglig.", + "update": "Uppdatera", + "ignoreUpdate": "Ignorera", + "retry": "Försök igen", + "viewActiveSessions": "Visa aktiva sessioner", + "no": "Nej", + "yes": "Ja", + "rateUsOnStore": "Betygsätt oss på {storeName}", + "blog": "Blogg", + "twitter": "Twitter", + "mastodon": "Mastodon", + "matrix": "Matrix", + "discord": "Discord", + "reddit": "Reddit", + "theme": "Tema", + "lightTheme": "Ljust", + "darkTheme": "Mörkt", + "subscription": "Prenumeration", + "renewSubscription": "Förnya prenumeration", + "yesRenew": "Ja, förnya", + "yesCancel": "Ja, avbryt", + "send": "Skicka", + "thankYou": "Tack", + "leave": "Lämna", + "pleaseLoginAgain": "Logga in igen", + "upgrade": "Uppgradera", + "name": "Namn", + "moveToAlbum": "Flytta till album", + "shareLink": "Dela länk", + "delete": "Radera", + "share": "Dela", + "moveItem": "{count, plural, one {Flytta objekt} other {Flytta objekt}}", + "@moveItem": { + "description": "Page title while moving one or more items to an album" + }, + "trashDaysLeft": "{count, plural, =0 {} =1 {1 dag} other {{count} dagar}}", + "@trashDaysLeft": { + "description": "Text to indicate number of days remaining before permanent deletion", + "placeholders": { + "count": { + "example": "1|2|3", + "type": "int" + } + } + }, + "deleteAll": "Radera alla", + "sortAlbumsBy": "Sortera efter", + "noResultsFound": "Inga resultat hittades", + "noExifData": "Ingen EXIF-data", + "exif": "EXIF", + "noResults": "Inga resultat", + "close": "Stäng", + "incorrectRecoveryKey": "Felaktig återställningsnyckel", + "theRecoveryKeyYouEnteredIsIncorrect": "Återställningsnyckeln du angav är felaktig", + "viewLogs": "Visa loggar", + "copyEmailAddress": "Kopiera e-postadress", + "language": "Språk", + "selectLanguage": "Välj språk", + "kiloMeterUnit": "km", + "addLocationButton": "Lägg till", + "save": "Spara", + "resetToDefault": "Återställ till standard", + "@resetToDefault": { + "description": "Button text to reset cover photo to default" + }, + "edit": "Redigera", + "color": "Färg", + "storageBreakupYou": "Du", + "@storageBreakupYou": { + "description": "Label to indicate how much storage you are using when you are part of a family plan" + }, + "availableStorageSpace": "{freeAmount} {storageUnit} gratis", + "appVersion": "Version: {versionValue}", + "fileInfoAddDescHint": "Lägg till en beskrivning...", + "androidCancelButton": "Avbryt", + "@androidCancelButton": { + "description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters." + }, + "goToSettings": "Gå till inställningar", + "@goToSettings": { + "description": "Message showed on a button that the user can click to go to settings pages from the current dialog. It is used on both Android and iOS side. Maximum 30 characters." + }, + "iOSOkButton": "OK", + "@iOSOkButton": { + "description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters." + }, + "create": "Skapa", + "viewAll": "Visa alla", + "inviteYourFriendsToEnte": "Bjud in dina vänner till Ente", + "fileTypes": "Filtyper", + "searchResultCount": "{count, plural, one{{count} resultat hittades} other{{count} resultat hittades}}", + "@searchResultCount": { + "description": "Text to tell user how many results were found for their search query", + "placeholders": { + "count": { + "example": "1|2|3", + "type": "int" + } + } + }, + "contacts": "Kontakter", + "noInternetConnection": "Ingen internetanslutning", + "pleaseCheckYourInternetConnectionAndTryAgain": "Kontrollera din internetanslutning och försök igen.", + "loginSessionExpiredDetails": "Din session har upphört. Logga in igen.", + "search": "Sök", + "whatsNew": "Nyheter", + "useAsCover": "Använd som omslag", + "notPersonLabel": "Inte {name}?", + "@notPersonLabel": { + "description": "Label to indicate that the person in the photo is not the person whose name is mentioned", + "placeholders": { + "name": { + "content": "{name}", + "type": "String" + } + } + }, + "next": "Nästa", + "guestView": "Gästvy", + "cl_guest_view_title": "Gästvy", + "cl_video_player_title": "Videospelare" +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_te.arb b/mobile/lib/l10n/intl_te.arb new file mode 100644 index 0000000000..c8494661c6 --- /dev/null +++ b/mobile/lib/l10n/intl_te.arb @@ -0,0 +1,3 @@ +{ + "@@locale ": "en" +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_th.arb b/mobile/lib/l10n/intl_th.arb new file mode 100644 index 0000000000..9d6b4c0801 --- /dev/null +++ b/mobile/lib/l10n/intl_th.arb @@ -0,0 +1,301 @@ +{ + "@@locale ": "en", + "enterYourEmailAddress": "ใส่ที่อยู่อีเมลของคุณ", + "accountWelcomeBack": "ยินดีต้อนรับกลับมา!", + "email": "อีเมล", + "cancel": "ยกเลิก", + "verify": "ยืนยัน", + "invalidEmailAddress": "ที่อยู่อีเมลไม่ถูกต้อง", + "enterValidEmail": "โปรดใส่ที่อยู่อีเมลที่ถูกต้อง", + "deleteAccount": "ลบบัญชี", + "askDeleteReason": "เหตุผลหลักที่คุณลบบัญชีคืออะไร?", + "deleteAccountFeedbackPrompt": "เราเสียใจที่เห็นคุณไป โปรดแบ่งปันความคิดเห็นของคุณเพื่อช่วยให้เราปรับปรุง", + "feedback": "ความคิดเห็น", + "kindlyHelpUsWithThisInformation": "กรุณาช่วยเราด้วยข้อมูลนี้", + "confirmDeletePrompt": "ใช่ ฉันต้องการลบบัญชีนี้และข้อมูลที่เกี่ยวข้องทั้งหมดแบบถาวร", + "confirmAccountDeletion": "ยืนยันการลบบัญชี", + "deleteAccountPermanentlyButton": "ลบบัญชีถาวร", + "yourAccountHasBeenDeleted": "บัญชีของคุณถูกลบแล้ว", + "selectReason": "เลือกเหตุผล", + "deleteReason1": "ขาดคุณสมบัติสำคัญที่ฉันต้องการ", + "deleteReason2": "ตัวแอปหรือคุณสมบัติบางอย่างไม่ทำงานเหมือนที่ฉันคิดว่าควรจะเป็น", + "deleteReason3": "ฉันเจอบริการอื่นที่ฉันชอบมากกว่า", + "deleteReason4": "เหตุผลของฉันไม่มีระบุไว้", + "sendEmail": "ส่งอีเมล", + "deleteRequestSLAText": "คำขอของคุณจะได้รับการดำเนินการภายใน 72 ชั่วโมง", + "deleteEmailRequest": "กรุณาส่งอีเมลไปที่ account-deletion@ente.io จากที่อยู่อีเมลที่คุณลงทะเบียนไว้", + "ok": "ตกลง", + "createAccount": "สร้างบัญชี", + "createNewAccount": "สร้างบัญชีใหม่", + "password": "รหัสผ่าน", + "confirmPassword": "ยืนยันรหัสผ่าน", + "activeSessions": "เซสชันที่ใช้งานอยู่", + "oops": "อ๊ะ", + "somethingWentWrongPleaseTryAgain": "มีบางอย่างผิดพลาด โปรดลองอีกครั้ง", + "thisDevice": "อุปกรณ์นี้", + "recoverButton": "กู้คืน", + "recoverySuccessful": "กู้คืนสำเร็จ!", + "decrypting": "กำลังถอดรหัส...", + "incorrectRecoveryKeyTitle": "คีย์การกู้คืนไม่ถูกต้อง", + "incorrectRecoveryKeyBody": "คีย์การกู้คืนที่คุณป้อนไม่ถูกต้อง", + "forgotPassword": "ลืมรหัสผ่าน", + "enterYourRecoveryKey": "ป้อนคีย์การกู้คืน", + "noRecoveryKey": "ไม่มีคีย์การกู้คืน?", + "sorry": "ขออภัย", + "noRecoveryKeyNoDecryption": "เนื่องจากลักษณะของโปรโตคอลการเข้ารหัสตั้งแต่ต้นทางถึงปลายทางของเรา ข้อมูลของคุณจึงไม่สามารถถอดรหัสได้หากไม่มีรหัสผ่านหรือคีย์การกู้คืน", + "verifyEmail": "ยืนยันอีเมล", + "toResetVerifyEmail": "เพื่อรีเซ็ตรหัสผ่านของคุณ โปรดยืนยันอีเมลของคุณก่อน", + "checkInboxAndSpamFolder": "โปรดตรวจสอบกล่องจดหมาย (และสแปม) ของคุณ เพื่อยืนยันให้เสร็จสิ้น", + "tapToEnterCode": "แตะเพื่อป้อนรหัส", + "resendEmail": "ส่งอีเมลอีกครั้ง", + "weHaveSendEmailTo": "เราได้ส่งจดหมายไปยัง {email}", + "@weHaveSendEmailTo": { + "description": "Text to indicate that we have sent a mail to the user", + "placeholders": { + "email": { + "description": "The email address of the user", + "type": "String", + "example": "example@ente.io" + } + } + }, + "setPasswordTitle": "ตั้งรหัสผ่าน", + "changePasswordTitle": "เปลี่ยนรหัสผ่าน", + "resetPasswordTitle": "รีเซ็ตรหัสผ่าน", + "passwordWarning": "เราไม่จัดเก็บรหัสผ่านนี้ ดังนั้นหากคุณลืม เราจะไม่สามารถถอดรหัสข้อมูลของคุณ", + "enterPasswordToEncrypt": "ใส่รหัสผ่านที่เราสามารถใช้เพื่อเข้ารหัสข้อมูลของคุณ", + "enterNewPasswordToEncrypt": "ใส่รหัสผ่านใหม่ที่เราสามารถใช้เพื่อเข้ารหัสข้อมูลของคุณ", + "weakStrength": "อ่อน", + "strongStrength": "แข็งแรง", + "moderateStrength": "ปานกลาง", + "passwordStrength": "ความแข็งแรงของรหัสผ่าน: {passwordStrengthValue}", + "@passwordStrength": { + "description": "Text to indicate the password strength", + "placeholders": { + "passwordStrengthValue": { + "description": "The strength of the password as a string", + "type": "String", + "example": "Weak or Moderate or Strong" + } + }, + "message": "Password Strength: {passwordStrengthText}" + }, + "passwordChangedSuccessfully": "เปลี่ยนรหัสผ่านสำเร็จ", + "pleaseWait": "กรุณารอสักครู่...", + "continueLabel": "ดำเนินการต่อ", + "insecureDevice": "อุปกรณ์ไม่ปลอดภัย", + "howItWorks": "วิธีการทำงาน", + "encryption": "การเข้ารหัส", + "ackPasswordLostWarning": "ฉันเข้าใจว่าหากฉันทำรหัสผ่านหาย ข้อมูลของฉันอาจสูญหายเนื่องจากข้อมูลของฉันมีการเข้ารหัสจากต้นทางถึงปลายทาง", + "privacyPolicyTitle": "นโยบายความเป็นส่วนตัว", + "termsOfServicesTitle": "เงื่อนไข", + "signUpTerms": "ฉันยอมรับเงื่อนไขการให้บริการและนโยบายความเป็นส่วนตัว", + "logInLabel": "เข้าสู่ระบบ", + "loginTerms": "โดยการคลิกเข้าสู่ระบบ ฉันยอมรับเงื่อนไขการให้บริการและนโยบายความเป็นส่วนตัว", + "changeEmail": "เปลี่ยนอีเมล", + "enterYourPassword": "ใส่รหัสผ่านของคุณ", + "welcomeBack": "ยินดีต้อนรับกลับมา!", + "contactSupport": "ติดต่อฝ่ายสนับสนุน", + "incorrectPasswordTitle": "รหัสผ่านไม่ถูกต้อง", + "pleaseTryAgain": "กรุณาลองอีกครั้ง", + "recreatePasswordTitle": "สร้างรหัสผ่านใหม่", + "useRecoveryKey": "ใช้คีย์การกู้คืน", + "recreatePasswordBody": "อุปกรณ์ปัจจุบันไม่ทรงพลังพอที่จะยืนยันรหัสผ่านของคุณ แต่เราสามารถสร้างใหม่ในลักษณะที่ใช้ได้กับอุปกรณ์ทั้งหมดได้\n\nกรุณาเข้าสู่ระบบโดยใช้คีย์การกู้คืนของคุณและสร้างรหัสผ่านใหม่ (คุณสามารถใช้รหัสเดิมอีกครั้งได้หากต้องการ)", + "verifyPassword": "ยืนยันรหัสผ่าน", + "recoveryKey": "คีย์การกู้คืน", + "recoveryKeyOnForgotPassword": "หากคุณลืมรหัสผ่าน วิธีเดียวที่คุณสามารถกู้คืนข้อมูลของคุณได้คือการใช้คีย์นี้", + "recoveryKeySaveDescription": "เราไม่จัดเก็บคีย์นี้ โปรดบันทึกคีย์ 24 คำนี้ไว้ในที่ที่ปลอดภัย", + "doThisLater": "ทำในภายหลัง", + "saveKey": "บันทึกคีย์", + "recoveryKeyCopiedToClipboard": "คัดลอกคีย์การกู้คืนไปยังคลิปบอร์ดแล้ว", + "recoverAccount": "กู้คืนบัญชี", + "recover": "กู้คืน", + "dropSupportEmail": "กรุณาส่งอีเมลไปที่ {supportEmail} จากที่อยู่อีเมลที่คุณลงทะเบียนไว้", + "@dropSupportEmail": { + "placeholders": { + "supportEmail": { + "description": "The support email address", + "type": "String", + "example": "support@ente.io" + } + } + }, + "twofactorSetup": "การตั้งค่าสองปัจจัย", + "enterCode": "ป้อนรหัส", + "scanCode": "สแกนรหัส", + "codeCopiedToClipboard": "คัดลอกรหัสไปยังคลิปบอร์ดแล้ว", + "tapToCopy": "แตะเพื่อคัดลอก", + "confirm": "ยืนยัน", + "setupComplete": "ตั้งค่าเสร็จสมบูรณ์", + "saveYourRecoveryKeyIfYouHaventAlready": "บันทึกคีย์การกู้คืนของคุณหากคุณยังไม่ได้ทำ", + "verifyingRecoveryKey": "กำลังยืนยันคีย์การกู้คืน...", + "recoveryKeyVerified": "ยืนยันคีย์การกู้คืนแล้ว", + "recoveryKeySuccessBody": "ยอดเยี่ยม! คีย์การกู้คืนของคุณถูกต้อง ขอบคุณสำหรับการยืนยัน\n\nโปรดอย่าลืมสำรองคีย์การกู้คืนของคุณไว้อย่างปลอดภัย", + "invalidRecoveryKey": "คีย์การกู้คืนที่คุณป้อนไม่ถูกต้อง โปรดตรวจสอบให้แน่ใจว่ามี 24 คำ และตรวจสอบการสะกดของแต่ละคำ\n\nหากคุณป้อนรหัสกู้คืนที่เก่ากว่า ตรวจสอบให้แน่ใจว่ามีความยาว 64 ตัวอักษร และตรวจสอบแต่ละตัวอักษร", + "invalidKey": "รหัสไม่ถูกต้อง", + "tryAgain": "ลองอีกครั้ง", + "viewRecoveryKey": "ดูคีย์การกู้คืน", + "confirmRecoveryKey": "ยืนยันคีย์การกู้คืน", + "recoveryKeyVerifyReason": "คีย์การกู้คืนเป็นวิธีเดียวที่จะกู้คืนรูปภาพของคุณหากคุณลืมรหัสผ่าน คุณสามารถหาคีย์การกู้คืนของคุณได้ในการตั้งค่า > ความปลอดภัย\n\nโปรดป้อนคีย์การกู้คืนของคุณที่นี่เพื่อยืนยันว่าคุณได้บันทึกไว้อย่างถูกต้อง", + "confirmYourRecoveryKey": "ยืนยันคีย์การกู้คืนของคุณ", + "addViewer": "เพิ่มผู้ชม", + "addCollaborator": "เพิ่มผู้ทำงานร่วมกัน", + "addANewEmail": "เพิ่มอีเมลใหม่", + "orPickAnExistingOne": "หรือเลือกที่มีอยู่แล้ว", + "enterEmail": "ใส่อีเมล", + "albumOwner": "เจ้าของ", + "@albumOwner": { + "description": "Role of the album owner" + }, + "you": "คุณ", + "addMore": "เพิ่มอีก", + "@addMore": { + "description": "Button text to add more collaborators/viewers" + }, + "allowAddingPhotos": "อนุญาตให้เพิ่มรูปภาพ", + "@allowAddingPhotos": { + "description": "Switch button to enable uploading photos to a public link" + }, + "allowDownloads": "อนุญาตให้ดาวน์โหลด", + "custom": "กำหนดเอง", + "@custom": { + "description": "Label for setting custom value for link expiry" + }, + "after1Hour": "หลังจาก 1 ชั่วโมง", + "after1Day": "หลังจาก 1 วัน", + "after1Week": "หลังจาก 1 สัปดาห์", + "after1Month": "หลังจาก 1 เดือน", + "after1Year": "หลังจาก 1 ปี", + "manageParticipants": "จัดการ", + "collectPhotos": "รวบรวมรูปภาพ", + "createPublicLink": "สร้างลิงก์สาธารณะ", + "sendLink": "ส่งลิงก์", + "copyLink": "คัดลอกลิงก์", + "linkHasExpired": "ลิงก์หมดอายุแล้ว", + "publicLinkEnabled": "เปิดใช้ลิงก์สาธารณะแล้ว", + "shareALink": "แชร์​ลิงก์", + "apply": "นำไปใช้", + "faq": "คำถามที่พบบ่อย", + "oopsSomethingWentWrong": "อ๊ะ มีบางอย่างผิดพลาด", + "peopleUsingYourCode": "ผู้คนที่ใช้รหัสของคุณ", + "eligible": "มีสิทธิ์", + "total": "รวม", + "importing": "กำลังนำเข้า....", + "trash": "ถังขยะ", + "uncategorized": "ไม่มีหมวดหมู่", + "videoSmallCase": "วิดีโอ", + "photoSmallCase": "รูปภาพ", + "waitingForWifi": "กำลังรอ WiFi...", + "status": "สถานะ", + "unselectAll": "ไม่เลือกทั้งหมด", + "selectAll": "เลือกทั้งหมด", + "skip": "ข้าม", + "itemCount": "{count, plural, other{{count} รายการ}}", + "deleteItemCount": "{count, plural, =1 {ลบ {count} รายการ} other {ลบ {count} รายการ}}", + "authToViewYourRecoveryKey": "โปรดตรวจสอบสิทธิ์เพื่อดูคีย์การกู้คืนของคุณ", + "lightTheme": "สว่าง", + "darkTheme": "มืด", + "systemTheme": "ระบบ", + "freeTrial": "ทดลองใช้ฟรี", + "@onEnte": { + "description": "The text displayed above albums backed up to Ente", + "type": "text" + }, + "onEnte": "บน ente", + "name": "ชื่อ", + "newest": "ใหม่สุด", + "lastUpdated": "อัปเดตล่าสุด", + "deleteEmptyAlbums": "ลบอัลบั้มที่ว่างเปล่า", + "deleteEmptyAlbumsWithQuestionMark": "ลบอัลบั้มที่ว่างเปล่าหรือไม่?", + "deleteProgress": "กำลังลบ {currentlyDeleting} / {totalCount}", + "genericProgress": "กำลังประมวลผล {currentlyProcessing} / {totalCount}", + "@genericProgress": { + "description": "Generic progress text to display when processing multiple items", + "type": "text", + "placeholders": { + "currentlyProcessing": { + "example": "1", + "type": "int" + }, + "totalCount": { + "example": "10", + "type": "int" + } + } + }, + "permanentlyDelete": "ลบอย่างถาวร", + "canOnlyCreateLinkForFilesOwnedByYou": "สามารถสร้างลิงก์ได้เฉพาะไฟล์ที่คุณเป็นเจ้าของ", + "publicLinkCreated": "สร้างลิงก์สาธารณะแล้ว", + "youCanManageYourLinksInTheShareTab": "คุณสามารถจัดการลิงก์ของคุณได้ในแท็บแชร์", + "linkCopiedToClipboard": "คัดลอกลิงก์ไปยังคลิปบอร์ดแล้ว", + "restore": " กู้คืน", + "@restore": { + "description": "Display text for an action which triggers a restore of item from trash", + "type": "text" + }, + "moveToAlbum": "ย้ายไปยังอัลบั้ม", + "unhide": "เลิกซ่อน", + "unarchive": "เลิกเก็บถาวร", + "favorite": "ชื่นชอบ", + "shareLink": "แชร์​ลิงก์", + "addToAlbum": "เพิ่มไปยังอัลบั้ม", + "delete": "ลบ", + "hide": "ซ่อน", + "share": "แชร์", + "unhideToAlbum": "เลิกซ่อนไปยังอัลบั้ม", + "restoreToAlbum": "กู้คืนไปยังอัลบั้ม", + "moveItem": "{count, plural, other {ย้ายรายการ}}", + "@moveItem": { + "description": "Page title while moving one or more items to an album" + }, + "addItem": "{count, plural, other {เพิ่มรายการ}}", + "@addItem": { + "description": "Page title while adding one or more items to album" + }, + "incorrectRecoveryKey": "คีย์การกู้คืนไม่ถูกต้อง", + "theRecoveryKeyYouEnteredIsIncorrect": "คีย์การกู้คืนที่คุณป้อนไม่ถูกต้อง", + "syncing": "กำลังซิงค์...", + "syncStopped": "หยุดการซิงค์แล้ว", + "loadMessage9": "เราใช้ Xchacha20Poly1305 เพื่อเข้ารหัสข้อมูลของคุณอย่างปลอดภัย", + "save": "บันทึก", + "edit": "แก้ไข", + "saveCopy": "บันทึกสำเนา", + "color": "สี", + "storageBreakupFamily": "ครอบครัว", + "storageBreakupYou": "คุณ", + "@storageBreakupYou": { + "description": "Label to indicate how much storage you are using when you are part of a family plan" + }, + "storageUsageInfo": "ใช้ไป {usedAmount} {usedStorageUnit} จาก {totalAmount} {totalStorageUnit}", + "@storageUsageInfo": { + "description": "Example: 1.2 GB of 2 GB used or 100 GB or 2TB used" + }, + "appVersion": "รุ่น: {versionValue}", + "verifyIDLabel": "ยืนยัน", + "fileInfoAddDescHint": "เพิ่มคำอธิบาย...", + "editLocationTagTitle": "แก้ไขตำแหน่ง", + "androidBiometricSuccess": "สำเร็จ", + "@androidBiometricSuccess": { + "description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters." + }, + "androidCancelButton": "ยกเลิก", + "@androidCancelButton": { + "description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters." + }, + "goToSettings": "ไปที่การตั้งค่า", + "@goToSettings": { + "description": "Message showed on a button that the user can click to go to settings pages from the current dialog. It is used on both Android and iOS side. Maximum 30 characters." + }, + "iOSOkButton": "ตกลง", + "@iOSOkButton": { + "description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters." + }, + "openstreetmapContributors": "ผู้มีส่วนร่วม OpenStreetMap", + "hostedAtOsmFrance": "โฮสต์ที่ OSM ฝรั่งเศส", + "map": "แผนที่", + "@map": { + "description": "Label for the map view" + }, + "maps": "แผนที่", + "enableMaps": "เปิดใช้งานแผนที่" +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ti.arb b/mobile/lib/l10n/intl_ti.arb new file mode 100644 index 0000000000..c8494661c6 --- /dev/null +++ b/mobile/lib/l10n/intl_ti.arb @@ -0,0 +1,3 @@ +{ + "@@locale ": "en" +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_tr.arb b/mobile/lib/l10n/intl_tr.arb index ffd6ec0f7c..a51913a120 100644 --- a/mobile/lib/l10n/intl_tr.arb +++ b/mobile/lib/l10n/intl_tr.arb @@ -1,4 +1,5 @@ { + "@@locale ": "en", "enterYourEmailAddress": "E-posta adresinizi girin", "accountWelcomeBack": "Tekrar hoş geldiniz!", "email": "E-Posta", @@ -23,7 +24,6 @@ "sendEmail": "E-posta gönder", "deleteRequestSLAText": "İsteğiniz 72 saat içinde gerçekleştirilecek.", "deleteEmailRequest": "Lütfen kayıtlı e-posta adresinizden account-deletion@ente.io'a e-posta gönderiniz.", - "entePhotosPerm": "Ente needs permission to preserve your photos", "ok": "Tamam", "createAccount": "Hesap oluşturun", "createNewAccount": "Yeni bir hesap oluşturun", @@ -225,17 +225,14 @@ }, "description": "Number of participants in an album, including the album owner." }, - "collabLinkSectionDescription": "Create a link to allow people to add and view photos in your shared album without needing an Ente app or account. Great for collecting event photos.", "collectPhotos": "Fotoğrafları topla", "collaborativeLink": "Organizasyon bağlantısı", - "shareWithNonenteUsers": "Share with non-Ente users", "createPublicLink": "Herkese açık link oluştur", "sendLink": "Link gönder", "copyLink": "Linki kopyala", "linkHasExpired": "Bağlantının süresi dolmuş", "publicLinkEnabled": "Herkese açık bağlantı aktive edildi", "shareALink": "Linki paylaş", - "sharedAlbumSectionDescription": "Create shared and collaborative albums with other Ente users, including users on free plans.", "shareWithPeopleSectionTitle": "{numberOfPeople, plural, =0 {Belirli kişilerle paylaş} =1 {1 kişiyle paylaşıldı} other {{numberOfPeople} kişiyle paylaşıldı}}", "@shareWithPeopleSectionTitle": { "placeholders": { @@ -259,12 +256,10 @@ }, "verificationId": "Doğrulama kimliği", "verifyEmailID": "{email} doğrula", - "emailNoEnteAccount": "{email} does not have an Ente account.\n\nSend them an invite to share photos.", "shareMyVerificationID": "İşte ente.io için doğrulama kimliğim: {verificationID}.", "shareTextConfirmOthersVerificationID": "Merhaba, bu ente.io doğrulama kimliğinizin doğruluğunu onaylayabilir misiniz: {verificationID}", "somethingWentWrong": "Bazı şeyler yanlış gitti", "sendInvite": "Davet kodu gönder", - "shareTextRecommendUsingEnte": "Download Ente so we can easily share original quality photos and videos\n\nhttps://ente.io", "done": "Bitti", "applyCodeTitle": "Kodu girin", "enterCodeDescription": "Arkadaşınız tarafından sağlanan kodu girerek hem sizin hem de arkadaşınızın ücretsiz depolamayı talep etmek için girin", @@ -281,7 +276,6 @@ "claimMore": "Arttır!", "theyAlsoGetXGb": "Aynı zamanda {storageAmountInGB} GB alıyorlar", "freeStorageOnReferralSuccess": "Birisinin davet kodunuzu uygulayıp ücretli hesap açtığı her seferede {storageAmountInGB} GB", - "shareTextReferralCode": "Ente referral code: {referralCode} \n\nApply it in Settings → General → Referrals to get {referralStorageInGB} GB free after you signup for a paid plan\n\nhttps://ente.io", "claimFreeStorage": "Bedava alan talep edin", "inviteYourFriends": "Arkadaşlarını davet et", "failedToFetchReferralDetails": "Davet ayrıntıları çekilemedi. Iütfen daha sonra deneyin.", @@ -334,7 +328,6 @@ "removeParticipantBody": "{userEmail} bu paylaşılan albümden kaldırılacaktır\n\nOnlar tarafından eklenen tüm fotoğraflar da albümden kaldırılacaktır", "keepPhotos": "Fotoğrafları sakla", "deletePhotos": "Fotoğrafları sil", - "inviteToEnte": "Invite to Ente", "removePublicLink": "Herkese açık link oluştur", "disableLinkMessage": "Bu, \"{albumName}\"e erişim için olan genel bağlantıyı kaldıracaktır.", "sharing": "Paylaşılıyor...", @@ -350,10 +343,7 @@ "videoSmallCase": "video", "photoSmallCase": "fotoğraf", "singleFileDeleteHighlight": "Tüm albümlerden silinecek.", - "singleFileInBothLocalAndRemote": "This {fileType} is in both Ente and your device.", - "singleFileInRemoteOnly": "This {fileType} will be deleted from Ente.", "singleFileDeleteFromDevice": "Bu {fileType}, cihazınızdan silinecek.", - "deleteFromEnte": "Delete from Ente", "yesDelete": "Evet, sil", "movedToTrash": "Cöp kutusuna taşı", "deleteFromDevice": "Cihazınızdan silin", @@ -409,7 +399,6 @@ "manageDeviceStorage": "Cihaz depolamasını yönet", "machineLearning": "Makine öğrenimi", "magicSearch": "Sihirli arama", - "mlIndexingDescription": "Please note that machine learning will result in a higher bandwidth and battery usage until all items are indexed.", "loadingModel": "Modeller indiriliyor...", "waitingForWifi": "WiFi bekleniyor...", "status": "Durum", @@ -445,13 +434,11 @@ "backupOverMobileData": "Mobil veri ile yedekle", "backupVideos": "Videolari yedekle", "disableAutoLock": "Otomatik kilidi devre dışı bırak", - "deviceLockExplanation": "Disable the device screen lock when Ente is in the foreground and there is a backup in progress. This is normally not needed, but may help big uploads and initial imports of large libraries complete faster.", "about": "Hakkında", "weAreOpenSource": "Biz açık kaynağız!", "privacy": "Gizlilik", "terms": "Şartlar", "checkForUpdates": "Güncellemeleri kontol et", - "checkStatus": "Check status", "checking": "Kontrol ediliyor...", "youAreOnTheLatestVersion": "En son sürüme sahipsiniz", "account": "Hesap", @@ -466,7 +453,6 @@ "authToInitiateAccountDeletion": "Hesap silme işlemini başlatmak için lütfen kimlik doğrulaması yapın", "areYouSureYouWantToLogout": "Çıkış yapmak istediğinize emin misiniz?", "yesLogout": "Evet, oturumu kapat", - "aNewVersionOfEnteIsAvailable": "A new version of Ente is available.", "update": "Güncelle", "installManually": "Manuel kurulum", "criticalUpdateAvailable": "Kritik güncelleme mevcut", @@ -479,13 +465,9 @@ "backedUpFolders": "Yedeklenmiş klasörler", "backup": "Yedekle", "freeUpDeviceSpace": "Cihaz alanını boşaltın", - "freeUpDeviceSpaceDesc": "Save space on your device by clearing files that have been already backed up.", "allClear": "✨ Tamamen temizle", "noDeviceThatCanBeDeleted": "Bu cihazda silinebilecek hiçbir dosyanız yok", "removeDuplicates": "Yinelenenleri kaldır", - "removeDuplicatesDesc": "Review and remove files that are exact duplicates.", - "viewLargeFiles": "Large files", - "viewLargeFilesDesc": "View files that are consuming the most amount of storage", "noDuplicates": "Yinelenenleri kaldır", "youveNoDuplicateFilesThatCanBeCleared": "Temizlenebilecek yinelenen dosyalarınız yok", "success": "Başarılı", @@ -558,7 +540,6 @@ "systemTheme": "Sistem", "freeTrial": "Ücretsiz deneme", "selectYourPlan": "Planınızı seçin", - "enteSubscriptionPitch": "Ente preserves your memories, so they're always available to you, even if you lose your device.", "enteSubscriptionShareWithFamily": "Aileniz de planınıza eklenebilir.", "currentUsageIs": "Güncel kullanımınız ", "@currentUsageIs": { @@ -573,7 +554,6 @@ "freeTrialValidTill": "Ücretsiz deneme {endDate} sona erir", "validTill": "{endDate} tarihine kadar geçerli", "addOnValidTill": "{storageAmount} eklentiniz {endDate} tarihine kadar geçerlidir", - "playStoreFreeTrialValidTill": "Free trial valid till {endDate}.\nYou can choose a paid plan afterwards.", "subWillBeCancelledOn": "Aboneliğiniz {endDate} tarihinde iptal edilecektir", "subscription": "Abonelik", "paymentDetails": "Ödeme detayları", @@ -624,7 +604,6 @@ "appleId": "Apple kimliği", "playstoreSubscription": "PlayStore aboneliği", "appstoreSubscription": "PlayStore aboneliği", - "subAlreadyLinkedErrMessage": "Your {id} is already linked to another Ente account.\nIf you would like to use your {id} with this account, please contact our support''", "visitWebToManage": "Aboneliğinizi yönetmek için lütfen web.ente.io adresini ziyaret edin", "couldNotUpdateSubscription": "Abonelikler kaydedilemedi", "pleaseContactSupportAndWeWillBeHappyToHelp": "Lütfen support@ente.io ile iletişime geçin; size yardımcı olmaktan memnuniyet duyarız!", @@ -669,9 +648,7 @@ "everywhere": "her yerde", "androidIosWebDesktop": "Android, iOS, Web, Masaüstü", "mobileWebDesktop": "Mobil, Web, Masaüstü", - "newToEnte": "New to Ente", "pleaseLoginAgain": "Lütfen tekrar giriş yapın", - "autoLogoutMessage": "Due to technical glitch, you have been logged out. Our apologies for the inconvenience.", "yourSubscriptionHasExpired": "Aboneliğinizin süresi doldu", "storageLimitExceeded": "Depolama sınırı aşıldı", "upgrade": "Yükselt", @@ -682,12 +659,10 @@ }, "backupFailed": "Yedekleme başarısız oldu", "couldNotBackUpTryLater": "Verilerinizi yedekleyemedik.\nDaha sonra tekrar deneyeceğiz.", - "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": "Ente can encrypt and preserve files only if you grant access to them", "pleaseGrantPermissions": "Lütfen izin ver", "grantPermission": "İzinleri değiştir", "privateSharing": "Özel paylaşım", "shareOnlyWithThePeopleYouWant": "Yalnızca istediğiniz kişilerle paylaşın", - "usePublicLinksForPeopleNotOnEnte": "Use public links for people not on Ente", "allowPeopleToAddPhotos": "Kullanıcıların fotoğraf eklemesine izin ver", "shareAnAlbumNow": "Şimdi bir albüm paylaşın", "collectEventPhotos": "Etkinlik fotoğraflarını topla", @@ -739,13 +714,11 @@ "unhide": "Gizleme", "unarchive": "Arşivden cıkar", "favorite": "Favori", - "removeFromFavorite": "Favorilerimden kaldır", "shareLink": "Linki paylaş", "createCollage": "Kolaj oluştur", "saveCollage": "Kolajı kaydet", "collageSaved": "Kolajınız galeriye kaydedildi", "collageLayout": "Düzen", - "addToEnte": "Add to Ente", "addToAlbum": "Albüme ekle", "delete": "Sil", "hide": "Gizle", @@ -810,10 +783,7 @@ "photosAddedByYouWillBeRemovedFromTheAlbum": "Eklediğiniz fotoğraflar albümden kaldırılacak", "youveNoFilesInThisAlbumThatCanBeDeleted": "Bu cihazda silinebilecek hiçbir dosyanız yok", "youDontHaveAnyArchivedItems": "Arşivlenmiş öğeniz yok.", - "ignoredFolderUploadReason": "Some files in this album are ignored from upload because they had previously been deleted from Ente.", "resetIgnoredFiles": "Yok sayılan dosyaları sıfırla", - "deviceFilesAutoUploading": "Files added to this device album will automatically get uploaded to Ente.", - "turnOnBackupForAutoUpload": "Turn on backup to automatically upload files added to this device folder to Ente.", "noHiddenPhotosOrVideos": "Gizli fotoğraf veya video yok", "toHideAPhotoOrVideo": "Bir fotoğrafı veya videoyu gizlemek için", "openTheItem": "• Öğeyi açın", @@ -839,7 +809,6 @@ "close": "Kapat", "setAs": "Şu şekilde ayarla", "fileSavedToGallery": "Video galeriye kaydedildi", - "filesSavedToGallery": "Files saved to gallery", "fileFailedToSaveToGallery": "Dosya galeriye kaydedilemedi", "download": "İndir", "pressAndHoldToPlayVideo": "Videoları yönetmek için basılı tutun", @@ -891,15 +860,6 @@ "@freeUpSpaceSaving": { "description": "Text to tell user how much space they can free up by deleting items from the device" }, - "freeUpAccessPostDelete": "You can still access {count, plural, one {it} other {them}} on Ente as long as you have an active subscription", - "@freeUpAccessPostDelete": { - "placeholders": { - "count": { - "example": "1", - "type": "int" - } - } - }, "freeUpAmount": "{sizeInMBorGB} yer açın", "thisEmailIsAlreadyInUse": "Bu e-posta zaten kullanılıyor", "incorrectCode": "Yanlış kod", @@ -942,7 +902,6 @@ "renameFile": "Dosyayı yeniden adlandır", "enterFileName": "Dosya adını girin", "filesDeleted": "Dosyalar silinmiş", - "selectedFilesAreNotOnEnte": "Selected files are not on Ente", "thisActionCannotBeUndone": "Bu eylem geri alınamaz", "emptyTrash": "Çöp kutusu boşaltılsın mı?", "permDeleteWarning": "Çöp kutusundaki tüm öğeler kalıcı olarak silinecek\n\nBu işlem geri alınamaz", @@ -951,7 +910,6 @@ "permanentlyDeleteFromDevice": "Cihazdan kalıcı olarak silinsin mi?", "someOfTheFilesYouAreTryingToDeleteAre": "Silmeye çalıştığınız dosyalardan bazıları yalnızca cihazınızda mevcuttur ve silindiği takdirde kurtarılamaz", "theyWillBeDeletedFromAllAlbums": "Tüm albümlerden silinecek.", - "someItemsAreInBothEnteAndYourDevice": "Some items are in both Ente and your device.", "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": "Seçilen öğeler tüm albümlerden silinecek ve çöp kutusuna taşınacak.", "theseItemsWillBeDeletedFromYourDevice": "Bu öğeler cihazınızdan silinecektir.", "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Bir şeyler ters gitmiş gibi görünüyor. Lütfen bir süre sonra tekrar deneyin. Hata devam ederse, lütfen destek ekibimizle iletişime geçin.", @@ -991,7 +949,6 @@ "fileTypesAndNames": "Dosya türleri ve adları", "location": "Konum", "moments": "Anlar", - "searchFaceEmptySection": "People will be shown here once indexing is done", "searchDatesEmptySection": "Tarihe, aya veya yıla göre arama yapın", "searchLocationEmptySection": "Bir fotoğrafın belli bir yarıçapında çekilen fotoğrafları gruplandırın", "searchPeopleEmptySection": "İnsanları davet ettiğinizde onların paylaştığı tüm fotoğrafları burada göreceksiniz", @@ -1046,7 +1003,6 @@ "@storageUsageInfo": { "description": "Example: 1.2 GB of 2 GB used or 100 GB or 2TB used" }, - "availableStorageSpace": "{freeAmount} {storageUnit} free", "appVersion": "Sürüm: {versionValue}", "verifyIDLabel": "Doğrula", "fileInfoAddDescHint": "Bir açıklama ekle...", @@ -1057,7 +1013,6 @@ }, "setRadius": "Yarıçapı ayarla", "familyPlanPortalTitle": "Aile", - "familyPlanOverview": "Add 5 family members to your existing plan without paying extra.\n\nEach member gets their own private space, and cannot see each other's files unless they're shared.\n\nFamily plans are available to customers who have a paid Ente subscription.\n\nSubscribe now to get started!", "androidBiometricHint": "Kimliği doğrula", "@androidBiometricHint": { "description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters." @@ -1135,7 +1090,6 @@ "noAlbumsSharedByYouYet": "Henüz paylaştığınız albüm yok", "sharedWithYou": "Sizinle paylaşıldı", "sharedByYou": "Paylaştıklarınız", - "inviteYourFriendsToEnte": "Invite your friends to Ente", "failedToDownloadVideo": "Video indirilemedi", "hiding": "Gizleniyor...", "unhiding": "Gösteriliyor...", @@ -1145,7 +1099,6 @@ "addToHiddenAlbum": "Gizli albüme ekle", "moveToHiddenAlbum": "Gizli albüme ekle", "fileTypes": "Dosya türü", - "deleteConfirmDialogBody": "This account is linked to other Ente apps, if you use any. Your uploaded data, across all Ente apps, will be scheduled for deletion, and your account will be permanently deleted.", "hearUsWhereTitle": "Ente'yi nereden duydunuz? (opsiyonel)", "hearUsExplanation": "Biz uygulama kurulumlarını takip etmiyoruz. Bizi nereden duyduğunuzdan bahsetmeniz bize çok yardımcı olacak!", "viewAddOnButton": "Eklentileri görüntüle", @@ -1175,7 +1128,6 @@ } }, "faces": "Yüzler", - "people": "People", "contents": "İçerikler", "addNew": "Yeni ekle", "@addNew": { @@ -1198,9 +1150,6 @@ "waitingForVerification": "Doğrulama bekleniyor...", "passkey": "Parola Anahtarı", "passkeyAuthTitle": "Geçiş anahtarı doğrulaması", - "passKeyPendingVerification": "Verification is still pending", - "loginSessionExpired": "Session expired", - "loginSessionExpiredDetails": "Your session has expired. Please login again.", "verifyPasskey": "Şifrenizi doğrulayın", "playOnTv": "Albümü TV'de oynat", "pair": "Eşleştir", @@ -1210,8 +1159,6 @@ "joinDiscord": "Discord'a Katıl", "locations": "Konum", "descriptions": "Açıklama", - "addAName": "Add a name", - "findPeopleByName": "Find people quickly by name", "addViewers": "{count, plural, zero {Görüntüleyen ekle} one {Görüntüleyen ekle} other {Görüntüleyen ekle}}", "addCollaborators": "{count, plural, zero {Ortak çalışan ekle} one {Ortak çalışan ekle} other {Ortak çalışan ekle}}", "longPressAnEmailToVerifyEndToEndEncryption": "Uçtan uca şifrelemeyi doğrulamak için bir e-postaya uzun basın.", @@ -1221,82 +1168,5 @@ "invalidEndpoint": "Geçersiz uç nokta", "invalidEndpointMessage": "Üzgünüz, girdiğiniz uç nokta geçersiz. Lütfen geçerli bir uç nokta girin ve tekrar deneyin.", "endpointUpdatedMessage": "Fatura başarıyla güncellendi", - "customEndpoint": "{endpoint}'e bağlanıldı", - "createCollaborativeLink": "Create collaborative link", - "search": "Search", - "enterPersonName": "Enter person name", - "removePersonLabel": "Remove person label", - "autoPairDesc": "Auto pair works only with devices that support Chromecast.", - "manualPairDesc": "Pair with PIN works with any screen you wish to view your album on.", - "connectToDevice": "Connect to device", - "autoCastDialogBody": "You'll see available Cast devices here.", - "autoCastiOSPermission": "Make sure Local Network permissions are turned on for the Ente Photos app, in Settings.", - "noDeviceFound": "No device found", - "stopCastingTitle": "Stop casting", - "stopCastingBody": "Do you want to stop casting?", - "castIPMismatchTitle": "Failed to cast album", - "castIPMismatchBody": "Please make sure you are on the same network as the TV.", - "pairingComplete": "Pairing complete", - "savingEdits": "Saving edits...", - "autoPair": "Auto pair", - "pairWithPin": "Pair with PIN", - "faceRecognition": "Face recognition", - "foundFaces": "Found faces", - "clusteringProgress": "Clustering progress", - "indexingIsPaused": "Indexing is paused. It will automatically resume when device is ready.", - "trim": "Trim", - "crop": "Crop", - "rotate": "Rotate", - "left": "Left", - "right": "Right", - "whatsNew": "What's new", - "reviewSuggestions": "Review suggestions", - "useAsCover": "Use as cover", - "notPersonLabel": "Not {name}?", - "@notPersonLabel": { - "description": "Label to indicate that the person in the photo is not the person whose name is mentioned", - "placeholders": { - "name": { - "content": "{name}", - "type": "String" - } - } - }, - "reenterPassword": "Re-enter password", - "reenterPin": "Re-enter PIN", - "deviceLock": "Device lock", - "pinLock": "PIN lock", - "next": "Next", - "setNewPassword": "Set new password", - "enterPin": "Enter PIN", - "setNewPin": "Set new PIN", - "appLock": "App lock", - "noSystemLockFound": "No system lock found", - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "To enable app lock, please setup device passcode or screen lock in your system settings.", - "tapToUnlock": "Tap to unlock", - "tooManyIncorrectAttempts": "Too many incorrect attempts", - "appLockDescription": "Choose between your device\\'s default lock screen and a custom lock screen with a PIN or password.", - "swipeLockEnablePreSteps": "To enable swipe lock, please setup device passcode or screen lock in your system settings.", - "autoLock": "Auto lock", - "immediately": "Immediately", - "autoLockFeatureDescription": "Time after which the app locks after being put in the background", - "hideContent": "Hide content", - "hideContentDescriptionAndroid": "Hides app content in the app switcher and disables screenshots", - "hideContentDescriptionIos": "Hides app content in the app switcher", - "passwordStrengthInfo": "Password strength is calculated considering the length of the password, used characters, and whether or not the password appears in the top 10,000 most used passwords", - "noQuickLinksSelected": "No quick links selected", - "pleaseSelectQuickLinksToRemove": "Please select quick links to remove", - "removePublicLinks": "Remove public links", - "thisWillRemovePublicLinksOfAllSelectedQuickLinks": "This will remove public links of all selected quick links.", - "guestView": "Guest view", - "guestViewEnablePreSteps": "To enable guest view, please setup device passcode or screen lock in your system settings.", - "cl_guest_view_title": "Misafir Görünümü", - "cl_guest_view_description": "Telefonunuzu bir arkadaşınıza fotoğraf göstermek için mi veriyorsunuz? Fazla kaydırmasından endişelenmeyin. Misafir görünümü seçtiğiniz fotoğraflarla sınırlı kalır.", - "cl_guest_view_call_to_action": "Fotoğrafları seçin ve \"Misafir Görünümü\"nü deneyin.", - "cl_panorama_viewer_title": "Panorama Görüntüleyici", - "cl_panorama_viewer_description": "360 derece görüşe sahip panorama fotoğrafları görüntüleme desteği ekledik. Hareket tabanlı gezinme ile etkileyici bir deneyim sunar!", - "cl_video_player_title": "Video Oynatıcı", - "cl_video_player_description": "Geliştirilmiş oynatma kontrolleri ve HDR video desteği ile yeni bir video oynatıcı sunuyoruz.", - "appLockDescriptions": "Choose between your device's default lock screen and a custom lock screen with a PIN or password.", - "authToViewPasskey": "Please authenticate to view your passkey" + "customEndpoint": "{endpoint}'e bağlanıldı" } \ No newline at end of file From b0379e8945ce17f2d7b464b0094a496fd9928821 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 14:28:51 +0530 Subject: [PATCH 039/275] [mob] Fix missing magic search --- .../semantic_search_service.dart | 38 +++++++------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/mobile/lib/services/machine_learning/semantic_search/semantic_search_service.dart b/mobile/lib/services/machine_learning/semantic_search/semantic_search_service.dart index 3c06bfc31d..7beb284df7 100644 --- a/mobile/lib/services/machine_learning/semantic_search/semantic_search_service.dart +++ b/mobile/lib/services/machine_learning/semantic_search/semantic_search_service.dart @@ -36,8 +36,8 @@ class SemanticSearchService { bool _hasInitialized = false; bool _textModelIsLoaded = false; - bool _isCacheRefreshPending = true; - List _cachedImageEmbeddings = []; + + Future>? _cachedImageEmbeddings; Future<(String, List)>? _searchScreenRequest; String? _latestPendingQuery; @@ -51,28 +51,28 @@ class SemanticSearchService { } _hasInitialized = true; - await _refreshClipCache(); + // call getClipEmbeddings after 5 seconds + Future.delayed(const Duration(seconds: 5), () async { + await getClipEmbeddings(); + }); Bus.instance.on().listen((event) { - _isCacheRefreshPending = true; + _cachedImageEmbeddings = null; }); unawaited(_loadTextModel(delay: true)); } bool isMagicSearchEnabledAndReady() { - return localSettings.isMLIndexingEnabled && - _textModelIsLoaded && - _cachedImageEmbeddings.isNotEmpty; + return localSettings.isMLIndexingEnabled && _textModelIsLoaded; } // searchScreenQuery should only be used for the user initiate query on the search screen. // If there are multiple call tho this method, then for all the calls, the result will be the same as the last query. Future<(String, List)> searchScreenQuery(String query) async { - await _refreshClipCache(); if (!isMagicSearchEnabledAndReady()) { if (flagService.internalUser) { _logger.info( - "Magic search enabled ${localSettings.isMLIndexingEnabled}, loaded $_textModelIsLoaded cached ${_cachedImageEmbeddings.isNotEmpty}", + "Magic search enabled ${localSettings.isMLIndexingEnabled}, loaded $_textModelIsLoaded ", ); } return (query, []); @@ -106,21 +106,10 @@ class SemanticSearchService { _logger.info("Indexes cleared"); } - Future _refreshClipCache() async { - if (_isCacheRefreshPending == false) { - return; - } - _isCacheRefreshPending = false; + Future> getClipEmbeddings() async { _logger.info("Pulling cached embeddings"); - final startTime = DateTime.now(); - _cachedImageEmbeddings = await MLDataDB.instance.getAll(); - final endTime = DateTime.now(); - _logger.info( - "Loading ${_cachedImageEmbeddings.length} took: ${(endTime.millisecondsSinceEpoch - startTime.millisecondsSinceEpoch)}ms", - ); - Bus.instance.fire(EmbeddingCacheUpdatedEvent()); - _logger - .info("Cached embeddings: " + _cachedImageEmbeddings.length.toString()); + _cachedImageEmbeddings ??= MLDataDB.instance.getAll(); + return _cachedImageEmbeddings!; } Future> getMatchingFiles( @@ -278,10 +267,11 @@ class SemanticSearchService { double? minimumSimilarity, }) async { final startTime = DateTime.now(); + final embeddings = await getClipEmbeddings(); final List queryResults = await _computer.compute( computeBulkSimilarities, param: { - "imageEmbeddings": _cachedImageEmbeddings, + "imageEmbeddings": embeddings, "textEmbedding": textEmbedding, "minimumSimilarity": minimumSimilarity, }, From 71034775983126217164725f72f2b8e10d91e844 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 16:25:27 +0530 Subject: [PATCH 040/275] [server] Reduce filedata delete worker count to 1 --- server/pkg/controller/filedata/delete.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/pkg/controller/filedata/delete.go b/server/pkg/controller/filedata/delete.go index a610282095..c46eba9d66 100644 --- a/server/pkg/controller/filedata/delete.go +++ b/server/pkg/controller/filedata/delete.go @@ -15,7 +15,7 @@ import ( // StartDataDeletion clears associated file data from the object store func (c *Controller) StartDataDeletion() { - go c.startDeleteWorkers(5) + go c.startDeleteWorkers(1) } func (c *Controller) startDeleteWorkers(n int) { @@ -24,7 +24,7 @@ func (c *Controller) startDeleteWorkers(n int) { for i := 0; i < n; i++ { go c.delete(i) // Stagger the workers - time.Sleep(time.Duration(2*i+1) * time.Second) + time.Sleep(time.Duration(2*i+1) * time.Minute) } } From e25d439b9b2b4fd9693a4922758748bbd8f49339 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 16:28:27 +0530 Subject: [PATCH 041/275] [server] Update validation for storage bonus --- server/ente/admin.go | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/server/ente/admin.go b/server/ente/admin.go index 0085ae95d8..edff1f6a2a 100644 --- a/server/ente/admin.go +++ b/server/ente/admin.go @@ -116,16 +116,21 @@ func (u SupportUpdateBonus) Validate() error { return errors.New("invalid input, set in MB and minute for test") } } else { - if u.StorageInGB != 200 && u.StorageInGB != 2000 && u.StorageInGB != 1000 { - return errors.New("invalid input for deal, only 200, 1000, 2000 allowed") - } + if isSupportBonus { if u.Year == 0 || u.Year > 100 { return errors.New("invalid input for year, only 1-100") } - } else if u.Year != 3 && u.Year != 5 { - return errors.New("invalid input for year, only 3 or 5") - + if u.StorageInGB == 0 || u.StorageInGB > 2000 { + return errors.New("invalid GB storage, only 1-2000") + } + } else { + if u.StorageInGB != 200 && u.StorageInGB != 2000 && u.StorageInGB != 1000 && u.StorageInGB != 50 { + return errors.New("invalid input for deal, only 50, 200, 1000, 2000 allowed") + } + if u.Year != 3 && u.Year != 5 { + return errors.New("invalid input for year, only 3 or 5") + } } } } From 520d893fd278e24f7ca6bcc6e3398ee99fe38012 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 18:05:36 +0530 Subject: [PATCH 042/275] Show ML option only on desktop --- .../src/components/Sidebar/Preferences.tsx | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/web/apps/photos/src/components/Sidebar/Preferences.tsx b/web/apps/photos/src/components/Sidebar/Preferences.tsx index 41c8a5886d..81cd1f9482 100644 --- a/web/apps/photos/src/components/Sidebar/Preferences.tsx +++ b/web/apps/photos/src/components/Sidebar/Preferences.tsx @@ -8,6 +8,7 @@ import { type SupportedLocale, } from "@/base/i18n"; import { MLSettings } from "@/new/photos/components/MLSettings"; +import { isMLSupported } from "@/new/photos/services/ml"; import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; import ChevronRight from "@mui/icons-material/ChevronRight"; import ScienceIcon from "@mui/icons-material/Science"; @@ -78,19 +79,21 @@ export const Preferences: React.FC = ({ endIcon={} label={t("advanced")} /> - - } - /> - - } - onClick={() => setOpenMLSettings(true)} - label={t("ml_search")} + {isMLSupported && ( + + } /> - - + + } + onClick={() => setOpenMLSettings(true)} + label={t("ml_search")} + /> + + + )} From 0f47842b5fceadafccbac38eefab85ca0e973410 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 18:13:17 +0530 Subject: [PATCH 043/275] [mob] generated files --- mobile/lib/generated/intl/messages_all.dart | 68 + mobile/lib/generated/intl/messages_ar.dart | 67 + mobile/lib/generated/intl/messages_bg.dart | 25 + mobile/lib/generated/intl/messages_ca.dart | 25 + mobile/lib/generated/intl/messages_cs.dart | 100 +- mobile/lib/generated/intl/messages_da.dart | 142 ++ mobile/lib/generated/intl/messages_de.dart | 214 ++- mobile/lib/generated/intl/messages_el.dart | 28 + mobile/lib/generated/intl/messages_en.dart | 212 +-- mobile/lib/generated/intl/messages_es.dart | 304 ++-- mobile/lib/generated/intl/messages_et.dart | 25 + mobile/lib/generated/intl/messages_fa.dart | 441 ++++++ mobile/lib/generated/intl/messages_fr.dart | 553 ++++--- mobile/lib/generated/intl/messages_gu.dart | 25 + mobile/lib/generated/intl/messages_he.dart | 975 +++++++++++++ mobile/lib/generated/intl/messages_hi.dart | 113 ++ mobile/lib/generated/intl/messages_id.dart | 1448 +++++++++++++++++++ mobile/lib/generated/intl/messages_it.dart | 381 ++--- mobile/lib/generated/intl/messages_ja.dart | 25 + mobile/lib/generated/intl/messages_km.dart | 25 + mobile/lib/generated/intl/messages_ko.dart | 118 +- mobile/lib/generated/intl/messages_nl.dart | 274 ++-- mobile/lib/generated/intl/messages_no.dart | 499 +++++-- mobile/lib/generated/intl/messages_pl.dart | 214 +-- mobile/lib/generated/intl/messages_pt.dart | 216 +-- mobile/lib/generated/intl/messages_ru.dart | 302 ++-- mobile/lib/generated/intl/messages_sv.dart | 548 +++++++ mobile/lib/generated/intl/messages_te.dart | 25 + mobile/lib/generated/intl/messages_th.dart | 365 +++++ mobile/lib/generated/intl/messages_ti.dart | 25 + mobile/lib/generated/intl/messages_tr.dart | 402 ++--- mobile/lib/generated/intl/messages_zh.dart | 256 ++-- mobile/lib/generated/l10n.dart | 17 + mobile/pubspec.yaml | 2 +- 34 files changed, 6429 insertions(+), 2030 deletions(-) create mode 100644 mobile/lib/generated/intl/messages_ar.dart create mode 100644 mobile/lib/generated/intl/messages_bg.dart create mode 100644 mobile/lib/generated/intl/messages_ca.dart create mode 100644 mobile/lib/generated/intl/messages_da.dart create mode 100644 mobile/lib/generated/intl/messages_el.dart create mode 100644 mobile/lib/generated/intl/messages_et.dart create mode 100644 mobile/lib/generated/intl/messages_fa.dart create mode 100644 mobile/lib/generated/intl/messages_gu.dart create mode 100644 mobile/lib/generated/intl/messages_he.dart create mode 100644 mobile/lib/generated/intl/messages_hi.dart create mode 100644 mobile/lib/generated/intl/messages_id.dart create mode 100644 mobile/lib/generated/intl/messages_ja.dart create mode 100644 mobile/lib/generated/intl/messages_km.dart create mode 100644 mobile/lib/generated/intl/messages_sv.dart create mode 100644 mobile/lib/generated/intl/messages_te.dart create mode 100644 mobile/lib/generated/intl/messages_th.dart create mode 100644 mobile/lib/generated/intl/messages_ti.dart diff --git a/mobile/lib/generated/intl/messages_all.dart b/mobile/lib/generated/intl/messages_all.dart index e274c0ccdb..fee2ce02b3 100644 --- a/mobile/lib/generated/intl/messages_all.dart +++ b/mobile/lib/generated/intl/messages_all.dart @@ -16,53 +16,113 @@ import 'package:intl/intl.dart'; import 'package:intl/message_lookup_by_library.dart'; import 'package:intl/src/intl_helpers.dart'; +import 'messages_ar.dart' as messages_ar; +import 'messages_bg.dart' as messages_bg; +import 'messages_ca.dart' as messages_ca; import 'messages_cs.dart' as messages_cs; +import 'messages_da.dart' as messages_da; import 'messages_de.dart' as messages_de; +import 'messages_el.dart' as messages_el; import 'messages_en.dart' as messages_en; import 'messages_es.dart' as messages_es; +import 'messages_et.dart' as messages_et; +import 'messages_fa.dart' as messages_fa; import 'messages_fr.dart' as messages_fr; +import 'messages_gu.dart' as messages_gu; +import 'messages_he.dart' as messages_he; +import 'messages_hi.dart' as messages_hi; +import 'messages_id.dart' as messages_id; import 'messages_it.dart' as messages_it; +import 'messages_ja.dart' as messages_ja; +import 'messages_km.dart' as messages_km; import 'messages_ko.dart' as messages_ko; import 'messages_nl.dart' as messages_nl; import 'messages_no.dart' as messages_no; import 'messages_pl.dart' as messages_pl; import 'messages_pt.dart' as messages_pt; import 'messages_ru.dart' as messages_ru; +import 'messages_sv.dart' as messages_sv; +import 'messages_te.dart' as messages_te; +import 'messages_th.dart' as messages_th; +import 'messages_ti.dart' as messages_ti; import 'messages_tr.dart' as messages_tr; import 'messages_zh.dart' as messages_zh; typedef Future LibraryLoader(); Map _deferredLibraries = { + 'ar': () => new SynchronousFuture(null), + 'bg': () => new SynchronousFuture(null), + 'ca': () => new SynchronousFuture(null), 'cs': () => new SynchronousFuture(null), + 'da': () => new SynchronousFuture(null), 'de': () => new SynchronousFuture(null), + 'el': () => new SynchronousFuture(null), 'en': () => new SynchronousFuture(null), 'es': () => new SynchronousFuture(null), + 'et': () => new SynchronousFuture(null), + 'fa': () => new SynchronousFuture(null), 'fr': () => new SynchronousFuture(null), + 'gu': () => new SynchronousFuture(null), + 'he': () => new SynchronousFuture(null), + 'hi': () => new SynchronousFuture(null), + 'id': () => new SynchronousFuture(null), 'it': () => new SynchronousFuture(null), + 'ja': () => new SynchronousFuture(null), + 'km': () => new SynchronousFuture(null), 'ko': () => new SynchronousFuture(null), 'nl': () => new SynchronousFuture(null), 'no': () => new SynchronousFuture(null), 'pl': () => new SynchronousFuture(null), 'pt': () => new SynchronousFuture(null), 'ru': () => new SynchronousFuture(null), + 'sv': () => new SynchronousFuture(null), + 'te': () => new SynchronousFuture(null), + 'th': () => new SynchronousFuture(null), + 'ti': () => new SynchronousFuture(null), 'tr': () => new SynchronousFuture(null), 'zh': () => new SynchronousFuture(null), }; MessageLookupByLibrary? _findExact(String localeName) { switch (localeName) { + case 'ar': + return messages_ar.messages; + case 'bg': + return messages_bg.messages; + case 'ca': + return messages_ca.messages; case 'cs': return messages_cs.messages; + case 'da': + return messages_da.messages; case 'de': return messages_de.messages; + case 'el': + return messages_el.messages; case 'en': return messages_en.messages; case 'es': return messages_es.messages; + case 'et': + return messages_et.messages; + case 'fa': + return messages_fa.messages; case 'fr': return messages_fr.messages; + case 'gu': + return messages_gu.messages; + case 'he': + return messages_he.messages; + case 'hi': + return messages_hi.messages; + case 'id': + return messages_id.messages; case 'it': return messages_it.messages; + case 'ja': + return messages_ja.messages; + case 'km': + return messages_km.messages; case 'ko': return messages_ko.messages; case 'nl': @@ -75,6 +135,14 @@ MessageLookupByLibrary? _findExact(String localeName) { return messages_pt.messages; case 'ru': return messages_ru.messages; + case 'sv': + return messages_sv.messages; + case 'te': + return messages_te.messages; + case 'th': + return messages_th.messages; + case 'ti': + return messages_ti.messages; case 'tr': return messages_tr.messages; case 'zh': diff --git a/mobile/lib/generated/intl/messages_ar.dart b/mobile/lib/generated/intl/messages_ar.dart new file mode 100644 index 0000000000..1ce7ba622c --- /dev/null +++ b/mobile/lib/generated/intl/messages_ar.dart @@ -0,0 +1,67 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a ar locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'ar'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "accountWelcomeBack": + MessageLookupByLibrary.simpleMessage("مرحبًا مجددًا!"), + "ackPasswordLostWarning": MessageLookupByLibrary.simpleMessage( + "أُدركُ أنّني فقدتُ كلمة مروري، فقد أفقد بياناتي لأن بياناتي مشفرة تشفيرًا تامًّا من النهاية إلى النهاية."), + "cancel": MessageLookupByLibrary.simpleMessage("إلغاء"), + "decrypting": MessageLookupByLibrary.simpleMessage("فك التشفير..."), + "email": MessageLookupByLibrary.simpleMessage("البريد الإلكتروني"), + "enterYourEmailAddress": + MessageLookupByLibrary.simpleMessage("أدخل عنوان بريدك الإلكتروني"), + "enterYourRecoveryKey": + MessageLookupByLibrary.simpleMessage("أدخل رمز الاسترداد"), + "forgotPassword": + MessageLookupByLibrary.simpleMessage("نسيت كلمة المرور"), + "incorrectRecoveryKeyBody": MessageLookupByLibrary.simpleMessage( + "مفتاح الاسترداد الذي أدخلته غير صحيح"), + "incorrectRecoveryKeyTitle": + MessageLookupByLibrary.simpleMessage("مفتاح الاسترداد غير صحيح"), + "invalidEmailAddress": MessageLookupByLibrary.simpleMessage( + "عنوان البريد الإلكتروني غير صالح"), + "noRecoveryKey": + MessageLookupByLibrary.simpleMessage("ما من مفتاح استرداد؟"), + "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( + "لا يمكن فك تشفير بياناتك دون كلمة المرور أو مفتاح الاسترداد بسبب طبيعة بروتوكول التشفير الخاص بنا من النهاية إلى النهاية"), + "recoverButton": MessageLookupByLibrary.simpleMessage("استرداد"), + "recoverySuccessful": + MessageLookupByLibrary.simpleMessage("نجح الاسترداد!"), + "sorry": MessageLookupByLibrary.simpleMessage("المعذرة"), + "terminate": MessageLookupByLibrary.simpleMessage("إنهاء"), + "terminateSession": + MessageLookupByLibrary.simpleMessage("إنهاء الجلسة؟"), + "thisDevice": MessageLookupByLibrary.simpleMessage("هذا الجهاز"), + "thisWillLogYouOutOfTheFollowingDevice": + MessageLookupByLibrary.simpleMessage( + "سيؤدي هذا إلى تسجيل خروجك من الجهاز التالي:"), + "thisWillLogYouOutOfThisDevice": MessageLookupByLibrary.simpleMessage( + "سيؤدي هذا إلى تسجيل خروجك من هذا الجهاز!"), + "toResetVerifyEmail": MessageLookupByLibrary.simpleMessage( + "لإعادة تعيين كلمة المرور، يرجى التحقق من بريدك الإلكتروني أولاً."), + "verify": MessageLookupByLibrary.simpleMessage("التحقّق"), + "verifyEmail": + MessageLookupByLibrary.simpleMessage("التحقق من البريد الإلكتروني") + }; +} diff --git a/mobile/lib/generated/intl/messages_bg.dart b/mobile/lib/generated/intl/messages_bg.dart new file mode 100644 index 0000000000..e887127f40 --- /dev/null +++ b/mobile/lib/generated/intl/messages_bg.dart @@ -0,0 +1,25 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a bg locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'bg'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => {}; +} diff --git a/mobile/lib/generated/intl/messages_ca.dart b/mobile/lib/generated/intl/messages_ca.dart new file mode 100644 index 0000000000..84dea987b0 --- /dev/null +++ b/mobile/lib/generated/intl/messages_ca.dart @@ -0,0 +1,25 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a ca locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'ca'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => {}; +} diff --git a/mobile/lib/generated/intl/messages_cs.dart b/mobile/lib/generated/intl/messages_cs.dart index be665f29b7..2bfb5800f1 100644 --- a/mobile/lib/generated/intl/messages_cs.dart +++ b/mobile/lib/generated/intl/messages_cs.dart @@ -20,104 +20,6 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'cs'; - static String m0(count) => - "${Intl.plural(count, zero: 'Add collaborator', one: 'Add collaborator', other: 'Add collaborators')}"; - - static String m1(count) => - "${Intl.plural(count, zero: 'Add viewer', one: 'Add viewer', other: 'Add viewers')}"; - final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => { - "addCollaborators": m0, - "addToHiddenAlbum": - MessageLookupByLibrary.simpleMessage("Add to hidden album"), - "addViewers": m1, - "appLock": MessageLookupByLibrary.simpleMessage("App lock"), - "appLockDescriptions": MessageLookupByLibrary.simpleMessage( - "Choose between your device\'s default lock screen and a custom lock screen with a PIN or password."), - "authToViewPasskey": MessageLookupByLibrary.simpleMessage( - "Please authenticate to view your passkey"), - "autoLock": MessageLookupByLibrary.simpleMessage("Auto lock"), - "autoLockFeatureDescription": MessageLookupByLibrary.simpleMessage( - "Time after which the app locks after being put in the background"), - "changeLocationOfSelectedItems": MessageLookupByLibrary.simpleMessage( - "Change location of selected items?"), - "clusteringProgress": - MessageLookupByLibrary.simpleMessage("Clustering progress"), - "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), - "createCollaborativeLink": - MessageLookupByLibrary.simpleMessage("Create collaborative link"), - "deleteConfirmDialogBody": MessageLookupByLibrary.simpleMessage( - "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted."), - "descriptions": MessageLookupByLibrary.simpleMessage("Descriptions"), - "deviceLock": MessageLookupByLibrary.simpleMessage("Device lock"), - "editLocation": MessageLookupByLibrary.simpleMessage("Edit location"), - "editsToLocationWillOnlyBeSeenWithinEnte": - MessageLookupByLibrary.simpleMessage( - "Edits to location will only be seen within Ente"), - "enterPersonName": - MessageLookupByLibrary.simpleMessage("Enter person name"), - "enterPin": MessageLookupByLibrary.simpleMessage("Enter PIN"), - "faceRecognition": - MessageLookupByLibrary.simpleMessage("Face recognition"), - "fileTypes": MessageLookupByLibrary.simpleMessage("File types"), - "foundFaces": MessageLookupByLibrary.simpleMessage("Found faces"), - "guestView": MessageLookupByLibrary.simpleMessage("Guest view"), - "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( - "To enable guest view, please setup device passcode or screen lock in your system settings."), - "hideContent": MessageLookupByLibrary.simpleMessage("Hide content"), - "hideContentDescriptionAndroid": MessageLookupByLibrary.simpleMessage( - "Hides app content in the app switcher and disables screenshots"), - "hideContentDescriptionIos": MessageLookupByLibrary.simpleMessage( - "Hides app content in the app switcher"), - "immediately": MessageLookupByLibrary.simpleMessage("Immediately"), - "indexingIsPaused": MessageLookupByLibrary.simpleMessage( - "Indexing is paused, will automatically resume when device is ready"), - "joinDiscord": MessageLookupByLibrary.simpleMessage("Join Discord"), - "locations": MessageLookupByLibrary.simpleMessage("Locations"), - "longPressAnEmailToVerifyEndToEndEncryption": - MessageLookupByLibrary.simpleMessage( - "Long press an email to verify end to end encryption."), - "modifyYourQueryOrTrySearchingFor": - MessageLookupByLibrary.simpleMessage( - "Modify your query, or try searching for"), - "moveToHiddenAlbum": - MessageLookupByLibrary.simpleMessage("Move to hidden album"), - "next": MessageLookupByLibrary.simpleMessage("Next"), - "noQuickLinksSelected": - MessageLookupByLibrary.simpleMessage("No quick links selected"), - "noSystemLockFound": - MessageLookupByLibrary.simpleMessage("No system lock found"), - "passwordLock": MessageLookupByLibrary.simpleMessage("Password lock"), - "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( - "Password strength is calculated considering the length of the password, used characters, and whether or not the password appears in the top 10,000 most used passwords"), - "pinLock": MessageLookupByLibrary.simpleMessage("PIN lock"), - "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( - "Please select quick links to remove"), - "reenterPassword": - MessageLookupByLibrary.simpleMessage("Re-enter password"), - "reenterPin": MessageLookupByLibrary.simpleMessage("Re-enter PIN"), - "removePersonLabel": - MessageLookupByLibrary.simpleMessage("Remove person label"), - "removePublicLinks": - MessageLookupByLibrary.simpleMessage("Remove public links"), - "search": MessageLookupByLibrary.simpleMessage("Search"), - "selectALocation": - MessageLookupByLibrary.simpleMessage("Select a location"), - "selectALocationFirst": - MessageLookupByLibrary.simpleMessage("Select a location first"), - "setNewPassword": - MessageLookupByLibrary.simpleMessage("Set new password"), - "setNewPin": MessageLookupByLibrary.simpleMessage("Set new PIN"), - "tapToUnlock": MessageLookupByLibrary.simpleMessage("Tap to unlock"), - "thisWillRemovePublicLinksOfAllSelectedQuickLinks": - MessageLookupByLibrary.simpleMessage( - "This will remove public links of all selected quick links."), - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": - MessageLookupByLibrary.simpleMessage( - "To enable app lock, please setup device passcode or screen lock in your system settings."), - "tooManyIncorrectAttempts": - MessageLookupByLibrary.simpleMessage("Too many incorrect attempts"), - "yourMap": MessageLookupByLibrary.simpleMessage("Your map") - }; + static Map _notInlinedMessages(_) => {}; } diff --git a/mobile/lib/generated/intl/messages_da.dart b/mobile/lib/generated/intl/messages_da.dart new file mode 100644 index 0000000000..f243887b61 --- /dev/null +++ b/mobile/lib/generated/intl/messages_da.dart @@ -0,0 +1,142 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a da locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'da'; + + static String m0(count, formattedCount) => + "${Intl.plural(count, zero: 'ingen minder', one: '${formattedCount} minde', other: '${formattedCount} minder')}"; + + static String m1(count) => "${count} valgt"; + + static String m2(verificationID) => + "Hey, kan du bekræfte, at dette er dit ente.io verifikation ID: ${verificationID}"; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "accountWelcomeBack": + MessageLookupByLibrary.simpleMessage("Velkommen tilbage!"), + "activeSessions": + MessageLookupByLibrary.simpleMessage("Aktive sessioner"), + "addOnPageSubtitle": + MessageLookupByLibrary.simpleMessage("Oplysninger om tilføjelser"), + "askDeleteReason": MessageLookupByLibrary.simpleMessage( + "Hvad er hovedårsagen til, at du sletter din konto?"), + "backedUpFolders": + MessageLookupByLibrary.simpleMessage("Sikkerhedskopierede mapper"), + "cancel": MessageLookupByLibrary.simpleMessage("Annuller"), + "confirmAccountDeletion": + MessageLookupByLibrary.simpleMessage("Bekræft Sletning Af Konto"), + "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( + "Ja, jeg ønsker at slette denne konto og alle dens data permanent."), + "confirmPassword": + MessageLookupByLibrary.simpleMessage("Bekræft adgangskode"), + "copypasteThisCodentoYourAuthenticatorApp": + MessageLookupByLibrary.simpleMessage( + "Kopiér denne kode\ntil din autentificeringsapp"), + "couldNotUpdateSubscription": MessageLookupByLibrary.simpleMessage( + "Abonnementet kunne ikke opdateres."), + "createAccount": MessageLookupByLibrary.simpleMessage("Opret konto"), + "createNewAccount": + MessageLookupByLibrary.simpleMessage("Opret en ny konto"), + "deleteAccount": MessageLookupByLibrary.simpleMessage("Slet konto"), + "deleteAccountFeedbackPrompt": MessageLookupByLibrary.simpleMessage( + "Vi er kede af at du forlader os. Forklar venligst hvorfor, så vi kan forbedre os."), + "deleteAccountPermanentlyButton": + MessageLookupByLibrary.simpleMessage("Slet konto permanent"), + "deleteEmailRequest": MessageLookupByLibrary.simpleMessage( + "Send venligst en email til account-deletion@ente.io fra din registrerede email adresse."), + "deleteReason1": MessageLookupByLibrary.simpleMessage( + "Der mangler en vigtig funktion, som jeg har brug for"), + "deleteReason3": MessageLookupByLibrary.simpleMessage( + "Jeg fandt en anden tjeneste, som jeg syntes bedre om"), + "deleteReason4": + MessageLookupByLibrary.simpleMessage("Min grund er ikke angivet"), + "deleteRequestSLAText": MessageLookupByLibrary.simpleMessage( + "Din anmodning vil blive behandlet inden for 72 timer."), + "developerSettingsWarning": MessageLookupByLibrary.simpleMessage( + "Er du sikker på, at du vil ændre udviklerindstillingerne?"), + "email": MessageLookupByLibrary.simpleMessage("Email"), + "enterPin": MessageLookupByLibrary.simpleMessage("Indtast PIN"), + "enterValidEmail": MessageLookupByLibrary.simpleMessage( + "Indtast venligst en gyldig email adresse."), + "enterYourEmailAddress": + MessageLookupByLibrary.simpleMessage("Indtast din email adresse"), + "familyPlanPortalTitle": + MessageLookupByLibrary.simpleMessage("Familie"), + "feedback": MessageLookupByLibrary.simpleMessage("Feedback"), + "fileSavedToGallery": + MessageLookupByLibrary.simpleMessage("Fil gemt i galleri"), + "findPeopleByName": + MessageLookupByLibrary.simpleMessage("Find folk hurtigt ved navn"), + "forgotPassword": + MessageLookupByLibrary.simpleMessage("Glemt adgangskode"), + "incorrectPasswordTitle": + MessageLookupByLibrary.simpleMessage("Forkert adgangskode"), + "incorrectRecoveryKeyBody": MessageLookupByLibrary.simpleMessage( + "Den gendannelsesnøgle du indtastede er forkert"), + "invalidEmailAddress": + MessageLookupByLibrary.simpleMessage("Ugyldig email adresse"), + "invite": MessageLookupByLibrary.simpleMessage("Inviter"), + "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( + "Hjælp os venligst med disse oplysninger"), + "loggingOut": MessageLookupByLibrary.simpleMessage("Logger ud..."), + "longPressAnEmailToVerifyEndToEndEncryption": + MessageLookupByLibrary.simpleMessage( + "Langt tryk på en e-mail for at bekræfte slutningen af krypteringen."), + "manage": MessageLookupByLibrary.simpleMessage("Administrér"), + "memoryCount": m0, + "mlIndexingDescription": MessageLookupByLibrary.simpleMessage( + "Bemærk venligst, at maskinindlæring vil resultere i en højere båndbredde og batteriforbrug, indtil alle elementer er indekseret. Overvej at bruge desktop app til hurtigere indeksering, vil alle resultater blive synkroniseret automatisk."), + "moments": MessageLookupByLibrary.simpleMessage("Øjeblikke"), + "next": MessageLookupByLibrary.simpleMessage("Næste"), + "ok": MessageLookupByLibrary.simpleMessage("Ok"), + "oops": MessageLookupByLibrary.simpleMessage("Ups"), + "password": MessageLookupByLibrary.simpleMessage("Adgangskode"), + "pleaseContactSupportAndWeWillBeHappyToHelp": + MessageLookupByLibrary.simpleMessage( + "Kontakt support@ente.io og vi vil være glade for at hjælpe!"), + "renameFile": MessageLookupByLibrary.simpleMessage("Omdøb fil"), + "scanThisBarcodeWithnyourAuthenticatorApp": + MessageLookupByLibrary.simpleMessage( + "Skan denne QR-kode med godkendelses-appen"), + "searchHint1": + MessageLookupByLibrary.simpleMessage("Hurtig, søgning på enheden"), + "selectReason": MessageLookupByLibrary.simpleMessage("Vælg årsag"), + "selectedPhotos": m1, + "sendEmail": MessageLookupByLibrary.simpleMessage("Send email"), + "shareTextConfirmOthersVerificationID": m2, + "somethingWentWrongPleaseTryAgain": + MessageLookupByLibrary.simpleMessage( + "Noget gik galt, prøv venligst igen"), + "subscribe": MessageLookupByLibrary.simpleMessage("Abonner"), + "terminateSession": + MessageLookupByLibrary.simpleMessage("Afslut session?"), + "thisWillLogYouOutOfTheFollowingDevice": + MessageLookupByLibrary.simpleMessage( + "Dette vil logge dig ud af følgende enhed:"), + "thisWillLogYouOutOfThisDevice": MessageLookupByLibrary.simpleMessage( + "Dette vil logge dig ud af denne enhed!"), + "verify": MessageLookupByLibrary.simpleMessage("Bekræft"), + "viewAddOnButton": + MessageLookupByLibrary.simpleMessage("Vis tilføjelser"), + "yourAccountHasBeenDeleted": + MessageLookupByLibrary.simpleMessage("Din konto er blevet slettet") + }; +} diff --git a/mobile/lib/generated/intl/messages_de.dart b/mobile/lib/generated/intl/messages_de.dart index e005292385..90dc0b7f0d 100644 --- a/mobile/lib/generated/intl/messages_de.dart +++ b/mobile/lib/generated/intl/messages_de.dart @@ -20,37 +20,37 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'de'; - static String m0(count) => + static String m3(count) => "${Intl.plural(count, one: 'Teilnehmer', other: 'Teilnehmer')} hinzufügen"; - static String m2(count) => + static String m4(count) => "${Intl.plural(count, one: 'Element hinzufügen', other: 'Elemente hinzufügen')}"; - static String m3(storageAmount, endDate) => + static String m5(storageAmount, endDate) => "Dein ${storageAmount} Add-on ist gültig bis ${endDate}"; - static String m1(count) => + static String m6(count) => "${Intl.plural(count, one: 'Betrachter', other: 'Betrachter')} hinzufügen"; - static String m4(emailOrName) => "Von ${emailOrName} hinzugefügt"; + static String m7(emailOrName) => "Von ${emailOrName} hinzugefügt"; - static String m5(albumName) => "Erfolgreich zu ${albumName} hinzugefügt"; + static String m8(albumName) => "Erfolgreich zu ${albumName} hinzugefügt"; - static String m6(count) => + static String m9(count) => "${Intl.plural(count, zero: 'Keine Teilnehmer', one: '1 Teilnehmer', other: '${count} Teilnehmer')}"; - static String m7(versionValue) => "Version: ${versionValue}"; + static String m10(versionValue) => "Version: ${versionValue}"; - static String m8(freeAmount, storageUnit) => + static String m11(freeAmount, storageUnit) => "${freeAmount} ${storageUnit} frei"; - static String m9(paymentProvider) => + static String m12(paymentProvider) => "Bitte kündige dein aktuelles Abo über ${paymentProvider} zuerst"; - static String m10(user) => + static String m13(user) => "Der Nutzer \"${user}\" wird keine weiteren Fotos zum Album hinzufügen können.\n\nJedoch kann er weiterhin vorhandene Bilder, welche durch ihn hinzugefügt worden sind, wieder entfernen"; - static String m11(isFamilyMember, storageAmountInGb) => + static String m14(isFamilyMember, storageAmountInGb) => "${Intl.select(isFamilyMember, { 'true': 'Deine Familiengruppe hat bereits ${storageAmountInGb} GB erhalten', @@ -58,115 +58,115 @@ class MessageLookup extends MessageLookupByLibrary { 'other': 'Du hast bereits ${storageAmountInGb} GB erhalten!', })}"; - static String m12(albumName) => + static String m15(albumName) => "Kollaborativer Link für ${albumName} erstellt"; - static String m13(familyAdminEmail) => + static String m16(familyAdminEmail) => "Bitte kontaktiere ${familyAdminEmail} um dein Abo zu verwalten"; - static String m14(provider) => + static String m17(provider) => "Bitte kontaktiere uns über support@ente.io, um dein ${provider} Abo zu verwalten."; - static String m15(endpoint) => "Verbunden mit ${endpoint}"; + static String m18(endpoint) => "Verbunden mit ${endpoint}"; - static String m16(count) => + static String m19(count) => "${Intl.plural(count, one: 'Lösche ${count} Element', other: 'Lösche ${count} Elemente')}"; - static String m17(currentlyDeleting, totalCount) => + static String m20(currentlyDeleting, totalCount) => "Lösche ${currentlyDeleting} / ${totalCount}"; - static String m18(albumName) => + static String m21(albumName) => "Der öffentliche Link zum Zugriff auf \"${albumName}\" wird entfernt."; - static String m19(supportEmail) => + static String m22(supportEmail) => "Bitte sende eine E-Mail an ${supportEmail} von deiner registrierten E-Mail-Adresse"; - static String m20(count, storageSaved) => + static String m23(count, storageSaved) => "Du hast ${Intl.plural(count, one: '${count} duplizierte Datei', other: '${count} dupliziere Dateien')} gelöscht und (${storageSaved}!) freigegeben"; - static String m21(count, formattedSize) => + static String m24(count, formattedSize) => "${count} Dateien, ${formattedSize} jede"; - static String m22(newEmail) => "E-Mail-Adresse geändert zu ${newEmail}"; + static String m25(newEmail) => "E-Mail-Adresse geändert zu ${newEmail}"; - static String m23(email) => + static String m26(email) => "${email} hat kein Ente-Konto.\n\nSende eine Einladung, um Fotos zu teilen."; - static String m24(count, formattedNumber) => + static String m27(count, formattedNumber) => "${Intl.plural(count, one: '1 Datei', other: '${formattedNumber} Dateien')} auf diesem Gerät wurde(n) sicher gespeichert"; - static String m25(count, formattedNumber) => + static String m28(count, formattedNumber) => "${Intl.plural(count, one: '1 Datei', other: '${formattedNumber} Dateien')} in diesem Album wurde(n) sicher gespeichert"; - static String m26(storageAmountInGB) => + static String m29(storageAmountInGB) => "${storageAmountInGB} GB jedes Mal, wenn sich jemand mit deinem Code für einen bezahlten Tarif anmeldet"; - static String m27(endDate) => "Kostenlose Demo verfügbar bis zum ${endDate}"; + static String m30(endDate) => "Kostenlose Demo verfügbar bis zum ${endDate}"; - static String m28(count) => + static String m31(count) => "Du kannst immernoch über Ente ${Intl.plural(count, one: 'darauf', other: 'auf sie')} zugreifen, solange du ein aktives Abo hast"; - static String m29(sizeInMBorGB) => "${sizeInMBorGB} freigeben"; + static String m32(sizeInMBorGB) => "${sizeInMBorGB} freigeben"; - static String m30(count, formattedSize) => + static String m33(count, formattedSize) => "${Intl.plural(count, one: 'Es kann vom Gerät gelöscht werden, um ${formattedSize} freizugeben', other: 'Sie können vom Gerät gelöscht werden, um ${formattedSize} freizugeben')}"; - static String m31(currentlyProcessing, totalCount) => + static String m34(currentlyProcessing, totalCount) => "Verarbeite ${currentlyProcessing} / ${totalCount}"; - static String m32(count) => + static String m35(count) => "${Intl.plural(count, one: '${count} Objekt', other: '${count} Objekte')}"; - static String m33(expiryTime) => "Link läuft am ${expiryTime} ab"; + static String m36(expiryTime) => "Link läuft am ${expiryTime} ab"; - static String m34(count, formattedCount) => + static String m0(count, formattedCount) => "${Intl.plural(count, zero: 'keine Erinnerungsstücke', one: '${formattedCount} Erinnerung', other: '${formattedCount} Erinnerungsstücke')}"; - static String m35(count) => + static String m37(count) => "${Intl.plural(count, one: 'Element verschieben', other: 'Elemente verschieben')}"; - static String m36(albumName) => "Erfolgreich zu ${albumName} hinzugefügt"; + static String m38(albumName) => "Erfolgreich zu ${albumName} hinzugefügt"; - static String m37(name) => "Nicht ${name}?"; + static String m39(name) => "Nicht ${name}?"; - static String m38(familyAdminEmail) => + static String m40(familyAdminEmail) => "Bitte wende Dich an ${familyAdminEmail}, um den Code zu ändern."; - static String m39(passwordStrengthValue) => + static String m41(passwordStrengthValue) => "Passwortstärke: ${passwordStrengthValue}"; - static String m40(providerName) => + static String m42(providerName) => "Bitte kontaktiere den Support von ${providerName}, falls etwas abgebucht wurde"; - static String m41(endDate) => + static String m43(endDate) => "Kostenlose Testversion gültig bis ${endDate}.\nDu kannst anschließend ein bezahltes Paket auswählen."; - static String m42(toEmail) => "Bitte sende uns eine E-Mail an ${toEmail}"; + static String m44(toEmail) => "Bitte sende uns eine E-Mail an ${toEmail}"; - static String m43(toEmail) => "Bitte sende die Protokolle an ${toEmail}"; + static String m45(toEmail) => "Bitte sende die Protokolle an ${toEmail}"; - static String m44(storeName) => "Bewerte uns auf ${storeName}"; + static String m46(storeName) => "Bewerte uns auf ${storeName}"; - static String m45(storageInGB) => + static String m47(storageInGB) => "3. Ihr beide erhaltet ${storageInGB} GB* kostenlos"; - static String m46(userEmail) => + static String m48(userEmail) => "${userEmail} wird aus diesem geteilten Album entfernt\n\nAlle von ihnen hinzugefügte Fotos werden ebenfalls aus dem Album entfernt"; - static String m47(endDate) => "Erneuert am ${endDate}"; + static String m49(endDate) => "Erneuert am ${endDate}"; - static String m48(count) => + static String m50(count) => "${Intl.plural(count, one: '${count} Ergebnis gefunden', other: '${count} Ergebnisse gefunden')}"; - static String m49(count) => "${count} ausgewählt"; + static String m1(count) => "${count} ausgewählt"; - static String m50(count, yourCount) => + static String m51(count, yourCount) => "${count} ausgewählt (${yourCount} von Ihnen)"; - static String m51(verificationID) => + static String m52(verificationID) => "Hier ist meine Verifizierungs-ID: ${verificationID} für ente.io."; - static String m52(verificationID) => + static String m2(verificationID) => "Hey, kannst du bestätigen, dass dies deine ente.io Verifizierungs-ID ist: ${verificationID}"; static String m53(referralCode, referralStorageInGB) => @@ -239,17 +239,17 @@ class MessageLookup extends MessageLookupByLibrary { "Neue E-Mail-Adresse hinzufügen"), "addCollaborator": MessageLookupByLibrary.simpleMessage("Bearbeiter hinzufügen"), - "addCollaborators": m0, + "addCollaborators": m3, "addFromDevice": MessageLookupByLibrary.simpleMessage("Vom Gerät hinzufügen"), - "addItem": m2, + "addItem": m4, "addLocation": MessageLookupByLibrary.simpleMessage("Ort hinzufügen"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Hinzufügen"), "addMore": MessageLookupByLibrary.simpleMessage("Mehr hinzufügen"), "addNew": MessageLookupByLibrary.simpleMessage("Hinzufügen"), "addOnPageSubtitle": MessageLookupByLibrary.simpleMessage("Details der Add-ons"), - "addOnValidTill": m3, + "addOnValidTill": m5, "addOns": MessageLookupByLibrary.simpleMessage("Add-ons"), "addPhotos": MessageLookupByLibrary.simpleMessage("Fotos hinzufügen"), "addSelected": @@ -260,12 +260,12 @@ class MessageLookup extends MessageLookupByLibrary { "addToHiddenAlbum": MessageLookupByLibrary.simpleMessage( "Zum versteckten Album hinzufügen"), "addViewer": MessageLookupByLibrary.simpleMessage("Album teilen"), - "addViewers": m1, + "addViewers": m6, "addYourPhotosNow": MessageLookupByLibrary.simpleMessage("Füge deine Foto jetzt hinzu"), "addedAs": MessageLookupByLibrary.simpleMessage("Hinzugefügt als"), - "addedBy": m4, - "addedSuccessfullyTo": m5, + "addedBy": m7, + "addedSuccessfullyTo": m8, "addingToFavorites": MessageLookupByLibrary.simpleMessage( "Wird zu Favoriten hinzugefügt..."), "advanced": MessageLookupByLibrary.simpleMessage("Erweitert"), @@ -276,7 +276,7 @@ class MessageLookup extends MessageLookupByLibrary { "after1Week": MessageLookupByLibrary.simpleMessage("Nach 1 Woche"), "after1Year": MessageLookupByLibrary.simpleMessage("Nach 1 Jahr"), "albumOwner": MessageLookupByLibrary.simpleMessage("Besitzer"), - "albumParticipantsCount": m6, + "albumParticipantsCount": m9, "albumTitle": MessageLookupByLibrary.simpleMessage("Albumtitel"), "albumUpdated": MessageLookupByLibrary.simpleMessage("Album aktualisiert"), @@ -317,7 +317,7 @@ class MessageLookup extends MessageLookupByLibrary { "appLock": MessageLookupByLibrary.simpleMessage("App-Sperre"), "appLockDescriptions": MessageLookupByLibrary.simpleMessage( "Wähle zwischen dem Standard-Sperrbildschirm deines Gerätes und einem eigenen Sperrbildschirm mit PIN oder Passwort."), - "appVersion": m7, + "appVersion": m10, "appleId": MessageLookupByLibrary.simpleMessage("Apple ID"), "apply": MessageLookupByLibrary.simpleMessage("Anwenden"), "applyCodeTitle": MessageLookupByLibrary.simpleMessage("Code nutzen"), @@ -394,7 +394,7 @@ class MessageLookup extends MessageLookupByLibrary { "autoPairDesc": MessageLookupByLibrary.simpleMessage( "Automatisches Verbinden funktioniert nur mit Geräten, die Chromecast unterstützen."), "available": MessageLookupByLibrary.simpleMessage("Verfügbar"), - "availableStorageSpace": m8, + "availableStorageSpace": m11, "backedUpFolders": MessageLookupByLibrary.simpleMessage("Gesicherte Ordner"), "backup": MessageLookupByLibrary.simpleMessage("Backup"), @@ -420,10 +420,10 @@ class MessageLookup extends MessageLookupByLibrary { "canOnlyRemoveFilesOwnedByYou": MessageLookupByLibrary.simpleMessage( "Du kannst nur Dateien entfernen, die dir gehören"), "cancel": MessageLookupByLibrary.simpleMessage("Abbrechen"), - "cancelOtherSubscription": m9, + "cancelOtherSubscription": m12, "cancelSubscription": MessageLookupByLibrary.simpleMessage("Abonnement kündigen"), - "cannotAddMorePhotosAfterBecomingViewer": m10, + "cannotAddMorePhotosAfterBecomingViewer": m13, "cannotDeleteSharedFiles": MessageLookupByLibrary.simpleMessage( "Konnte geteilte Dateien nicht löschen"), "castIPMismatchBody": MessageLookupByLibrary.simpleMessage( @@ -471,7 +471,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Freien Speicher einlösen"), "claimMore": MessageLookupByLibrary.simpleMessage("Mehr einlösen!"), "claimed": MessageLookupByLibrary.simpleMessage("Eingelöst"), - "claimedStorageSoFar": m11, + "claimedStorageSoFar": m14, "cleanUncategorized": MessageLookupByLibrary.simpleMessage("Unkategorisiert leeren"), "cleanUncategorizedDescription": MessageLookupByLibrary.simpleMessage( @@ -500,7 +500,7 @@ class MessageLookup extends MessageLookupByLibrary { "Erstelle einen Link, mit dem andere Fotos in dem geteilten Album sehen und selbst welche hinzufügen können - ohne dass sie die ein Ente-Konto oder die App benötigen. Ideal um gemeinsam Fotos von Events zu sammeln."), "collaborativeLink": MessageLookupByLibrary.simpleMessage("Gemeinschaftlicher Link"), - "collaborativeLinkCreatedFor": m12, + "collaborativeLinkCreatedFor": m15, "collaborator": MessageLookupByLibrary.simpleMessage("Bearbeiter"), "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": MessageLookupByLibrary.simpleMessage( @@ -529,10 +529,10 @@ class MessageLookup extends MessageLookupByLibrary { "Bestätige deinen Wiederherstellungsschlüssel"), "connectToDevice": MessageLookupByLibrary.simpleMessage("Mit Gerät verbinden"), - "contactFamilyAdmin": m13, + "contactFamilyAdmin": m16, "contactSupport": MessageLookupByLibrary.simpleMessage("Support kontaktieren"), - "contactToManageSubscription": m14, + "contactToManageSubscription": m17, "contacts": MessageLookupByLibrary.simpleMessage("Kontakte"), "contents": MessageLookupByLibrary.simpleMessage("Inhalte"), "continueLabel": MessageLookupByLibrary.simpleMessage("Weiter"), @@ -578,7 +578,7 @@ class MessageLookup extends MessageLookupByLibrary { "currentUsageIs": MessageLookupByLibrary.simpleMessage("Aktuell genutzt werden "), "custom": MessageLookupByLibrary.simpleMessage("Benutzerdefiniert"), - "customEndpoint": m15, + "customEndpoint": m18, "darkTheme": MessageLookupByLibrary.simpleMessage("Dunkel"), "dayToday": MessageLookupByLibrary.simpleMessage("Heute"), "dayYesterday": MessageLookupByLibrary.simpleMessage("Gestern"), @@ -614,11 +614,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Vom Gerät löschen"), "deleteFromEnte": MessageLookupByLibrary.simpleMessage("Von Ente löschen"), - "deleteItemCount": m16, + "deleteItemCount": m19, "deleteLocation": MessageLookupByLibrary.simpleMessage("Standort löschen"), "deletePhotos": MessageLookupByLibrary.simpleMessage("Fotos löschen"), - "deleteProgress": m17, + "deleteProgress": m20, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Es fehlt eine zentrale Funktion, die ich benötige"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -657,7 +657,7 @@ class MessageLookup extends MessageLookupByLibrary { "Zuschauer können weiterhin Screenshots oder mit anderen externen Programmen Kopien der Bilder machen."), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Bitte beachten Sie:"), - "disableLinkMessage": m18, + "disableLinkMessage": m21, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Zweiten Faktor (2FA) deaktivieren"), "disablingTwofactorAuthentication": @@ -680,9 +680,9 @@ class MessageLookup extends MessageLookupByLibrary { "Herunterladen fehlgeschlagen"), "downloading": MessageLookupByLibrary.simpleMessage("Wird heruntergeladen..."), - "dropSupportEmail": m19, - "duplicateFileCountWithStorageSaved": m20, - "duplicateItemsGroup": m21, + "dropSupportEmail": m22, + "duplicateFileCountWithStorageSaved": m23, + "duplicateItemsGroup": m24, "edit": MessageLookupByLibrary.simpleMessage("Bearbeiten"), "editLocation": MessageLookupByLibrary.simpleMessage("Standort bearbeiten"), @@ -695,8 +695,8 @@ class MessageLookup extends MessageLookupByLibrary { "Edits to location will only be seen within Ente"), "eligible": MessageLookupByLibrary.simpleMessage("zulässig"), "email": MessageLookupByLibrary.simpleMessage("E-Mail"), - "emailChangedTo": m22, - "emailNoEnteAccount": m23, + "emailChangedTo": m25, + "emailNoEnteAccount": m26, "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("E-Mail-Verifizierung"), "emailYourLogs": MessageLookupByLibrary.simpleMessage( @@ -806,8 +806,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Dateitypen"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Dateitypen und -namen"), - "filesBackedUpFromDevice": m24, - "filesBackedUpInAlbum": m25, + "filesBackedUpFromDevice": m27, + "filesBackedUpInAlbum": m28, "filesDeleted": MessageLookupByLibrary.simpleMessage("Dateien gelöscht"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage( @@ -823,27 +823,27 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Gesichter gefunden"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage( "Kostenlos hinzugefügter Speicherplatz"), - "freeStorageOnReferralSuccess": m26, + "freeStorageOnReferralSuccess": m29, "freeStorageUsable": MessageLookupByLibrary.simpleMessage( "Freier Speicherplatz nutzbar"), "freeTrial": MessageLookupByLibrary.simpleMessage("Kostenlose Testphase"), - "freeTrialValidTill": m27, - "freeUpAccessPostDelete": m28, - "freeUpAmount": m29, + "freeTrialValidTill": m30, + "freeUpAccessPostDelete": m31, + "freeUpAmount": m32, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("Gerätespeicher freiräumen"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Spare Speicherplatz auf deinem Gerät, indem du Dateien löschst, die bereits gesichert wurden."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Speicherplatz freigeben"), - "freeUpSpaceSaving": m30, + "freeUpSpaceSaving": m33, "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Bis zu 1000 Erinnerungsstücke angezeigt in der Galerie"), "general": MessageLookupByLibrary.simpleMessage("Allgemein"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Generierung von Verschlüsselungscodes..."), - "genericProgress": m31, + "genericProgress": m34, "goToSettings": MessageLookupByLibrary.simpleMessage("Zu den Einstellungen"), "googlePlayId": MessageLookupByLibrary.simpleMessage("Google Play ID"), @@ -923,7 +923,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Etwas ist schiefgelaufen. Bitte versuche es später noch einmal. Sollte der Fehler weiter bestehen, kontaktiere unser Supportteam."), - "itemCount": m32, + "itemCount": m35, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Elemente zeigen die Anzahl der Tage bis zum dauerhaften Löschen an"), @@ -952,7 +952,7 @@ class MessageLookup extends MessageLookupByLibrary { "linkDeviceLimit": MessageLookupByLibrary.simpleMessage("Geräte-Limit"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Aktiviert"), "linkExpired": MessageLookupByLibrary.simpleMessage("Abgelaufen"), - "linkExpiresOn": m33, + "linkExpiresOn": m36, "linkExpiry": MessageLookupByLibrary.simpleMessage("Ablaufdatum des Links"), "linkHasExpired": @@ -1030,7 +1030,7 @@ class MessageLookup extends MessageLookupByLibrary { "maps": MessageLookupByLibrary.simpleMessage("Karten"), "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), - "memoryCount": m34, + "memoryCount": m0, "merchandise": MessageLookupByLibrary.simpleMessage("Merchandise"), "mlConsent": MessageLookupByLibrary.simpleMessage( "Maschinelles Lernen aktivieren"), @@ -1053,12 +1053,12 @@ class MessageLookup extends MessageLookupByLibrary { "moments": MessageLookupByLibrary.simpleMessage("Momente"), "monthly": MessageLookupByLibrary.simpleMessage("Monatlich"), "moreDetails": MessageLookupByLibrary.simpleMessage("Weitere Details"), - "moveItem": m35, + "moveItem": m37, "moveToAlbum": MessageLookupByLibrary.simpleMessage("Zum Album verschieben"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage( "Zu verstecktem Album verschieben"), - "movedSuccessfullyTo": m36, + "movedSuccessfullyTo": m38, "movedToTrash": MessageLookupByLibrary.simpleMessage( "In den Papierkorb verschoben"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1106,7 +1106,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Keine Ergebnisse gefunden"), "noSystemLockFound": MessageLookupByLibrary.simpleMessage("Keine Systemsperre gefunden"), - "notPersonLabel": m37, + "notPersonLabel": m39, "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage("Noch nichts mit Dir geteilt"), "nothingToSeeHere": MessageLookupByLibrary.simpleMessage( @@ -1117,7 +1117,7 @@ class MessageLookup extends MessageLookupByLibrary { "onDevice": MessageLookupByLibrary.simpleMessage("Auf dem Gerät"), "onEnte": MessageLookupByLibrary.simpleMessage( "Auf ente"), - "onlyFamilyAdminCanChangeCode": m38, + "onlyFamilyAdminCanChangeCode": m40, "oops": MessageLookupByLibrary.simpleMessage("Hoppla"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( "Hoppla, die Änderungen konnten nicht gespeichert werden"), @@ -1146,7 +1146,7 @@ class MessageLookup extends MessageLookupByLibrary { "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage( "Passwort erfolgreich geändert"), "passwordLock": MessageLookupByLibrary.simpleMessage("Passwort Sperre"), - "passwordStrength": m39, + "passwordStrength": m41, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "Die Berechnung der Stärke des Passworts basiert auf dessen Länge, den verwendeten Zeichen, und ob es in den 10.000 am häufigsten verwendeten Passwörtern vorkommt"), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -1157,7 +1157,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Zahlung fehlgeschlagen"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Leider ist deine Zahlung fehlgeschlagen. Wende dich an unseren Support und wir helfen dir weiter!"), - "paymentFailedTalkToProvider": m40, + "paymentFailedTalkToProvider": m42, "pendingItems": MessageLookupByLibrary.simpleMessage("Ausstehende Elemente"), "pendingSync": @@ -1186,7 +1186,7 @@ class MessageLookup extends MessageLookupByLibrary { "pinLock": MessageLookupByLibrary.simpleMessage("PIN-Sperre"), "playOnTv": MessageLookupByLibrary.simpleMessage( "Album auf dem Fernseher wiedergeben"), - "playStoreFreeTrialValidTill": m41, + "playStoreFreeTrialValidTill": m43, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("PlayStore Abo"), "pleaseCheckYourInternetConnectionAndTryAgain": @@ -1198,14 +1198,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Bitte wenden Sie sich an den Support, falls das Problem weiterhin besteht"), - "pleaseEmailUsAt": m42, + "pleaseEmailUsAt": m44, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage( "Bitte erteile die nötigen Berechtigungen"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Bitte logge dich erneut ein"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Bitte wähle die zu entfernenden schnellen Links"), - "pleaseSendTheLogsTo": m43, + "pleaseSendTheLogsTo": m45, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Bitte versuche es erneut"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1241,7 +1241,7 @@ class MessageLookup extends MessageLookupByLibrary { "raiseTicket": MessageLookupByLibrary.simpleMessage("Ticket erstellen"), "rateTheApp": MessageLookupByLibrary.simpleMessage("App bewerten"), "rateUs": MessageLookupByLibrary.simpleMessage("Bewerte uns"), - "rateUsOnStore": m44, + "rateUsOnStore": m46, "recover": MessageLookupByLibrary.simpleMessage("Wiederherstellen"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Konto wiederherstellen"), @@ -1278,7 +1278,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Gib diesen Code an deine Freunde"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Sie schließen ein bezahltes Abo ab"), - "referralStep3": m45, + "referralStep3": m47, "referrals": MessageLookupByLibrary.simpleMessage("Weiterempfehlungen"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Einlösungen sind derzeit pausiert"), @@ -1306,7 +1306,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Link entfernen"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Teilnehmer entfernen"), - "removeParticipantBody": m46, + "removeParticipantBody": m48, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Personenetikett entfernen"), "removePublicLink": @@ -1324,7 +1324,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("Datei umbenennen"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Abonnement erneuern"), - "renewsOn": m47, + "renewsOn": m49, "reportABug": MessageLookupByLibrary.simpleMessage("Fehler melden"), "reportBug": MessageLookupByLibrary.simpleMessage("Fehler melden"), "resendEmail": @@ -1396,7 +1396,7 @@ class MessageLookup extends MessageLookupByLibrary { "Gruppiere Fotos, die innerhalb des Radius eines bestimmten Fotos aufgenommen wurden"), "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage( "Laden Sie Personen ein, damit Sie geteilte Fotos hier einsehen können"), - "searchResultCount": m48, + "searchResultCount": m50, "security": MessageLookupByLibrary.simpleMessage("Sicherheit"), "selectALocation": MessageLookupByLibrary.simpleMessage("Standort auswählen"), @@ -1423,8 +1423,8 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage( "Ausgewählte Elemente werden aus allen Alben gelöscht und in den Papierkorb verschoben."), - "selectedPhotos": m49, - "selectedPhotosWithYours": m50, + "selectedPhotos": m1, + "selectedPhotosWithYours": m51, "send": MessageLookupByLibrary.simpleMessage("Absenden"), "sendEmail": MessageLookupByLibrary.simpleMessage("E-Mail senden"), "sendInvite": MessageLookupByLibrary.simpleMessage("Einladung senden"), @@ -1452,10 +1452,10 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Teile jetzt ein Album"), "shareLink": MessageLookupByLibrary.simpleMessage("Link teilen"), - "shareMyVerificationID": m51, + "shareMyVerificationID": m52, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Teile mit ausgewählten Personen"), - "shareTextConfirmOthersVerificationID": m52, + "shareTextConfirmOthersVerificationID": m2, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Hol dir Ente, damit wir ganz einfach Fotos und Videos in Originalqualität teilen können\n\nhttps://ente.io"), "shareTextReferralCode": m53, @@ -1721,8 +1721,6 @@ class MessageLookup extends MessageLookupByLibrary { "viewAllExifData": MessageLookupByLibrary.simpleMessage("Alle Exif-Daten anzeigen"), "viewLargeFiles": MessageLookupByLibrary.simpleMessage("Große Dateien"), - "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( - "Dateien anzeigen, die den meisten Speicherplatz belegen"), "viewLogs": MessageLookupByLibrary.simpleMessage("Protokolle anzeigen"), "viewRecoveryKey": MessageLookupByLibrary.simpleMessage( "Wiederherstellungsschlüssel anzeigen"), diff --git a/mobile/lib/generated/intl/messages_el.dart b/mobile/lib/generated/intl/messages_el.dart new file mode 100644 index 0000000000..79c0433b27 --- /dev/null +++ b/mobile/lib/generated/intl/messages_el.dart @@ -0,0 +1,28 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a el locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'el'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "enterYourEmailAddress": MessageLookupByLibrary.simpleMessage( + "Εισάγετε την διεύθυνση ηλ. ταχυδρομείου σας") + }; +} diff --git a/mobile/lib/generated/intl/messages_en.dart b/mobile/lib/generated/intl/messages_en.dart index 1559ecc898..0c377470aa 100644 --- a/mobile/lib/generated/intl/messages_en.dart +++ b/mobile/lib/generated/intl/messages_en.dart @@ -20,151 +20,151 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'en'; - static String m0(count) => + static String m3(count) => "${Intl.plural(count, zero: 'Add collaborator', one: 'Add collaborator', other: 'Add collaborators')}"; - static String m2(count) => + static String m4(count) => "${Intl.plural(count, one: 'Add item', other: 'Add items')}"; - static String m3(storageAmount, endDate) => + static String m5(storageAmount, endDate) => "Your ${storageAmount} add-on is valid till ${endDate}"; - static String m1(count) => + static String m6(count) => "${Intl.plural(count, zero: 'Add viewer', one: 'Add viewer', other: 'Add viewers')}"; - static String m4(emailOrName) => "Added by ${emailOrName}"; + static String m7(emailOrName) => "Added by ${emailOrName}"; - static String m5(albumName) => "Added successfully to ${albumName}"; + static String m8(albumName) => "Added successfully to ${albumName}"; - static String m6(count) => + static String m9(count) => "${Intl.plural(count, zero: 'No Participants', one: '1 Participant', other: '${count} Participants')}"; - static String m7(versionValue) => "Version: ${versionValue}"; + static String m10(versionValue) => "Version: ${versionValue}"; - static String m8(freeAmount, storageUnit) => + static String m11(freeAmount, storageUnit) => "${freeAmount} ${storageUnit} free"; - static String m9(paymentProvider) => + static String m12(paymentProvider) => "Please cancel your existing subscription from ${paymentProvider} first"; - static String m10(user) => + static String m13(user) => "${user} will not be able to add more photos to this album\n\nThey will still be able to remove existing photos added by them"; - static String m11(isFamilyMember, storageAmountInGb) => + static String m14(isFamilyMember, storageAmountInGb) => "${Intl.select(isFamilyMember, { 'true': 'Your family has claimed ${storageAmountInGb} GB so far', 'false': 'You have claimed ${storageAmountInGb} GB so far', 'other': 'You have claimed ${storageAmountInGb} GB so far!', })}"; - static String m12(albumName) => "Collaborative link created for ${albumName}"; + static String m15(albumName) => "Collaborative link created for ${albumName}"; - static String m13(familyAdminEmail) => + static String m16(familyAdminEmail) => "Please contact ${familyAdminEmail} to manage your subscription"; - static String m14(provider) => + static String m17(provider) => "Please contact us at support@ente.io to manage your ${provider} subscription."; - static String m15(endpoint) => "Connected to ${endpoint}"; + static String m18(endpoint) => "Connected to ${endpoint}"; - static String m16(count) => + static String m19(count) => "${Intl.plural(count, one: 'Delete ${count} item', other: 'Delete ${count} items')}"; - static String m17(currentlyDeleting, totalCount) => + static String m20(currentlyDeleting, totalCount) => "Deleting ${currentlyDeleting} / ${totalCount}"; - static String m18(albumName) => + static String m21(albumName) => "This will remove the public link for accessing \"${albumName}\"."; - static String m19(supportEmail) => + static String m22(supportEmail) => "Please drop an email to ${supportEmail} from your registered email address"; - static String m20(count, storageSaved) => + static String m23(count, storageSaved) => "You have cleaned up ${Intl.plural(count, one: '${count} duplicate file', other: '${count} duplicate files')}, saving (${storageSaved}!)"; - static String m21(count, formattedSize) => + static String m24(count, formattedSize) => "${count} files, ${formattedSize} each"; - static String m22(newEmail) => "Email changed to ${newEmail}"; + static String m25(newEmail) => "Email changed to ${newEmail}"; - static String m23(email) => + static String m26(email) => "${email} does not have an Ente account.\n\nSend them an invite to share photos."; - static String m24(count, formattedNumber) => + static String m27(count, formattedNumber) => "${Intl.plural(count, one: '1 file', other: '${formattedNumber} files')} on this device have been backed up safely"; - static String m25(count, formattedNumber) => + static String m28(count, formattedNumber) => "${Intl.plural(count, one: '1 file', other: '${formattedNumber} files')} in this album has been backed up safely"; - static String m26(storageAmountInGB) => + static String m29(storageAmountInGB) => "${storageAmountInGB} GB each time someone signs up for a paid plan and applies your code"; - static String m27(endDate) => "Free trial valid till ${endDate}"; + static String m30(endDate) => "Free trial valid till ${endDate}"; - static String m28(count) => + static String m31(count) => "You can still access ${Intl.plural(count, one: 'it', other: 'them')} on Ente as long as you have an active subscription"; - static String m29(sizeInMBorGB) => "Free up ${sizeInMBorGB}"; + static String m32(sizeInMBorGB) => "Free up ${sizeInMBorGB}"; - static String m30(count, formattedSize) => + static String m33(count, formattedSize) => "${Intl.plural(count, one: 'It can be deleted from the device to free up ${formattedSize}', other: 'They can be deleted from the device to free up ${formattedSize}')}"; - static String m31(currentlyProcessing, totalCount) => + static String m34(currentlyProcessing, totalCount) => "Processing ${currentlyProcessing} / ${totalCount}"; - static String m32(count) => + static String m35(count) => "${Intl.plural(count, one: '${count} item', other: '${count} items')}"; - static String m33(expiryTime) => "Link will expire on ${expiryTime}"; + static String m36(expiryTime) => "Link will expire on ${expiryTime}"; - static String m34(count, formattedCount) => + static String m0(count, formattedCount) => "${Intl.plural(count, zero: 'no memories', one: '${formattedCount} memory', other: '${formattedCount} memories')}"; - static String m35(count) => + static String m37(count) => "${Intl.plural(count, one: 'Move item', other: 'Move items')}"; - static String m36(albumName) => "Moved successfully to ${albumName}"; + static String m38(albumName) => "Moved successfully to ${albumName}"; - static String m37(name) => "Not ${name}?"; + static String m39(name) => "Not ${name}?"; - static String m38(familyAdminEmail) => + static String m40(familyAdminEmail) => "Please contact ${familyAdminEmail} to change your code."; - static String m39(passwordStrengthValue) => + static String m41(passwordStrengthValue) => "Password strength: ${passwordStrengthValue}"; - static String m40(providerName) => + static String m42(providerName) => "Please talk to ${providerName} support if you were charged"; - static String m41(endDate) => + static String m43(endDate) => "Free trial valid till ${endDate}.\nYou can choose a paid plan afterwards."; - static String m42(toEmail) => "Please email us at ${toEmail}"; + static String m44(toEmail) => "Please email us at ${toEmail}"; - static String m43(toEmail) => "Please send the logs to \n${toEmail}"; + static String m45(toEmail) => "Please send the logs to \n${toEmail}"; - static String m44(storeName) => "Rate us on ${storeName}"; + static String m46(storeName) => "Rate us on ${storeName}"; - static String m45(storageInGB) => + static String m47(storageInGB) => "3. Both of you get ${storageInGB} GB* free"; - static String m46(userEmail) => + static String m48(userEmail) => "${userEmail} will be removed from this shared album\n\nAny photos added by them will also be removed from the album"; - static String m47(endDate) => "Subscription renews on ${endDate}"; + static String m49(endDate) => "Subscription renews on ${endDate}"; - static String m48(count) => + static String m50(count) => "${Intl.plural(count, one: '${count} result found', other: '${count} results found')}"; - static String m49(count) => "${count} selected"; + static String m1(count) => "${count} selected"; - static String m50(count, yourCount) => + static String m51(count, yourCount) => "${count} selected (${yourCount} yours)"; - static String m51(verificationID) => + static String m52(verificationID) => "Here\'s my verification ID: ${verificationID} for ente.io."; - static String m52(verificationID) => + static String m2(verificationID) => "Hey, can you confirm that this is your ente.io verification ID: ${verificationID}"; static String m53(referralCode, referralStorageInGB) => @@ -234,17 +234,17 @@ class MessageLookup extends MessageLookupByLibrary { "addANewEmail": MessageLookupByLibrary.simpleMessage("Add a new email"), "addCollaborator": MessageLookupByLibrary.simpleMessage("Add collaborator"), - "addCollaborators": m0, + "addCollaborators": m3, "addFromDevice": MessageLookupByLibrary.simpleMessage("Add from device"), - "addItem": m2, + "addItem": m4, "addLocation": MessageLookupByLibrary.simpleMessage("Add location"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Add"), "addMore": MessageLookupByLibrary.simpleMessage("Add more"), "addNew": MessageLookupByLibrary.simpleMessage("Add new"), "addOnPageSubtitle": MessageLookupByLibrary.simpleMessage("Details of add-ons"), - "addOnValidTill": m3, + "addOnValidTill": m5, "addOns": MessageLookupByLibrary.simpleMessage("Add-ons"), "addPhotos": MessageLookupByLibrary.simpleMessage("Add photos"), "addSelected": MessageLookupByLibrary.simpleMessage("Add selected"), @@ -253,12 +253,12 @@ class MessageLookup extends MessageLookupByLibrary { "addToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Add to hidden album"), "addViewer": MessageLookupByLibrary.simpleMessage("Add viewer"), - "addViewers": m1, + "addViewers": m6, "addYourPhotosNow": MessageLookupByLibrary.simpleMessage("Add your photos now"), "addedAs": MessageLookupByLibrary.simpleMessage("Added as"), - "addedBy": m4, - "addedSuccessfullyTo": m5, + "addedBy": m7, + "addedSuccessfullyTo": m8, "addingToFavorites": MessageLookupByLibrary.simpleMessage("Adding to favorites..."), "advanced": MessageLookupByLibrary.simpleMessage("Advanced"), @@ -269,7 +269,7 @@ class MessageLookup extends MessageLookupByLibrary { "after1Week": MessageLookupByLibrary.simpleMessage("After 1 week"), "after1Year": MessageLookupByLibrary.simpleMessage("After 1 year"), "albumOwner": MessageLookupByLibrary.simpleMessage("Owner"), - "albumParticipantsCount": m6, + "albumParticipantsCount": m9, "albumTitle": MessageLookupByLibrary.simpleMessage("Album title"), "albumUpdated": MessageLookupByLibrary.simpleMessage("Album updated"), "albums": MessageLookupByLibrary.simpleMessage("Albums"), @@ -306,7 +306,7 @@ class MessageLookup extends MessageLookupByLibrary { "appLock": MessageLookupByLibrary.simpleMessage("App lock"), "appLockDescriptions": MessageLookupByLibrary.simpleMessage( "Choose between your device\'s default lock screen and a custom lock screen with a PIN or password."), - "appVersion": m7, + "appVersion": m10, "appleId": MessageLookupByLibrary.simpleMessage("Apple ID"), "apply": MessageLookupByLibrary.simpleMessage("Apply"), "applyCodeTitle": MessageLookupByLibrary.simpleMessage("Apply code"), @@ -381,7 +381,7 @@ class MessageLookup extends MessageLookupByLibrary { "autoPairDesc": MessageLookupByLibrary.simpleMessage( "Auto pair works only with devices that support Chromecast."), "available": MessageLookupByLibrary.simpleMessage("Available"), - "availableStorageSpace": m8, + "availableStorageSpace": m11, "backedUpFolders": MessageLookupByLibrary.simpleMessage("Backed up folders"), "backup": MessageLookupByLibrary.simpleMessage("Backup"), @@ -405,10 +405,10 @@ class MessageLookup extends MessageLookupByLibrary { "canOnlyRemoveFilesOwnedByYou": MessageLookupByLibrary.simpleMessage( "Can only remove files owned by you"), "cancel": MessageLookupByLibrary.simpleMessage("Cancel"), - "cancelOtherSubscription": m9, + "cancelOtherSubscription": m12, "cancelSubscription": MessageLookupByLibrary.simpleMessage("Cancel subscription"), - "cannotAddMorePhotosAfterBecomingViewer": m10, + "cannotAddMorePhotosAfterBecomingViewer": m13, "cannotDeleteSharedFiles": MessageLookupByLibrary.simpleMessage("Cannot delete shared files"), "castIPMismatchBody": MessageLookupByLibrary.simpleMessage( @@ -454,7 +454,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Claim free storage"), "claimMore": MessageLookupByLibrary.simpleMessage("Claim more!"), "claimed": MessageLookupByLibrary.simpleMessage("Claimed"), - "claimedStorageSoFar": m11, + "claimedStorageSoFar": m14, "cleanUncategorized": MessageLookupByLibrary.simpleMessage("Clean Uncategorized"), "cleanUncategorizedDescription": MessageLookupByLibrary.simpleMessage( @@ -483,7 +483,7 @@ class MessageLookup extends MessageLookupByLibrary { "Create a link to allow people to add and view photos in your shared album without needing an Ente app or account. Great for collecting event photos."), "collaborativeLink": MessageLookupByLibrary.simpleMessage("Collaborative link"), - "collaborativeLinkCreatedFor": m12, + "collaborativeLinkCreatedFor": m15, "collaborator": MessageLookupByLibrary.simpleMessage("Collaborator"), "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": MessageLookupByLibrary.simpleMessage( @@ -512,10 +512,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Confirm your recovery key"), "connectToDevice": MessageLookupByLibrary.simpleMessage("Connect to device"), - "contactFamilyAdmin": m13, + "contactFamilyAdmin": m16, "contactSupport": MessageLookupByLibrary.simpleMessage("Contact support"), - "contactToManageSubscription": m14, + "contactToManageSubscription": m17, "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "contents": MessageLookupByLibrary.simpleMessage("Contents"), "continueLabel": MessageLookupByLibrary.simpleMessage("Continue"), @@ -559,7 +559,7 @@ class MessageLookup extends MessageLookupByLibrary { "currentUsageIs": MessageLookupByLibrary.simpleMessage("Current usage is "), "custom": MessageLookupByLibrary.simpleMessage("Custom"), - "customEndpoint": m15, + "customEndpoint": m18, "darkTheme": MessageLookupByLibrary.simpleMessage("Dark"), "dayToday": MessageLookupByLibrary.simpleMessage("Today"), "dayYesterday": MessageLookupByLibrary.simpleMessage("Yesterday"), @@ -594,11 +594,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Delete from device"), "deleteFromEnte": MessageLookupByLibrary.simpleMessage("Delete from Ente"), - "deleteItemCount": m16, + "deleteItemCount": m19, "deleteLocation": MessageLookupByLibrary.simpleMessage("Delete location"), "deletePhotos": MessageLookupByLibrary.simpleMessage("Delete photos"), - "deleteProgress": m17, + "deleteProgress": m20, "deleteReason1": MessageLookupByLibrary.simpleMessage( "It’s missing a key feature that I need"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -638,7 +638,7 @@ class MessageLookup extends MessageLookupByLibrary { "Viewers can still take screenshots or save a copy of your photos using external tools"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Please note"), - "disableLinkMessage": m18, + "disableLinkMessage": m21, "disableTwofactor": MessageLookupByLibrary.simpleMessage("Disable two-factor"), "disablingTwofactorAuthentication": @@ -659,9 +659,9 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("Download failed"), "downloading": MessageLookupByLibrary.simpleMessage("Downloading..."), - "dropSupportEmail": m19, - "duplicateFileCountWithStorageSaved": m20, - "duplicateItemsGroup": m21, + "dropSupportEmail": m22, + "duplicateFileCountWithStorageSaved": m23, + "duplicateItemsGroup": m24, "edit": MessageLookupByLibrary.simpleMessage("Edit"), "editLocation": MessageLookupByLibrary.simpleMessage("Edit location"), "editLocationTagTitle": @@ -672,8 +672,8 @@ class MessageLookup extends MessageLookupByLibrary { "Edits to location will only be seen within Ente"), "eligible": MessageLookupByLibrary.simpleMessage("eligible"), "email": MessageLookupByLibrary.simpleMessage("Email"), - "emailChangedTo": m22, - "emailNoEnteAccount": m23, + "emailChangedTo": m25, + "emailNoEnteAccount": m26, "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("Email verification"), "emailYourLogs": @@ -779,8 +779,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("File types"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("File types and names"), - "filesBackedUpFromDevice": m24, - "filesBackedUpInAlbum": m25, + "filesBackedUpFromDevice": m27, + "filesBackedUpInAlbum": m28, "filesDeleted": MessageLookupByLibrary.simpleMessage("Files deleted"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage("Files saved to gallery"), @@ -794,25 +794,25 @@ class MessageLookup extends MessageLookupByLibrary { "foundFaces": MessageLookupByLibrary.simpleMessage("Found faces"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("Free storage claimed"), - "freeStorageOnReferralSuccess": m26, + "freeStorageOnReferralSuccess": m29, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("Free storage usable"), "freeTrial": MessageLookupByLibrary.simpleMessage("Free trial"), - "freeTrialValidTill": m27, - "freeUpAccessPostDelete": m28, - "freeUpAmount": m29, + "freeTrialValidTill": m30, + "freeUpAccessPostDelete": m31, + "freeUpAmount": m32, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("Free up device space"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Save space on your device by clearing files that have been already backed up."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Free up space"), - "freeUpSpaceSaving": m30, + "freeUpSpaceSaving": m33, "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Up to 1000 memories shown in gallery"), "general": MessageLookupByLibrary.simpleMessage("General"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Generating encryption keys..."), - "genericProgress": m31, + "genericProgress": m34, "goToSettings": MessageLookupByLibrary.simpleMessage("Go to settings"), "googlePlayId": MessageLookupByLibrary.simpleMessage("Google Play ID"), "grantFullAccessPrompt": MessageLookupByLibrary.simpleMessage( @@ -886,7 +886,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "It looks like something went wrong. Please retry after some time. If the error persists, please contact our support team."), - "itemCount": m32, + "itemCount": m35, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Items show the number of days remaining before permanent deletion"), @@ -912,7 +912,7 @@ class MessageLookup extends MessageLookupByLibrary { "linkDeviceLimit": MessageLookupByLibrary.simpleMessage("Device limit"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Enabled"), "linkExpired": MessageLookupByLibrary.simpleMessage("Expired"), - "linkExpiresOn": m33, + "linkExpiresOn": m36, "linkExpiry": MessageLookupByLibrary.simpleMessage("Link expiry"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("Link has expired"), @@ -989,7 +989,7 @@ class MessageLookup extends MessageLookupByLibrary { "maps": MessageLookupByLibrary.simpleMessage("Maps"), "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), - "memoryCount": m34, + "memoryCount": m0, "merchandise": MessageLookupByLibrary.simpleMessage("Merchandise"), "mlConsent": MessageLookupByLibrary.simpleMessage("Enable machine learning"), @@ -1012,11 +1012,11 @@ class MessageLookup extends MessageLookupByLibrary { "moments": MessageLookupByLibrary.simpleMessage("Moments"), "monthly": MessageLookupByLibrary.simpleMessage("Monthly"), "moreDetails": MessageLookupByLibrary.simpleMessage("More details"), - "moveItem": m35, + "moveItem": m37, "moveToAlbum": MessageLookupByLibrary.simpleMessage("Move to album"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Move to hidden album"), - "movedSuccessfullyTo": m36, + "movedSuccessfullyTo": m38, "movedToTrash": MessageLookupByLibrary.simpleMessage("Moved to trash"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage("Moving files to album..."), @@ -1062,7 +1062,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("No results found"), "noSystemLockFound": MessageLookupByLibrary.simpleMessage("No system lock found"), - "notPersonLabel": m37, + "notPersonLabel": m39, "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage("Nothing shared with you yet"), "nothingToSeeHere": @@ -1072,7 +1072,7 @@ class MessageLookup extends MessageLookupByLibrary { "onDevice": MessageLookupByLibrary.simpleMessage("On device"), "onEnte": MessageLookupByLibrary.simpleMessage( "On ente"), - "onlyFamilyAdminCanChangeCode": m38, + "onlyFamilyAdminCanChangeCode": m40, "oops": MessageLookupByLibrary.simpleMessage("Oops"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage("Oops, could not save edits"), @@ -1100,7 +1100,7 @@ class MessageLookup extends MessageLookupByLibrary { "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage( "Password changed successfully"), "passwordLock": MessageLookupByLibrary.simpleMessage("Password lock"), - "passwordStrength": m39, + "passwordStrength": m41, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "Password strength is calculated considering the length of the password, used characters, and whether or not the password appears in the top 10,000 most used passwords"), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -1110,7 +1110,7 @@ class MessageLookup extends MessageLookupByLibrary { "paymentFailed": MessageLookupByLibrary.simpleMessage("Payment failed"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Unfortunately your payment failed. Please contact support and we\'ll help you out!"), - "paymentFailedTalkToProvider": m40, + "paymentFailedTalkToProvider": m42, "pendingItems": MessageLookupByLibrary.simpleMessage("Pending items"), "pendingSync": MessageLookupByLibrary.simpleMessage("Pending sync"), "people": MessageLookupByLibrary.simpleMessage("People"), @@ -1136,7 +1136,7 @@ class MessageLookup extends MessageLookupByLibrary { "pinAlbum": MessageLookupByLibrary.simpleMessage("Pin album"), "pinLock": MessageLookupByLibrary.simpleMessage("PIN lock"), "playOnTv": MessageLookupByLibrary.simpleMessage("Play album on TV"), - "playStoreFreeTrialValidTill": m41, + "playStoreFreeTrialValidTill": m43, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("PlayStore subscription"), "pleaseCheckYourInternetConnectionAndTryAgain": @@ -1148,14 +1148,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Please contact support if the problem persists"), - "pleaseEmailUsAt": m42, + "pleaseEmailUsAt": m44, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage("Please grant permissions"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Please login again"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Please select quick links to remove"), - "pleaseSendTheLogsTo": m43, + "pleaseSendTheLogsTo": m45, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Please try again"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1190,7 +1190,7 @@ class MessageLookup extends MessageLookupByLibrary { "raiseTicket": MessageLookupByLibrary.simpleMessage("Raise ticket"), "rateTheApp": MessageLookupByLibrary.simpleMessage("Rate the app"), "rateUs": MessageLookupByLibrary.simpleMessage("Rate us"), - "rateUsOnStore": m44, + "rateUsOnStore": m46, "recover": MessageLookupByLibrary.simpleMessage("Recover"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Recover account"), @@ -1224,7 +1224,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Give this code to your friends"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. They sign up for a paid plan"), - "referralStep3": m45, + "referralStep3": m47, "referrals": MessageLookupByLibrary.simpleMessage("Referrals"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Referrals are currently paused"), @@ -1250,7 +1250,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Remove link"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Remove participant"), - "removeParticipantBody": m46, + "removeParticipantBody": m48, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Remove person label"), "removePublicLink": @@ -1268,7 +1268,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("Rename file"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Renew subscription"), - "renewsOn": m47, + "renewsOn": m49, "reportABug": MessageLookupByLibrary.simpleMessage("Report a bug"), "reportBug": MessageLookupByLibrary.simpleMessage("Report bug"), "resendEmail": MessageLookupByLibrary.simpleMessage("Resend email"), @@ -1336,7 +1336,7 @@ class MessageLookup extends MessageLookupByLibrary { "Group photos that are taken within some radius of a photo"), "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage( "Invite people, and you\'ll see all photos shared by them here"), - "searchResultCount": m48, + "searchResultCount": m50, "security": MessageLookupByLibrary.simpleMessage("Security"), "selectALocation": MessageLookupByLibrary.simpleMessage("Select a location"), @@ -1363,8 +1363,8 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage( "Selected items will be deleted from all albums and moved to trash."), - "selectedPhotos": m49, - "selectedPhotosWithYours": m50, + "selectedPhotos": m1, + "selectedPhotosWithYours": m51, "send": MessageLookupByLibrary.simpleMessage("Send"), "sendEmail": MessageLookupByLibrary.simpleMessage("Send email"), "sendInvite": MessageLookupByLibrary.simpleMessage("Send invite"), @@ -1391,10 +1391,10 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Share an album now"), "shareLink": MessageLookupByLibrary.simpleMessage("Share link"), - "shareMyVerificationID": m51, + "shareMyVerificationID": m52, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Share only with the people you want"), - "shareTextConfirmOthersVerificationID": m52, + "shareTextConfirmOthersVerificationID": m2, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Download Ente so we can easily share original quality photos and videos\n\nhttps://ente.io"), "shareTextReferralCode": m53, diff --git a/mobile/lib/generated/intl/messages_es.dart b/mobile/lib/generated/intl/messages_es.dart index f057cefd5f..479c1538a0 100644 --- a/mobile/lib/generated/intl/messages_es.dart +++ b/mobile/lib/generated/intl/messages_es.dart @@ -20,37 +20,37 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'es'; - static String m0(count) => + static String m3(count) => "${Intl.plural(count, zero: 'Añadir colaborador', one: 'Añadir colaborador', other: 'Añadir colaboradores')}"; - static String m2(count) => + static String m4(count) => "${Intl.plural(count, one: 'Agregar elemento', other: 'Agregar elementos')}"; - static String m3(storageAmount, endDate) => + static String m5(storageAmount, endDate) => "Tu ${storageAmount} adicional es válido hasta ${endDate}"; - static String m1(count) => + static String m6(count) => "${Intl.plural(count, zero: 'Añadir espectador', one: 'Añadir espectador', other: 'Añadir espectadores')}"; - static String m4(emailOrName) => "Añadido por ${emailOrName}"; + static String m7(emailOrName) => "Añadido por ${emailOrName}"; - static String m5(albumName) => "Añadido exitosamente a ${albumName}"; + static String m8(albumName) => "Añadido exitosamente a ${albumName}"; - static String m6(count) => + static String m9(count) => "${Intl.plural(count, zero: 'No hay Participantes', one: '1 Participante', other: '${count} Participantes')}"; - static String m7(versionValue) => "Versión: ${versionValue}"; + static String m10(versionValue) => "Versión: ${versionValue}"; - static String m8(freeAmount, storageUnit) => + static String m11(freeAmount, storageUnit) => "${freeAmount} ${storageUnit} gratis"; - static String m9(paymentProvider) => + static String m12(paymentProvider) => "Por favor, cancela primero tu suscripción existente de ${paymentProvider}"; - static String m10(user) => + static String m13(user) => "${user} no podrá añadir más fotos a este álbum\n\nTodavía podrán eliminar las fotos ya añadidas por ellos"; - static String m11(isFamilyMember, storageAmountInGb) => + static String m14(isFamilyMember, storageAmountInGb) => "${Intl.select(isFamilyMember, { 'true': 'Tu familia ha reclamado ${storageAmountInGb} GB hasta el momento', @@ -60,111 +60,113 @@ class MessageLookup extends MessageLookupByLibrary { '¡Tú has reclamado ${storageAmountInGb} GB hasta el momento!', })}"; - static String m12(albumName) => + static String m15(albumName) => "Enlace colaborativo creado para ${albumName}"; - static String m13(familyAdminEmail) => + static String m16(familyAdminEmail) => "Por favor contacta con ${familyAdminEmail} para administrar tu suscripción"; - static String m14(provider) => + static String m17(provider) => "Por favor, contáctanos en support@ente.io para gestionar tu suscripción a ${provider}."; - static String m15(endpoint) => "Conectado a ${endpoint}"; + static String m18(endpoint) => "Conectado a ${endpoint}"; - static String m16(count) => + static String m19(count) => "${Intl.plural(count, one: 'Elimina ${count} elemento', other: 'Elimina ${count} elementos')}"; - static String m17(currentlyDeleting, totalCount) => + static String m20(currentlyDeleting, totalCount) => "Borrando ${currentlyDeleting} / ${totalCount}"; - static String m18(albumName) => + static String m21(albumName) => "Esto eliminará el enlace público para acceder a \"${albumName}\"."; - static String m19(supportEmail) => + static String m22(supportEmail) => "Por favor, envía un correo electrónico a ${supportEmail} desde tu dirección de correo electrónico registrada"; - static String m20(count, storageSaved) => + static String m23(count, storageSaved) => "¡Has limpiado ${Intl.plural(count, one: '${count} archivo duplicado', other: '${count} archivos duplicados')}, ahorrando (${storageSaved}!)"; - static String m21(count, formattedSize) => + static String m24(count, formattedSize) => "${count} archivos, ${formattedSize} cada uno"; - static String m22(newEmail) => "Correo cambiado a ${newEmail}"; + static String m25(newEmail) => "Correo cambiado a ${newEmail}"; - static String m23(email) => + static String m26(email) => "${email} no tiene una cuente en Ente.\n\nEnvíale una invitación para compartir fotos."; - static String m24(count, formattedNumber) => + static String m27(count, formattedNumber) => "${Intl.plural(count, one: '1 archivo', other: '${formattedNumber} archivos')} en este dispositivo han sido respaldados de forma segura"; - static String m25(count, formattedNumber) => + static String m28(count, formattedNumber) => "${Intl.plural(count, one: '1 archivo', other: '${formattedNumber} archivos')} en este álbum ha sido respaldado de forma segura"; - static String m26(storageAmountInGB) => + static String m29(storageAmountInGB) => "${storageAmountInGB} GB cada vez que alguien se registra en un plan de pago y aplica tu código"; - static String m27(endDate) => "Prueba gratuita válida hasta ${endDate}"; + static String m30(endDate) => "Prueba gratuita válida hasta ${endDate}"; - static String m28(count) => + static String m31(count) => "Aún puedes acceder ${Intl.plural(count, one: 'a él', other: 'a ellos')} en Ente mientras tengas una suscripción activa"; - static String m29(sizeInMBorGB) => "Liberar ${sizeInMBorGB}"; + static String m32(sizeInMBorGB) => "Liberar ${sizeInMBorGB}"; - static String m30(count, formattedSize) => + static String m33(count, formattedSize) => "${Intl.plural(count, one: 'Se puede eliminar del dispositivo para liberar ${formattedSize}', other: 'Se pueden eliminar del dispositivo para liberar ${formattedSize}')}"; - static String m31(currentlyProcessing, totalCount) => + static String m34(currentlyProcessing, totalCount) => "Procesando ${currentlyProcessing} / ${totalCount}"; - static String m32(count) => + static String m35(count) => "${Intl.plural(count, one: '${count} elemento', other: '${count} elementos')}"; - static String m33(expiryTime) => "El enlace caducará en ${expiryTime}"; + static String m36(expiryTime) => "El enlace caducará en ${expiryTime}"; - static String m34(count, formattedCount) => + static String m0(count, formattedCount) => "${Intl.plural(count, zero: 'sin recuerdos', one: '${formattedCount} recuerdo', other: '${formattedCount} recuerdos')}"; - static String m35(count) => + static String m37(count) => "${Intl.plural(count, one: 'Mover elemento', other: 'Mover elementos')}"; - static String m36(albumName) => "Movido exitosamente a ${albumName}"; + static String m38(albumName) => "Movido exitosamente a ${albumName}"; - static String m39(passwordStrengthValue) => - "Seguridad de la contraseña : ${passwordStrengthValue}"; + static String m39(name) => "¿No es ${name}?"; - static String m40(providerName) => + static String m41(passwordStrengthValue) => + "Seguridad de la contraseña: ${passwordStrengthValue}"; + + static String m42(providerName) => "Por favor, habla con el soporte de ${providerName} si se te cobró"; - static String m41(endDate) => + static String m43(endDate) => "Prueba gratuita válida hasta ${endDate}.\nPuedes elegir un plan de pago después."; - static String m42(toEmail) => + static String m44(toEmail) => "Por favor, envíanos un correo electrónico a ${toEmail}"; - static String m43(toEmail) => "Por favor, envía los registros a ${toEmail}"; + static String m45(toEmail) => "Por favor, envía los registros a ${toEmail}"; - static String m44(storeName) => "Califícanos en ${storeName}"; + static String m46(storeName) => "Califícanos en ${storeName}"; - static String m45(storageInGB) => + static String m47(storageInGB) => "3. Ambos obtienen ${storageInGB} GB* gratis"; - static String m46(userEmail) => + static String m48(userEmail) => "${userEmail} será eliminado de este álbum compartido\n\nCualquier foto añadida por ellos también será eliminada del álbum"; - static String m47(endDate) => "La suscripción se renueva el ${endDate}"; + static String m49(endDate) => "La suscripción se renueva el ${endDate}"; - static String m48(count) => + static String m50(count) => "${Intl.plural(count, one: '${count} resultado encontrado', other: '${count} resultados encontrados')}"; - static String m49(count) => "${count} seleccionados"; + static String m1(count) => "${count} seleccionados"; - static String m50(count, yourCount) => + static String m51(count, yourCount) => "${count} seleccionados (${yourCount} tuyos)"; - static String m51(verificationID) => + static String m52(verificationID) => "Aquí está mi ID de verificación: ${verificationID} para ente.io."; - static String m52(verificationID) => + static String m2(verificationID) => "Hola, ¿puedes confirmar que esta es tu ID de verificación ente.io: ${verificationID}?"; static String m53(referralCode, referralStorageInGB) => @@ -234,10 +236,10 @@ class MessageLookup extends MessageLookupByLibrary { "Agregar nuevo correo electrónico"), "addCollaborator": MessageLookupByLibrary.simpleMessage("Agregar colaborador"), - "addCollaborators": m0, + "addCollaborators": m3, "addFromDevice": MessageLookupByLibrary.simpleMessage( "Agregar desde el dispositivo"), - "addItem": m2, + "addItem": m4, "addLocation": MessageLookupByLibrary.simpleMessage("Agregar ubicación"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Añadir"), @@ -245,7 +247,7 @@ class MessageLookup extends MessageLookupByLibrary { "addNew": MessageLookupByLibrary.simpleMessage("Añadir nuevo"), "addOnPageSubtitle": MessageLookupByLibrary.simpleMessage( "Detalles de los complementos"), - "addOnValidTill": m3, + "addOnValidTill": m5, "addOns": MessageLookupByLibrary.simpleMessage("Complementos"), "addPhotos": MessageLookupByLibrary.simpleMessage("Agregar fotos"), "addSelected": @@ -255,12 +257,12 @@ class MessageLookup extends MessageLookupByLibrary { "addToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Añadir al álbum oculto"), "addViewer": MessageLookupByLibrary.simpleMessage("Añadir espectador"), - "addViewers": m1, + "addViewers": m6, "addYourPhotosNow": MessageLookupByLibrary.simpleMessage("Añade tus fotos ahora"), "addedAs": MessageLookupByLibrary.simpleMessage("Agregado como"), - "addedBy": m4, - "addedSuccessfullyTo": m5, + "addedBy": m7, + "addedSuccessfullyTo": m8, "addingToFavorites": MessageLookupByLibrary.simpleMessage("Añadiendo a favoritos..."), "advanced": MessageLookupByLibrary.simpleMessage("Avanzado"), @@ -273,7 +275,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Después de una semana"), "after1Year": MessageLookupByLibrary.simpleMessage("Después de un año"), "albumOwner": MessageLookupByLibrary.simpleMessage("Propietario"), - "albumParticipantsCount": m6, + "albumParticipantsCount": m9, "albumTitle": MessageLookupByLibrary.simpleMessage("Título del álbum"), "albumUpdated": MessageLookupByLibrary.simpleMessage("Álbum actualizado"), @@ -310,10 +312,8 @@ class MessageLookup extends MessageLookupByLibrary { "Android, iOS, Web, Computadora"), "androidSignInTitle": MessageLookupByLibrary.simpleMessage("Autentificación requerida"), - "appLock": MessageLookupByLibrary.simpleMessage("App lock"), - "appLockDescriptions": MessageLookupByLibrary.simpleMessage( - "Choose between your device\'s default lock screen and a custom lock screen with a PIN or password."), - "appVersion": m7, + "appLock": MessageLookupByLibrary.simpleMessage("Aplicación bloqueada"), + "appVersion": m10, "appleId": MessageLookupByLibrary.simpleMessage("ID de Apple"), "apply": MessageLookupByLibrary.simpleMessage("Aplicar"), "applyCodeTitle": MessageLookupByLibrary.simpleMessage("Usar código"), @@ -358,8 +358,6 @@ class MessageLookup extends MessageLookupByLibrary { "Por favor, autentícate para configurar la autenticación de dos factores"), "authToInitiateAccountDeletion": MessageLookupByLibrary.simpleMessage( "Por favor, autentícate para iniciar la eliminación de la cuenta"), - "authToViewPasskey": MessageLookupByLibrary.simpleMessage( - "Please authenticate to view your passkey"), "authToViewYourActiveSessions": MessageLookupByLibrary.simpleMessage( "Por favor, autentícate para ver tus sesiones activas"), "authToViewYourHiddenFiles": MessageLookupByLibrary.simpleMessage( @@ -379,9 +377,9 @@ class MessageLookup extends MessageLookupByLibrary { "Aquí verás los dispositivos de transmisión disponibles."), "autoCastiOSPermission": MessageLookupByLibrary.simpleMessage( "Asegúrate de que los permisos de la red local están activados para la aplicación Ente Fotos, en Configuración."), - "autoLock": MessageLookupByLibrary.simpleMessage("Auto lock"), + "autoLock": MessageLookupByLibrary.simpleMessage("Autobloqueo"), "autoLockFeatureDescription": MessageLookupByLibrary.simpleMessage( - "Time after which the app locks after being put in the background"), + "Tiempo después de que la aplicación esté en segundo plano"), "autoLogoutMessage": MessageLookupByLibrary.simpleMessage( "Debido a un fallo técnico, has sido desconectado. Nuestras disculpas por las molestias."), "autoPair": @@ -389,7 +387,7 @@ class MessageLookup extends MessageLookupByLibrary { "autoPairDesc": MessageLookupByLibrary.simpleMessage( "El emparejamiento automático funciona sólo con dispositivos compatibles con Chromecast."), "available": MessageLookupByLibrary.simpleMessage("Disponible"), - "availableStorageSpace": m8, + "availableStorageSpace": m11, "backedUpFolders": MessageLookupByLibrary.simpleMessage("Carpetas respaldadas"), "backup": MessageLookupByLibrary.simpleMessage("Copia de respaldo"), @@ -416,10 +414,10 @@ class MessageLookup extends MessageLookupByLibrary { "canOnlyRemoveFilesOwnedByYou": MessageLookupByLibrary.simpleMessage( "Sólo puede eliminar archivos de tu propiedad"), "cancel": MessageLookupByLibrary.simpleMessage("Cancelar"), - "cancelOtherSubscription": m9, + "cancelOtherSubscription": m12, "cancelSubscription": MessageLookupByLibrary.simpleMessage("Cancelar suscripción"), - "cannotAddMorePhotosAfterBecomingViewer": m10, + "cannotAddMorePhotosAfterBecomingViewer": m13, "cannotDeleteSharedFiles": MessageLookupByLibrary.simpleMessage( "No se pueden eliminar los archivos compartidos"), "castIPMismatchBody": MessageLookupByLibrary.simpleMessage( @@ -445,25 +443,11 @@ class MessageLookup extends MessageLookupByLibrary { "Revisa tu bandeja de entrada (y spam) para completar la verificación"), "checkStatus": MessageLookupByLibrary.simpleMessage("Comprobar estado"), "checking": MessageLookupByLibrary.simpleMessage("Comprobando..."), - "cl_guest_view_call_to_action": MessageLookupByLibrary.simpleMessage( - "Selecciona fotos y prueba la \"Vista de Invitado\"."), - "cl_guest_view_description": MessageLookupByLibrary.simpleMessage( - "¿Vas a mostrar fotos a un amigo? No te preocupes por si desliza demasiado. La vista de invitado bloqueará las fotos que selecciones."), - "cl_guest_view_title": - MessageLookupByLibrary.simpleMessage("Vista de Invitado"), - "cl_panorama_viewer_description": MessageLookupByLibrary.simpleMessage( - "Hemos añadido soporte para ver fotos panorámicas con vistas de 360 grados. ¡La experiencia es inmersiva con navegación basada en el movimiento!"), - "cl_panorama_viewer_title": - MessageLookupByLibrary.simpleMessage("Visor Panorámico"), - "cl_video_player_description": MessageLookupByLibrary.simpleMessage( - "Presentamos un nuevo reproductor de video, con mejores controles de reproducción y soporte para videos HDR."), - "cl_video_player_title": - MessageLookupByLibrary.simpleMessage("Reproductor de Video"), "claimFreeStorage": MessageLookupByLibrary.simpleMessage( "Reclamar almacenamiento gratis"), "claimMore": MessageLookupByLibrary.simpleMessage("¡Reclama más!"), "claimed": MessageLookupByLibrary.simpleMessage("Reclamado"), - "claimedStorageSoFar": m11, + "claimedStorageSoFar": m14, "cleanUncategorized": MessageLookupByLibrary.simpleMessage("Limpiar no categorizado"), "cleanUncategorizedDescription": MessageLookupByLibrary.simpleMessage( @@ -490,7 +474,7 @@ class MessageLookup extends MessageLookupByLibrary { "Crea un enlace para permitir que otros pueda añadir y ver fotos en tu álbum compartido sin necesitar la aplicación Ente o una cuenta. Genial para recolectar fotos de eventos."), "collaborativeLink": MessageLookupByLibrary.simpleMessage("Enlace colaborativo"), - "collaborativeLinkCreatedFor": m12, + "collaborativeLinkCreatedFor": m15, "collaborator": MessageLookupByLibrary.simpleMessage("Colaborador"), "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": MessageLookupByLibrary.simpleMessage( @@ -507,7 +491,7 @@ class MessageLookup extends MessageLookupByLibrary { "confirm2FADisable": MessageLookupByLibrary.simpleMessage( "¿Estás seguro de que deseas deshabilitar la autenticación de doble factor?"), "confirmAccountDeletion": - MessageLookupByLibrary.simpleMessage("Corfirmar borrado de cuenta"), + MessageLookupByLibrary.simpleMessage("Confirmar borrado de cuenta"), "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( "Sí, quiero eliminar permanentemente esta cuenta y todos sus datos."), "confirmPassword": @@ -520,10 +504,10 @@ class MessageLookup extends MessageLookupByLibrary { "Confirma tu clave de recuperación"), "connectToDevice": MessageLookupByLibrary.simpleMessage("Conectar a dispositivo"), - "contactFamilyAdmin": m13, + "contactFamilyAdmin": m16, "contactSupport": MessageLookupByLibrary.simpleMessage("Contactar con soporte"), - "contactToManageSubscription": m14, + "contactToManageSubscription": m17, "contacts": MessageLookupByLibrary.simpleMessage("Contactos"), "contents": MessageLookupByLibrary.simpleMessage("Contenidos"), "continueLabel": MessageLookupByLibrary.simpleMessage("Continuar"), @@ -568,7 +552,7 @@ class MessageLookup extends MessageLookupByLibrary { "currentUsageIs": MessageLookupByLibrary.simpleMessage("El uso actual es de "), "custom": MessageLookupByLibrary.simpleMessage("Personalizado"), - "customEndpoint": m15, + "customEndpoint": m18, "darkTheme": MessageLookupByLibrary.simpleMessage("Oscuro"), "dayToday": MessageLookupByLibrary.simpleMessage("Hoy"), "dayYesterday": MessageLookupByLibrary.simpleMessage("Ayer"), @@ -604,12 +588,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Eliminar del dispositivo"), "deleteFromEnte": MessageLookupByLibrary.simpleMessage("Eliminar de Ente"), - "deleteItemCount": m16, + "deleteItemCount": m19, "deleteLocation": MessageLookupByLibrary.simpleMessage("Borrar la ubicación"), "deletePhotos": MessageLookupByLibrary.simpleMessage("Borrar las fotos"), - "deleteProgress": m17, + "deleteProgress": m20, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Falta una característica clave que necesito"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -638,7 +622,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Introduce el código"), "deviceFilesAutoUploading": MessageLookupByLibrary.simpleMessage( "Los archivos añadidos a este álbum de dispositivo se subirán automáticamente a Ente."), - "deviceLock": MessageLookupByLibrary.simpleMessage("Device lock"), + "deviceLock": + MessageLookupByLibrary.simpleMessage("Dispositivo Bloqueado"), "deviceLockExplanation": MessageLookupByLibrary.simpleMessage( "Deshabilita el bloqueo de pantalla del dispositivo cuando Ente está en primer plano y haya una copia de seguridad en curso. Normalmente esto no es necesario, pero puede ayudar a que las grandes cargas y las importaciones iniciales de grandes bibliotecas se completen más rápido."), "deviceNotFound": @@ -650,7 +635,7 @@ class MessageLookup extends MessageLookupByLibrary { "Los espectadores todavía pueden tomar capturas de pantalla o guardar una copia de tus fotos usando herramientas externas"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Por favor, ten en cuenta"), - "disableLinkMessage": m18, + "disableLinkMessage": m21, "disableTwofactor": MessageLookupByLibrary.simpleMessage("Deshabilitar dos factores"), "disablingTwofactorAuthentication": @@ -673,9 +658,9 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("Descarga fallida"), "downloading": MessageLookupByLibrary.simpleMessage("Descargando..."), - "dropSupportEmail": m19, - "duplicateFileCountWithStorageSaved": m20, - "duplicateItemsGroup": m21, + "dropSupportEmail": m22, + "duplicateFileCountWithStorageSaved": m23, + "duplicateItemsGroup": m24, "edit": MessageLookupByLibrary.simpleMessage("Editar"), "editLocation": MessageLookupByLibrary.simpleMessage("Editar la ubicación"), @@ -688,8 +673,8 @@ class MessageLookup extends MessageLookupByLibrary { "Las ediciones a la ubicación sólo se verán dentro de Ente"), "eligible": MessageLookupByLibrary.simpleMessage("elegible"), "email": MessageLookupByLibrary.simpleMessage("Correo electrónico"), - "emailChangedTo": m22, - "emailNoEnteAccount": m23, + "emailChangedTo": m25, + "emailNoEnteAccount": m26, "emailVerificationToggle": MessageLookupByLibrary.simpleMessage( "Verificación por correo electrónico"), "emailYourLogs": MessageLookupByLibrary.simpleMessage( @@ -736,7 +721,8 @@ class MessageLookup extends MessageLookupByLibrary { "Introduce una contraseña que podamos usar para cifrar tus datos"), "enterPersonName": MessageLookupByLibrary.simpleMessage( "Ingresar el nombre de una persona"), - "enterPin": MessageLookupByLibrary.simpleMessage("Enter PIN"), + "enterPin": + MessageLookupByLibrary.simpleMessage("Ingresa tu contraseña"), "enterReferralCode": MessageLookupByLibrary.simpleMessage( "Ingresar código de referencia"), "enterThe6digitCodeFromnyourAuthenticatorApp": @@ -799,8 +785,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Tipos de archivos"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Tipos de archivo y nombres"), - "filesBackedUpFromDevice": m24, - "filesBackedUpInAlbum": m25, + "filesBackedUpFromDevice": m27, + "filesBackedUpInAlbum": m28, "filesDeleted": MessageLookupByLibrary.simpleMessage("Archivos eliminados"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage( @@ -815,25 +801,25 @@ class MessageLookup extends MessageLookupByLibrary { "foundFaces": MessageLookupByLibrary.simpleMessage("Caras encontradas"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage( "Almacenamiento gratuito reclamado"), - "freeStorageOnReferralSuccess": m26, + "freeStorageOnReferralSuccess": m29, "freeStorageUsable": MessageLookupByLibrary.simpleMessage( "Almacenamiento libre disponible"), "freeTrial": MessageLookupByLibrary.simpleMessage("Prueba gratuita"), - "freeTrialValidTill": m27, - "freeUpAccessPostDelete": m28, - "freeUpAmount": m29, + "freeTrialValidTill": m30, + "freeUpAccessPostDelete": m31, + "freeUpAmount": m32, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage( "Liberar espacio del dispositivo"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Ahorra espacio en tu dispositivo limpiando archivos que ya han sido respaldados."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Liberar espacio"), - "freeUpSpaceSaving": m30, + "freeUpSpaceSaving": m33, "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Hasta 1000 memorias mostradas en la galería"), "general": MessageLookupByLibrary.simpleMessage("General"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Generando claves de encriptación..."), - "genericProgress": m31, + "genericProgress": m34, "goToSettings": MessageLookupByLibrary.simpleMessage("Ir a Ajustes"), "googlePlayId": MessageLookupByLibrary.simpleMessage("ID de Google Play"), @@ -843,9 +829,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Conceder permiso"), "groupNearbyPhotos": MessageLookupByLibrary.simpleMessage("Agrupar fotos cercanas"), - "guestView": MessageLookupByLibrary.simpleMessage("Guest view"), + "guestView": MessageLookupByLibrary.simpleMessage("Vista de invitado"), "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( - "To enable guest view, please setup device passcode or screen lock in your system settings."), + "Para habilitar la vista de invitados, por favor configure el código de acceso del dispositivo o el bloqueo de pantalla en los ajustes de su sistema."), "hearUsExplanation": MessageLookupByLibrary.simpleMessage( "No rastreamos las aplicaciones instaladas. ¡Nos ayudarías si nos dijeras dónde nos encontraste!"), "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( @@ -853,11 +839,12 @@ class MessageLookup extends MessageLookupByLibrary { "help": MessageLookupByLibrary.simpleMessage("Ayuda"), "hidden": MessageLookupByLibrary.simpleMessage("Oculto"), "hide": MessageLookupByLibrary.simpleMessage("Ocultar"), - "hideContent": MessageLookupByLibrary.simpleMessage("Hide content"), + "hideContent": + MessageLookupByLibrary.simpleMessage("Ocultar contenido"), "hideContentDescriptionAndroid": MessageLookupByLibrary.simpleMessage( - "Hides app content in the app switcher and disables screenshots"), + "Oculta el contenido de la aplicación en el selector de aplicaciones y desactivar capturas de pantalla"), "hideContentDescriptionIos": MessageLookupByLibrary.simpleMessage( - "Hides app content in the app switcher"), + "Ocultar el contenido de la aplicación en el selector de aplicaciones"), "hiding": MessageLookupByLibrary.simpleMessage("Ocultando..."), "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("Alojado en OSM France"), @@ -872,7 +859,7 @@ class MessageLookup extends MessageLookupByLibrary { "ignoreUpdate": MessageLookupByLibrary.simpleMessage("Ignorar"), "ignoredFolderUploadReason": MessageLookupByLibrary.simpleMessage( "Algunos archivos de este álbum son ignorados de la carga porque previamente habían sido borrados de Ente."), - "immediately": MessageLookupByLibrary.simpleMessage("Immediately"), + "immediately": MessageLookupByLibrary.simpleMessage("Inmediatamente"), "importing": MessageLookupByLibrary.simpleMessage("Importando...."), "incorrectCode": MessageLookupByLibrary.simpleMessage("Código incorrecto"), @@ -910,7 +897,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Parece que algo salió mal. Por favor, vuelve a intentarlo después de algún tiempo. Si el error persiste, ponte en contacto con nuestro equipo de soporte."), - "itemCount": m32, + "itemCount": m35, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Los artículos muestran el número de días restantes antes de ser borrados permanente"), @@ -940,7 +927,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Límite del dispositivo"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Habilitado"), "linkExpired": MessageLookupByLibrary.simpleMessage("Vencido"), - "linkExpiresOn": m33, + "linkExpiresOn": m36, "linkExpiry": MessageLookupByLibrary.simpleMessage("Enlace vence"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("El enlace ha caducado"), @@ -1022,10 +1009,8 @@ class MessageLookup extends MessageLookupByLibrary { "maps": MessageLookupByLibrary.simpleMessage("Mapas"), "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), - "memoryCount": m34, + "memoryCount": m0, "merchandise": MessageLookupByLibrary.simpleMessage("Mercancías"), - "mlIndexingDescription": MessageLookupByLibrary.simpleMessage( - "Por favor, ten en cuenta que el aprendizaje automático resultará en un mayor ancho de banda y uso de batería hasta que todos los elementos sean indexados."), "mobileWebDesktop": MessageLookupByLibrary.simpleMessage("Celular, Web, Computadora"), "moderateStrength": MessageLookupByLibrary.simpleMessage("Moderada"), @@ -1034,11 +1019,11 @@ class MessageLookup extends MessageLookupByLibrary { "Modifica tu consulta o intenta buscar"), "moments": MessageLookupByLibrary.simpleMessage("Momentos"), "monthly": MessageLookupByLibrary.simpleMessage("Mensual"), - "moveItem": m35, + "moveItem": m37, "moveToAlbum": MessageLookupByLibrary.simpleMessage("Mover al álbum"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Mover al álbum oculto"), - "movedSuccessfullyTo": m36, + "movedSuccessfullyTo": m38, "movedToTrash": MessageLookupByLibrary.simpleMessage("Movido a la papelera"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1052,7 +1037,7 @@ class MessageLookup extends MessageLookupByLibrary { "newAlbum": MessageLookupByLibrary.simpleMessage("Nuevo álbum"), "newToEnte": MessageLookupByLibrary.simpleMessage("Nuevo en Ente"), "newest": MessageLookupByLibrary.simpleMessage("Más reciente"), - "next": MessageLookupByLibrary.simpleMessage("Next"), + "next": MessageLookupByLibrary.simpleMessage("Siguiente"), "no": MessageLookupByLibrary.simpleMessage("No"), "noAlbumsSharedByYouYet": MessageLookupByLibrary.simpleMessage( "Aún no has compartido ningún álbum"), @@ -1075,8 +1060,8 @@ class MessageLookup extends MessageLookupByLibrary { "No se están respaldando fotos ahora mismo"), "noPhotosFoundHere": MessageLookupByLibrary.simpleMessage( "No se encontró ninguna foto aquí"), - "noQuickLinksSelected": - MessageLookupByLibrary.simpleMessage("No quick links selected"), + "noQuickLinksSelected": MessageLookupByLibrary.simpleMessage( + "No se han seleccionado enlaces rápidos"), "noRecoveryKey": MessageLookupByLibrary.simpleMessage("¿Sin clave de recuperación?"), "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( @@ -1084,8 +1069,9 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Sin resultados"), "noResultsFound": MessageLookupByLibrary.simpleMessage( "No se han encontrado resultados"), - "noSystemLockFound": - MessageLookupByLibrary.simpleMessage("No system lock found"), + "noSystemLockFound": MessageLookupByLibrary.simpleMessage( + "Bloqueo de sistema no encontrado"), + "notPersonLabel": m39, "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( "Aún no hay nada compartido contigo"), "nothingToSeeHere": MessageLookupByLibrary.simpleMessage( @@ -1114,6 +1100,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Emparejar con PIN"), "pairingComplete": MessageLookupByLibrary.simpleMessage("Emparejamiento completo"), + "panorama": MessageLookupByLibrary.simpleMessage("Panorama"), "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage( "La verificación aún está pendiente"), "passkey": MessageLookupByLibrary.simpleMessage("Clave de acceso"), @@ -1124,9 +1111,9 @@ class MessageLookup extends MessageLookupByLibrary { "Contraseña cambiada correctamente"), "passwordLock": MessageLookupByLibrary.simpleMessage("Bloqueo por contraseña"), - "passwordStrength": m39, + "passwordStrength": m41, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( - "Password strength is calculated considering the length of the password, used characters, and whether or not the password appears in the top 10,000 most used passwords"), + "La intensidad de la contraseña se calcula teniendo en cuenta la longitud de la contraseña, los caracteres utilizados, y si la contraseña aparece o no en el top 10,000 de contraseñas más usadas"), "passwordWarning": MessageLookupByLibrary.simpleMessage( "No almacenamos esta contraseña, así que si la olvidas, no podemos descifrar tus datos"), "paymentDetails": @@ -1134,7 +1121,7 @@ class MessageLookup extends MessageLookupByLibrary { "paymentFailed": MessageLookupByLibrary.simpleMessage("Pago fallido"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Lamentablemente tu pago falló. Por favor, ¡contacta con el soporte técnico y te ayudaremos!"), - "paymentFailedTalkToProvider": m40, + "paymentFailedTalkToProvider": m42, "pendingItems": MessageLookupByLibrary.simpleMessage("Elementos pendientes"), "pendingSync": @@ -1160,10 +1147,10 @@ class MessageLookup extends MessageLookupByLibrary { "pickCenterPoint": MessageLookupByLibrary.simpleMessage("Elegir punto central"), "pinAlbum": MessageLookupByLibrary.simpleMessage("Fijar álbum"), - "pinLock": MessageLookupByLibrary.simpleMessage("PIN lock"), + "pinLock": MessageLookupByLibrary.simpleMessage("PIN Bloqueado"), "playOnTv": MessageLookupByLibrary.simpleMessage("Reproducir álbum en TV"), - "playStoreFreeTrialValidTill": m41, + "playStoreFreeTrialValidTill": m43, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("Suscripción en la PlayStore"), "pleaseCheckYourInternetConnectionAndTryAgain": @@ -1175,14 +1162,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Por favor, contacta a soporte técnico si el problema persiste"), - "pleaseEmailUsAt": m42, + "pleaseEmailUsAt": m44, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage("Por favor, concede permiso"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage( "Por favor, vuelve a iniciar sesión"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( - "Please select quick links to remove"), - "pleaseSendTheLogsTo": m43, + "Por favor, selecciona enlaces rápidos para eliminar"), + "pleaseSendTheLogsTo": m45, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Por favor, inténtalo nuevamente"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1219,7 +1206,7 @@ class MessageLookup extends MessageLookupByLibrary { "rateTheApp": MessageLookupByLibrary.simpleMessage("Evalúa la aplicación"), "rateUs": MessageLookupByLibrary.simpleMessage("Califícanos"), - "rateUsOnStore": m44, + "rateUsOnStore": m46, "recover": MessageLookupByLibrary.simpleMessage("Recuperar"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Recuperar cuenta"), @@ -1246,15 +1233,15 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Recrear contraseña"), "reddit": MessageLookupByLibrary.simpleMessage("Reddit"), "reenterPassword": - MessageLookupByLibrary.simpleMessage("Re-enter password"), - "reenterPin": MessageLookupByLibrary.simpleMessage("Re-enter PIN"), + MessageLookupByLibrary.simpleMessage("Rescribe tu contraseña"), + "reenterPin": MessageLookupByLibrary.simpleMessage("Rescribe tu PIN"), "referFriendsAnd2xYourPlan": MessageLookupByLibrary.simpleMessage( "Refiere a amigos y 2x su plan"), "referralStep1": MessageLookupByLibrary.simpleMessage( "1. Dale este código a tus amigos"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Se inscriben a un plan pagado"), - "referralStep3": m45, + "referralStep3": m47, "referrals": MessageLookupByLibrary.simpleMessage("Referidos"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Las referencias están actualmente en pausa"), @@ -1277,17 +1264,17 @@ class MessageLookup extends MessageLookupByLibrary { "removeFromAlbumTitle": MessageLookupByLibrary.simpleMessage("¿Eliminar del álbum?"), "removeFromFavorite": - MessageLookupByLibrary.simpleMessage("Quitar de favoritos"), + MessageLookupByLibrary.simpleMessage("Remover desde favoritos"), "removeLink": MessageLookupByLibrary.simpleMessage("Eliminar enlace"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Quitar participante"), - "removeParticipantBody": m46, + "removeParticipantBody": m48, "removePersonLabel": MessageLookupByLibrary.simpleMessage( "Eliminar etiqueta de persona"), "removePublicLink": MessageLookupByLibrary.simpleMessage("Quitar enlace público"), "removePublicLinks": - MessageLookupByLibrary.simpleMessage("Remove public links"), + MessageLookupByLibrary.simpleMessage("Eliminar enlaces públicos"), "removeShareItemsWarning": MessageLookupByLibrary.simpleMessage( "Algunos de los elementos que estás eliminando fueron añadidos por otras personas, y perderás el acceso a ellos"), "removeWithQuestionMark": @@ -1299,7 +1286,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("Renombrar archivo"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Renovar suscripción"), - "renewsOn": m47, + "renewsOn": m49, "reportABug": MessageLookupByLibrary.simpleMessage("Reportar un error"), "reportBug": MessageLookupByLibrary.simpleMessage("Reportar error"), "resendEmail": @@ -1370,7 +1357,7 @@ class MessageLookup extends MessageLookupByLibrary { "Agrupar las fotos que se tomaron cerca de la localización de una foto"), "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage( "Invita a gente y verás todas las fotos compartidas aquí"), - "searchResultCount": m48, + "searchResultCount": m50, "security": MessageLookupByLibrary.simpleMessage("Seguridad"), "selectALocation": MessageLookupByLibrary.simpleMessage("Seleccionar una ubicación"), @@ -1399,8 +1386,8 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage( "Los archivos seleccionados serán eliminados de todos los álbumes y movidos a la papelera."), - "selectedPhotos": m49, - "selectedPhotosWithYours": m50, + "selectedPhotos": m1, + "selectedPhotosWithYours": m51, "send": MessageLookupByLibrary.simpleMessage("Enviar"), "sendEmail": MessageLookupByLibrary.simpleMessage("Enviar correo electrónico"), @@ -1416,8 +1403,9 @@ class MessageLookup extends MessageLookupByLibrary { "setCover": MessageLookupByLibrary.simpleMessage("Definir portada"), "setLabel": MessageLookupByLibrary.simpleMessage("Establecer"), "setNewPassword": - MessageLookupByLibrary.simpleMessage("Set new password"), - "setNewPin": MessageLookupByLibrary.simpleMessage("Set new PIN"), + MessageLookupByLibrary.simpleMessage("Ingresa tu nueva contraseña"), + "setNewPin": + MessageLookupByLibrary.simpleMessage("Ingresa tu nuevo PIN"), "setPasswordTitle": MessageLookupByLibrary.simpleMessage("Establecer contraseña"), "setRadius": MessageLookupByLibrary.simpleMessage("Establecer radio"), @@ -1431,10 +1419,10 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Compartir un álbum ahora"), "shareLink": MessageLookupByLibrary.simpleMessage("Compartir enlace"), - "shareMyVerificationID": m51, + "shareMyVerificationID": m52, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Comparte sólo con la gente que quieres"), - "shareTextConfirmOthersVerificationID": m52, + "shareTextConfirmOthersVerificationID": m2, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Descarga Ente para que podamos compartir fácilmente fotos y videos en calidad original.\n\nhttps://ente.io"), "shareTextReferralCode": m53, @@ -1548,7 +1536,8 @@ class MessageLookup extends MessageLookupByLibrary { "tapToCopy": MessageLookupByLibrary.simpleMessage("toca para copiar"), "tapToEnterCode": MessageLookupByLibrary.simpleMessage( "Toca para introducir el código"), - "tapToUnlock": MessageLookupByLibrary.simpleMessage("Tap to unlock"), + "tapToUnlock": + MessageLookupByLibrary.simpleMessage("Toca para desbloquear"), "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Parece que algo salió mal. Por favor, vuelve a intentarlo después de algún tiempo. Si el error persiste, ponte en contacto con nuestro equipo de soporte."), "terminate": MessageLookupByLibrary.simpleMessage("Terminar"), @@ -1595,17 +1584,14 @@ class MessageLookup extends MessageLookupByLibrary { "¡Esto cerrará la sesión de este dispositivo!"), "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( - "This will remove public links of all selected quick links."), - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": - MessageLookupByLibrary.simpleMessage( - "To enable app lock, please setup device passcode or screen lock in your system settings."), + "Esto eliminará los enlaces públicos de todos los enlaces rápidos seleccionados."), "toHideAPhotoOrVideo": MessageLookupByLibrary.simpleMessage( "Para ocultar una foto o video"), "toResetVerifyEmail": MessageLookupByLibrary.simpleMessage( "Para restablecer tu contraseña, por favor verifica tu correo electrónico primero."), "todaysLogs": MessageLookupByLibrary.simpleMessage("Registros de hoy"), - "tooManyIncorrectAttempts": - MessageLookupByLibrary.simpleMessage("Too many incorrect attempts"), + "tooManyIncorrectAttempts": MessageLookupByLibrary.simpleMessage( + "Demasiados intentos incorrectos"), "total": MessageLookupByLibrary.simpleMessage("total"), "totalSize": MessageLookupByLibrary.simpleMessage("Tamaño total"), "trash": MessageLookupByLibrary.simpleMessage("Papelera"), @@ -1656,6 +1642,8 @@ class MessageLookup extends MessageLookupByLibrary { "Hasta el 50% de descuento, hasta el 4 de diciembre."), "usableReferralStorageInfo": MessageLookupByLibrary.simpleMessage( "El almacenamiento utilizable está limitado por tu plan actual. El exceso de almacenamiento reclamado se volverá automáticamente utilizable cuando actualices tu plan."), + "useAsCover": + MessageLookupByLibrary.simpleMessage("Usar como cubierta"), "usePublicLinksForPeopleNotOnEnte": MessageLookupByLibrary.simpleMessage( "Usar enlaces públicos para personas que no están en Ente"), @@ -1682,6 +1670,8 @@ class MessageLookup extends MessageLookupByLibrary { "verifying": MessageLookupByLibrary.simpleMessage("Verificando..."), "verifyingRecoveryKey": MessageLookupByLibrary.simpleMessage( "Verificando clave de recuperación..."), + "videoInfo": + MessageLookupByLibrary.simpleMessage("Información de video"), "videoSmallCase": MessageLookupByLibrary.simpleMessage("vídeo"), "videos": MessageLookupByLibrary.simpleMessage("Vídeos"), "viewActiveSessions": @@ -1693,8 +1683,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ver todos los datos EXIF"), "viewLargeFiles": MessageLookupByLibrary.simpleMessage("Archivos grandes"), - "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( - "Ver archivos que consumen la mayor cantidad de almacenamiento"), "viewLogs": MessageLookupByLibrary.simpleMessage("Ver Registros"), "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("Ver código de recuperación"), diff --git a/mobile/lib/generated/intl/messages_et.dart b/mobile/lib/generated/intl/messages_et.dart new file mode 100644 index 0000000000..c1b8a2ba7e --- /dev/null +++ b/mobile/lib/generated/intl/messages_et.dart @@ -0,0 +1,25 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a et locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'et'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => {}; +} diff --git a/mobile/lib/generated/intl/messages_fa.dart b/mobile/lib/generated/intl/messages_fa.dart new file mode 100644 index 0000000000..b6650a943a --- /dev/null +++ b/mobile/lib/generated/intl/messages_fa.dart @@ -0,0 +1,441 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a fa locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'fa'; + + static String m10(versionValue) => "نسخه: ${versionValue}"; + + static String m11(freeAmount, storageUnit) => + "${freeAmount} ${storageUnit} رایگان"; + + static String m22(supportEmail) => + "لطفا یک ایمیل از آدرس ایمیلی که ثبت نام کردید به ${supportEmail} ارسال کنید"; + + static String m41(passwordStrengthValue) => + "قدرت رمز عبور: ${passwordStrengthValue}"; + + static String m46(storeName) => "به ما در ${storeName} امتیاز دهید"; + + static String m60( + usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => + "${usedAmount} ${usedStorageUnit} از ${totalAmount} ${totalStorageUnit} استفاده شده"; + + static String m68(email) => "تایید ${email}"; + + static String m69(email) => + "ما یک ایمیل به ${email} ارسال کرده‌ایم"; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "aNewVersionOfEnteIsAvailable": MessageLookupByLibrary.simpleMessage( + "نسخه جدید Ente در دسترس است."), + "about": MessageLookupByLibrary.simpleMessage("درباره ما"), + "account": MessageLookupByLibrary.simpleMessage("حساب کاربری"), + "accountWelcomeBack": + MessageLookupByLibrary.simpleMessage("خوش آمدید!"), + "ackPasswordLostWarning": MessageLookupByLibrary.simpleMessage( + "من درک می‌کنم که اگر رمز عبور خود را گم کنم، ممکن است اطلاعات خود را از دست بدهم، زیرا اطلاعات من رمزگذاری سرتاسر شده است."), + "activeSessions": + MessageLookupByLibrary.simpleMessage("دستگاه‌های فعال"), + "addANewEmail": + MessageLookupByLibrary.simpleMessage("افزودن ایمیل جدید"), + "addCollaborator": MessageLookupByLibrary.simpleMessage("افزودن همکار"), + "addMore": MessageLookupByLibrary.simpleMessage("افزودن بیشتر"), + "addViewer": MessageLookupByLibrary.simpleMessage("افزودن بیننده"), + "addedAs": MessageLookupByLibrary.simpleMessage("اضافه شده به عنوان"), + "advanced": MessageLookupByLibrary.simpleMessage("پیشرفته"), + "albumUpdated": MessageLookupByLibrary.simpleMessage("آلبوم به‌روز شد"), + "allowAddPhotosDescription": MessageLookupByLibrary.simpleMessage( + "به افراد که این پیوند را دارند، اجازه دهید عکس‌ها را به آلبوم اشتراک گذاری شده اضافه کنند."), + "allowAddingPhotos": + MessageLookupByLibrary.simpleMessage("اجازه اضافه کردن عکس"), + "allowPeopleToAddPhotos": MessageLookupByLibrary.simpleMessage( + "به افراد اجازه دهید عکس اضافه کنند"), + "androidBiometricHint": + MessageLookupByLibrary.simpleMessage("تایید هویت"), + "androidBiometricSuccess": + MessageLookupByLibrary.simpleMessage("موفقیت"), + "androidCancelButton": MessageLookupByLibrary.simpleMessage("لغو"), + "androidIosWebDesktop": MessageLookupByLibrary.simpleMessage( + "اندروید، آی‌اواس، وب، رایانه رومیزی"), + "appVersion": m10, + "archive": MessageLookupByLibrary.simpleMessage("بایگانی"), + "areYouSureYouWantToLogout": MessageLookupByLibrary.simpleMessage( + "آیا برای خارج شدن مطمئن هستید؟"), + "askDeleteReason": MessageLookupByLibrary.simpleMessage( + "دلیل اصلی که حساب کاربری‌تان را حذف می‌کنید، چیست؟"), + "atAFalloutShelter": + MessageLookupByLibrary.simpleMessage("در یک پناهگاه ذخیره می‌شود"), + "authToViewYourActiveSessions": MessageLookupByLibrary.simpleMessage( + "لطفاً برای مشاهده دستگاه‌های فعال خود احراز هویت کنید"), + "available": MessageLookupByLibrary.simpleMessage("در دسترس"), + "availableStorageSpace": m11, + "backedUpFolders": + MessageLookupByLibrary.simpleMessage("پوشه‌های پشتیبان گیری شده"), + "backup": MessageLookupByLibrary.simpleMessage("پشتیبان گیری"), + "blog": MessageLookupByLibrary.simpleMessage("وبلاگ"), + "cancel": MessageLookupByLibrary.simpleMessage("لغو"), + "cannotDeleteSharedFiles": MessageLookupByLibrary.simpleMessage( + "پرونده‌های به اشتراک گذاشته شده را نمی‌توان حذف کرد"), + "changeEmail": MessageLookupByLibrary.simpleMessage("تغییر ایمیل"), + "changePasswordTitle": + MessageLookupByLibrary.simpleMessage("تغییر رمز عبور"), + "checkForUpdates": + MessageLookupByLibrary.simpleMessage("بررسی برای به‌روزرسانی"), + "checkInboxAndSpamFolder": MessageLookupByLibrary.simpleMessage( + "لطفا صندوق ورودی (و هرزنامه) خود را برای تایید کامل بررسی کنید"), + "checkStatus": MessageLookupByLibrary.simpleMessage("بررسی وضعیت"), + "checking": MessageLookupByLibrary.simpleMessage("در حال بررسی..."), + "collabLinkSectionDescription": MessageLookupByLibrary.simpleMessage( + "پیوندی ایجاد کنید تا به افراد اجازه دهید بدون نیاز به برنامه یا حساب کاربری Ente عکس‌ها را در آلبوم اشتراک گذاشته شده شما اضافه و مشاهده کنند. برای جمع‌آوری عکس‌های رویداد عالی است."), + "collaborator": MessageLookupByLibrary.simpleMessage("همکار"), + "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": + MessageLookupByLibrary.simpleMessage( + "همکاران می‌توانند عکس‌ها و ویدیوها را به آلبوم اشتراک گذاری شده اضافه کنند."), + "color": MessageLookupByLibrary.simpleMessage("رنگ"), + "confirm": MessageLookupByLibrary.simpleMessage("تایید"), + "confirmAccountDeletion": + MessageLookupByLibrary.simpleMessage("تایید حذف حساب کاربری"), + "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( + "بله، من می‌خواهم برای همیشه این حساب کاربری و تمام اطلاعات آن را حذف کنم."), + "confirmPassword": + MessageLookupByLibrary.simpleMessage("تایید رمز عبور"), + "confirmRecoveryKey": + MessageLookupByLibrary.simpleMessage("تایید کلید بازیابی"), + "confirmYourRecoveryKey": MessageLookupByLibrary.simpleMessage( + "کلید بازیابی خود را تایید کنید"), + "contactSupport": + MessageLookupByLibrary.simpleMessage("ارتباط با پشتیبانی"), + "continueLabel": MessageLookupByLibrary.simpleMessage("ادامه"), + "convertToAlbum": + MessageLookupByLibrary.simpleMessage("تبدیل به آلبوم"), + "createAccount": + MessageLookupByLibrary.simpleMessage("ایجاد حساب کاربری"), + "createNewAccount": + MessageLookupByLibrary.simpleMessage("ایجاد حساب کاربری جدید"), + "criticalUpdateAvailable": MessageLookupByLibrary.simpleMessage( + "به‌روزرسانی حیاتی در دسترس است"), + "custom": MessageLookupByLibrary.simpleMessage("سفارشی"), + "darkTheme": MessageLookupByLibrary.simpleMessage("تیره"), + "dayToday": MessageLookupByLibrary.simpleMessage("امروز"), + "dayYesterday": MessageLookupByLibrary.simpleMessage("دیروز"), + "decrypting": + MessageLookupByLibrary.simpleMessage("در حال رمزگشایی..."), + "deleteAccount": + MessageLookupByLibrary.simpleMessage("حذف حساب کاربری"), + "deleteAccountFeedbackPrompt": MessageLookupByLibrary.simpleMessage( + "ما متاسفیم که می‌بینیم شما می‌روید. لطفا نظرات خود را برای کمک به بهبود ما به اشتراک بگذارید."), + "deleteAccountPermanentlyButton": + MessageLookupByLibrary.simpleMessage("حذف دائمی حساب کاربری"), + "deleteAll": MessageLookupByLibrary.simpleMessage("حذف همه"), + "deleteEmailRequest": MessageLookupByLibrary.simpleMessage( + "لطفا یک ایمیل به account-deletion@ente.io از آدرس ایمیل ثبت شده خود ارسال کنید."), + "deleteReason1": MessageLookupByLibrary.simpleMessage( + "یک ویژگی کلیدی که به آن نیاز دارم، وجود ندارد"), + "deleteReason2": MessageLookupByLibrary.simpleMessage( + "برنامه یا یک ویژگی خاص آنطور که من فکر می‌کنم، عمل نمی‌کند"), + "deleteReason3": MessageLookupByLibrary.simpleMessage( + "سرویس دیگری پیدا کردم که بهتر می‌پسندم"), + "deleteReason4": + MessageLookupByLibrary.simpleMessage("دلیل من ذکر نشده است"), + "deleteRequestSLAText": MessageLookupByLibrary.simpleMessage( + "درخواست شما ظرف مدت ۷۲ ساعت پردازش خواهد شد."), + "designedToOutlive": MessageLookupByLibrary.simpleMessage( + "طراحی شده تا بیشتر زنده بماند"), + "details": MessageLookupByLibrary.simpleMessage("جزئیات"), + "developerSettings": + MessageLookupByLibrary.simpleMessage("تنظیمات توسعه‌دهنده"), + "didYouKnow": MessageLookupByLibrary.simpleMessage("آیا می‌دانستید؟"), + "discord": MessageLookupByLibrary.simpleMessage("دیسکورد"), + "doThisLater": MessageLookupByLibrary.simpleMessage("بعداً انجام شود"), + "downloading": MessageLookupByLibrary.simpleMessage("در حال دانلود..."), + "dropSupportEmail": m22, + "editLocationTagTitle": + MessageLookupByLibrary.simpleMessage("ویرایش مکان"), + "email": MessageLookupByLibrary.simpleMessage("ایمیل"), + "encryption": MessageLookupByLibrary.simpleMessage("رمزگذاری"), + "encryptionKeys": + MessageLookupByLibrary.simpleMessage("کلیدهای رمزنگاری"), + "endtoendEncryptedByDefault": MessageLookupByLibrary.simpleMessage( + "به صورت پیش‌فرض رمزگذاری سرتاسر"), + "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": + MessageLookupByLibrary.simpleMessage( + "Ente فقط در صورتی می‌تواند پرونده‌ها را رمزگذاری و نگه‌داری کند که به آن‌ها دسترسی داشته باشید"), + "entePhotosPerm": MessageLookupByLibrary.simpleMessage( + "Ente برای نگه‌داری عکس‌های شما به دسترسی نیاز دارد"), + "enterEmail": + MessageLookupByLibrary.simpleMessage("ایمیل را وارد کنید"), + "enterNewPasswordToEncrypt": MessageLookupByLibrary.simpleMessage( + "رمز عبور جدیدی را وارد کنید که بتوانیم از آن برای رمزگذاری اطلاعات شما استفاده کنیم"), + "enterPassword": + MessageLookupByLibrary.simpleMessage("رمز عبور را وارد کنید"), + "enterPasswordToEncrypt": MessageLookupByLibrary.simpleMessage( + "رمز عبوری را وارد کنید که بتوانیم از آن برای رمزگذاری اطلاعات شما استفاده کنیم"), + "enterValidEmail": MessageLookupByLibrary.simpleMessage( + "لطفا یک ایمیل معتبر وارد کنید."), + "enterYourEmailAddress": + MessageLookupByLibrary.simpleMessage("آدرس ایمیل خود را وارد کنید"), + "enterYourPassword": + MessageLookupByLibrary.simpleMessage("رمز عبور خود را وارد کنید"), + "enterYourRecoveryKey": MessageLookupByLibrary.simpleMessage( + "کلید بازیابی خود را وارد کنید"), + "error": MessageLookupByLibrary.simpleMessage("خطا"), + "everywhere": MessageLookupByLibrary.simpleMessage("همه جا"), + "existingUser": MessageLookupByLibrary.simpleMessage("کاربر موجود"), + "familyPlanPortalTitle": + MessageLookupByLibrary.simpleMessage("خانوادگی"), + "familyPlans": + MessageLookupByLibrary.simpleMessage("برنامه‌های خانوادگی"), + "faq": MessageLookupByLibrary.simpleMessage("سوالات متداول"), + "feedback": MessageLookupByLibrary.simpleMessage("بازخورد"), + "fileInfoAddDescHint": + MessageLookupByLibrary.simpleMessage("افزودن توضیحات..."), + "fileTypes": MessageLookupByLibrary.simpleMessage("انواع پرونده"), + "forYourMemories": + MessageLookupByLibrary.simpleMessage("برای خاطرات شما"), + "forgotPassword": + MessageLookupByLibrary.simpleMessage("رمز عبور را فراموش کرده‌اید"), + "general": MessageLookupByLibrary.simpleMessage("عمومی"), + "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( + "در حال تولید کلیدهای رمزگذاری..."), + "grantFullAccessPrompt": MessageLookupByLibrary.simpleMessage( + "لطفا اجازه دسترسی به تمام عکس‌ها را در تنظیمات برنامه بدهید"), + "grantPermission": MessageLookupByLibrary.simpleMessage("دسترسی دادن"), + "hearUsExplanation": MessageLookupByLibrary.simpleMessage( + "ما نصب برنامه را ردیابی نمی‌کنیم. اگر بگویید کجا ما را پیدا کردید، به ما کمک می‌کند!"), + "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( + "از کجا در مورد Ente شنیدی؟ (اختیاری)"), + "howItWorks": MessageLookupByLibrary.simpleMessage("چگونه کار می‌کند"), + "ignoreUpdate": MessageLookupByLibrary.simpleMessage("نادیده گرفتن"), + "incorrectPasswordTitle": + MessageLookupByLibrary.simpleMessage("رمز عبور درست نیست"), + "incorrectRecoveryKeyBody": MessageLookupByLibrary.simpleMessage( + "کلید بازیابی که وارد کردید درست نیست"), + "incorrectRecoveryKeyTitle": + MessageLookupByLibrary.simpleMessage("کلید بازیابی درست نیست"), + "insecureDevice": MessageLookupByLibrary.simpleMessage("دستگاه ناامن"), + "installManually": MessageLookupByLibrary.simpleMessage("نصب دستی"), + "invalidEmailAddress": + MessageLookupByLibrary.simpleMessage("آدرس ایمیل معتبر نیست"), + "invalidKey": MessageLookupByLibrary.simpleMessage("کلید نامعتبر"), + "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": + MessageLookupByLibrary.simpleMessage( + "به نظر می‌رسد مشکلی وجود دارد. لطفا بعد از مدتی دوباره تلاش کنید. اگر همچنان با خطا مواجه می‌شوید، لطفا با تیم پشتیبانی ما ارتباط برقرار کنید."), + "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( + "لطفا با این اطلاعات به ما کمک کنید"), + "lightTheme": MessageLookupByLibrary.simpleMessage("روشن"), + "loadMessage2": MessageLookupByLibrary.simpleMessage( + "ما تا کنون بیش از ۳۰ میلیون خاطره را حفظ کرده‌ایم"), + "lockButtonLabel": MessageLookupByLibrary.simpleMessage("قفل"), + "logInLabel": MessageLookupByLibrary.simpleMessage("ورود"), + "loggingOut": MessageLookupByLibrary.simpleMessage("در حال خروج..."), + "loginTerms": MessageLookupByLibrary.simpleMessage( + "با کلیک بر روی ورود به سیستم، من با شرایط خدمات و سیاست حفظ حریم خصوصی موافقم"), + "logout": MessageLookupByLibrary.simpleMessage("خروج"), + "manage": MessageLookupByLibrary.simpleMessage("مدیریت"), + "manageFamily": MessageLookupByLibrary.simpleMessage("مدیریت خانواده"), + "manageLink": MessageLookupByLibrary.simpleMessage("مدیریت پیوند"), + "manageParticipants": MessageLookupByLibrary.simpleMessage("مدیریت"), + "manageSubscription": + MessageLookupByLibrary.simpleMessage("مدیریت اشتراک"), + "mastodon": MessageLookupByLibrary.simpleMessage("ماستودون"), + "matrix": MessageLookupByLibrary.simpleMessage("ماتریس"), + "merchandise": MessageLookupByLibrary.simpleMessage("کالا"), + "moderateStrength": MessageLookupByLibrary.simpleMessage("متوسط"), + "never": MessageLookupByLibrary.simpleMessage("هرگز"), + "newToEnte": MessageLookupByLibrary.simpleMessage("کاربر جدید Ente"), + "no": MessageLookupByLibrary.simpleMessage("خیر"), + "noRecoveryKey": + MessageLookupByLibrary.simpleMessage("کلید بازیابی ندارید؟"), + "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( + "با توجه به ماهیت پروتکل رمزگذاری سرتاسر ما، اطلاعات شما بدون رمز عبور یا کلید بازیابی شما قابل رمزگشایی نیست"), + "notifications": MessageLookupByLibrary.simpleMessage("آگاه‌سازی‌ها"), + "ok": MessageLookupByLibrary.simpleMessage("تایید"), + "oops": MessageLookupByLibrary.simpleMessage("اوه"), + "password": MessageLookupByLibrary.simpleMessage("رمز عبور"), + "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage( + "رمز عبور با موفقیت تغییر کرد"), + "passwordStrength": m41, + "passwordWarning": MessageLookupByLibrary.simpleMessage( + "ما این رمز عبور را ذخیره نمی‌کنیم، بنابراین اگر فراموش کنید، نمی‌توانیم اطلاعات شما را رمزگشایی کنیم"), + "photoSmallCase": MessageLookupByLibrary.simpleMessage("عکس"), + "pleaseGrantPermissions": + MessageLookupByLibrary.simpleMessage("لطفا دسترسی بدهید"), + "pleaseLoginAgain": + MessageLookupByLibrary.simpleMessage("لطفا دوباره وارد شوید"), + "pleaseTryAgain": + MessageLookupByLibrary.simpleMessage("لطفا دوباره تلاش کنید"), + "pleaseWait": MessageLookupByLibrary.simpleMessage("لطفا صبر کنید..."), + "preparingLogs": + MessageLookupByLibrary.simpleMessage("در حال آماده‌سازی لاگ‌ها..."), + "privacy": MessageLookupByLibrary.simpleMessage("حریم خصوصی"), + "privacyPolicyTitle": + MessageLookupByLibrary.simpleMessage("سیاست حفظ حریم خصوصی"), + "privateBackups": + MessageLookupByLibrary.simpleMessage("پشتیبان گیری خصوصی"), + "privateSharing": + MessageLookupByLibrary.simpleMessage("اشتراک گذاری خصوصی"), + "rateUsOnStore": m46, + "recover": MessageLookupByLibrary.simpleMessage("بازیابی"), + "recoverAccount": + MessageLookupByLibrary.simpleMessage("بازیابی حساب کاربری"), + "recoverButton": MessageLookupByLibrary.simpleMessage("بازیابی"), + "recoveryKey": MessageLookupByLibrary.simpleMessage("کلید بازیابی"), + "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( + "کلید بازیابی در کلیپ‌بورد کپی شد"), + "recoveryKeyOnForgotPassword": MessageLookupByLibrary.simpleMessage( + "اگر رمز عبور خود را فراموش کردید، تنها راهی که می‌توانید اطلاعات خود را بازیابی کنید با این کلید است."), + "recoveryKeySaveDescription": MessageLookupByLibrary.simpleMessage( + "ما این کلید را ذخیره نمی‌کنیم، لطفا این کلید ۲۴ کلمه‌ای را در مکانی امن ذخیره کنید."), + "recoverySuccessful": + MessageLookupByLibrary.simpleMessage("بازیابی موفقیت آمیز بود!"), + "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( + "دستگاه فعلی به اندازه کافی قدرتمند نیست تا رمز عبور شما را تایید کند، اما ما می‌توانیم به گونه‌ای بازسازی کنیم که با تمام دستگاه‌ها کار کند.\n\nلطفا با استفاده از کلید بازیابی خود وارد شوید و رمز عبور خود را دوباره ایجاد کنید (در صورت تمایل می‌توانید دوباره از همان رمز عبور استفاده کنید)."), + "recreatePasswordTitle": + MessageLookupByLibrary.simpleMessage("بازتولید رمز عبور"), + "reddit": MessageLookupByLibrary.simpleMessage("ردیت"), + "removeLink": MessageLookupByLibrary.simpleMessage("حذف پیوند"), + "rename": MessageLookupByLibrary.simpleMessage("تغییر نام"), + "renameAlbum": MessageLookupByLibrary.simpleMessage("تغییر نام آلبوم"), + "renameFile": MessageLookupByLibrary.simpleMessage("تغییر نام پرونده"), + "resendEmail": MessageLookupByLibrary.simpleMessage("ارسال مجدد ایمیل"), + "resetPasswordTitle": + MessageLookupByLibrary.simpleMessage("بازنشانی رمز عبور"), + "retry": MessageLookupByLibrary.simpleMessage("سعی مجدد"), + "reviewSuggestions": + MessageLookupByLibrary.simpleMessage("مرور پیشنهادها"), + "safelyStored": MessageLookupByLibrary.simpleMessage("به طور ایمن"), + "saveKey": MessageLookupByLibrary.simpleMessage("ذخیره کلید"), + "search": MessageLookupByLibrary.simpleMessage("جستجو"), + "security": MessageLookupByLibrary.simpleMessage("امنیت"), + "selectAll": MessageLookupByLibrary.simpleMessage("انتخاب همه"), + "selectFoldersForBackup": MessageLookupByLibrary.simpleMessage( + "پوشه‌ها را برای پشتیبان گیری انتخاب کنید"), + "selectReason": MessageLookupByLibrary.simpleMessage("انتخاب دلیل"), + "selectedFoldersWillBeEncryptedAndBackedUp": + MessageLookupByLibrary.simpleMessage( + "پوشه‌های انتخاب شده، رمزگذاری شده و از آنها نسخه پشتیبان تهیه می‌شود"), + "send": MessageLookupByLibrary.simpleMessage("ارسال"), + "sendEmail": MessageLookupByLibrary.simpleMessage("ارسال ایمیل"), + "setPasswordTitle": + MessageLookupByLibrary.simpleMessage("تنظیم رمز عبور"), + "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( + "فقط با افرادی که می‌خواهید به اشتراک بگذارید"), + "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( + "Ente را دانلود کنید تا بتوانید به راحتی عکس‌ها و ویدیوهای با کیفیت اصلی را به اشتراک بگذارید\n\nhttps://ente.io"), + "sharedPhotoNotifications": MessageLookupByLibrary.simpleMessage( + "عکس‌های جدید به اشتراک گذاشته شده"), + "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( + "هنگامی که شخصی عکسی را به آلبوم مشترکی که شما بخشی از آن هستید اضافه می‌کند، آگاه‌سازی دریافت می‌کنید"), + "signUpTerms": MessageLookupByLibrary.simpleMessage( + "من با شرایط خدمات و سیاست حفظ حریم خصوصی موافقم"), + "skip": MessageLookupByLibrary.simpleMessage("رد کردن"), + "social": MessageLookupByLibrary.simpleMessage("شبکه اجتماعی"), + "somethingWentWrongPleaseTryAgain": + MessageLookupByLibrary.simpleMessage( + "مشکلی پیش آمده، لطفا دوباره تلاش کنید"), + "sorry": MessageLookupByLibrary.simpleMessage("متاسفیم"), + "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": + MessageLookupByLibrary.simpleMessage( + "با عرض پوزش، ما نمی‌توانیم کلیدهای امن را در این دستگاه تولید کنیم.\n\nلطفا از دستگاه دیگری ثبت نام کنید."), + "sortAlbumsBy": + MessageLookupByLibrary.simpleMessage("مرتب‌سازی براساس"), + "sortNewestFirst": + MessageLookupByLibrary.simpleMessage("ایتدا جدیدترین"), + "sortOldestFirst": + MessageLookupByLibrary.simpleMessage("ایتدا قدیمی‌ترین"), + "startBackup": + MessageLookupByLibrary.simpleMessage("شروع پشتیبان گیری"), + "status": MessageLookupByLibrary.simpleMessage("وضعیت"), + "storage": MessageLookupByLibrary.simpleMessage("حافظه ذخیره‌سازی"), + "storageBreakupFamily": + MessageLookupByLibrary.simpleMessage("خانوادگی"), + "storageBreakupYou": MessageLookupByLibrary.simpleMessage("شما"), + "storageUsageInfo": m60, + "strongStrength": MessageLookupByLibrary.simpleMessage("قوی"), + "support": MessageLookupByLibrary.simpleMessage("پشتیبانی"), + "systemTheme": MessageLookupByLibrary.simpleMessage("سیستم"), + "tapToEnterCode": MessageLookupByLibrary.simpleMessage( + "برای وارد کردن کد ضربه بزنید"), + "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( + "به نظر می‌رسد مشکلی وجود دارد. لطفا بعد از مدتی دوباره تلاش کنید. اگر همچنان با خطا مواجه می‌شوید، لطفا با تیم پشتیبانی ما ارتباط برقرار کنید."), + "terminate": MessageLookupByLibrary.simpleMessage("خروج"), + "terminateSession": + MessageLookupByLibrary.simpleMessage("خروچ دستگاه؟"), + "terms": MessageLookupByLibrary.simpleMessage("شرایط و مقررات"), + "termsOfServicesTitle": + MessageLookupByLibrary.simpleMessage("شرایط و مقررات"), + "theDownloadCouldNotBeCompleted": + MessageLookupByLibrary.simpleMessage("دانلود کامل نشد"), + "theme": MessageLookupByLibrary.simpleMessage("تم"), + "thisDevice": MessageLookupByLibrary.simpleMessage("این دستگاه"), + "thisWillLogYouOutOfTheFollowingDevice": + MessageLookupByLibrary.simpleMessage( + "با این کار شما از دستگاه زیر خارج می‌شوید:"), + "thisWillLogYouOutOfThisDevice": MessageLookupByLibrary.simpleMessage( + "این کار شما را از این دستگاه خارج می‌کند!"), + "toResetVerifyEmail": MessageLookupByLibrary.simpleMessage( + "برای تنظیم مجدد رمز عبور، لطفا ابتدا ایمیل خود را تایید کنید."), + "tryAgain": MessageLookupByLibrary.simpleMessage("دوباره امتحان کنید"), + "twitter": MessageLookupByLibrary.simpleMessage("توییتر"), + "uncategorized": MessageLookupByLibrary.simpleMessage("دسته‌بندی نشده"), + "unselectAll": MessageLookupByLibrary.simpleMessage("لغو انتخاب همه"), + "update": MessageLookupByLibrary.simpleMessage("به‌روزرسانی"), + "updateAvailable": + MessageLookupByLibrary.simpleMessage("به‌رورزرسانی در دسترس است"), + "updatingFolderSelection": MessageLookupByLibrary.simpleMessage( + "در حال به‌روزرسانی گزینش پوشه..."), + "usePublicLinksForPeopleNotOnEnte": + MessageLookupByLibrary.simpleMessage( + "استفاده از پیوندهای عمومی برای افرادی که در Ente نیستند"), + "useRecoveryKey": MessageLookupByLibrary.simpleMessage( + "از کلید بازیابی استفاده کنید"), + "verify": MessageLookupByLibrary.simpleMessage("تایید"), + "verifyEmail": MessageLookupByLibrary.simpleMessage("تایید ایمیل"), + "verifyEmailID": m68, + "verifyIDLabel": MessageLookupByLibrary.simpleMessage("تایید"), + "verifyPassword": + MessageLookupByLibrary.simpleMessage("تایید رمز عبور"), + "verifying": MessageLookupByLibrary.simpleMessage("در حال تایید..."), + "videoSmallCase": MessageLookupByLibrary.simpleMessage("ویدیو"), + "viewActiveSessions": + MessageLookupByLibrary.simpleMessage("مشاهده دستگاه‌های فعال"), + "viewRecoveryKey": + MessageLookupByLibrary.simpleMessage("نمایش کلید بازیابی"), + "viewer": MessageLookupByLibrary.simpleMessage("بیننده"), + "weAreOpenSource": + MessageLookupByLibrary.simpleMessage("ما متن‌باز هستیم!"), + "weHaveSendEmailTo": m69, + "weakStrength": MessageLookupByLibrary.simpleMessage("ضعیف"), + "welcomeBack": MessageLookupByLibrary.simpleMessage("خوش آمدید!"), + "whatsNew": MessageLookupByLibrary.simpleMessage("تغییرات جدید"), + "yes": MessageLookupByLibrary.simpleMessage("بله"), + "yesConvertToViewer": + MessageLookupByLibrary.simpleMessage("بله، تبدیل به بیننده شود"), + "yesLogout": MessageLookupByLibrary.simpleMessage("بله، خارج می‌شوم"), + "you": MessageLookupByLibrary.simpleMessage("شما"), + "youAreOnAFamilyPlan": MessageLookupByLibrary.simpleMessage( + "شما در یک برنامه خانوادگی هستید!"), + "youAreOnTheLatestVersion": MessageLookupByLibrary.simpleMessage( + "شما در حال استفاده از آخرین نسخه هستید"), + "yourAccountHasBeenDeleted": + MessageLookupByLibrary.simpleMessage("حساب کاربری شما حذف شده است") + }; +} diff --git a/mobile/lib/generated/intl/messages_fr.dart b/mobile/lib/generated/intl/messages_fr.dart index 4b70fe3fc5..af1060e22b 100644 --- a/mobile/lib/generated/intl/messages_fr.dart +++ b/mobile/lib/generated/intl/messages_fr.dart @@ -20,34 +20,37 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'fr'; - static String m0(count) => - "${Intl.plural(count, zero: 'Add collaborator', one: 'Add collaborator', other: 'Add collaborators')}"; + static String m3(count) => + "${Intl.plural(count, zero: 'Ajouter un coauteur', one: 'Ajouter un coauteur', other: 'Ajouter des coauteurs')}"; - static String m2(count) => + static String m4(count) => "${Intl.plural(count, one: 'Ajoutez un objet', other: 'Ajoutez des objets')}"; - static String m1(count) => - "${Intl.plural(count, zero: 'Add viewer', one: 'Add viewer', other: 'Add viewers')}"; - - static String m4(emailOrName) => "Ajouté par ${emailOrName}"; - - static String m5(albumName) => "Ajouté avec succès à ${albumName}"; + static String m5(storageAmount, endDate) => + "Votre extension de ${storageAmount} est valable jusqu\'au ${endDate}"; static String m6(count) => + "${Intl.plural(count, zero: 'Ajouter un lecteur', one: 'Ajouter un lecteur', other: 'Ajouter des lecteurs')}"; + + static String m7(emailOrName) => "Ajouté par ${emailOrName}"; + + static String m8(albumName) => "Ajouté avec succès à ${albumName}"; + + static String m9(count) => "${Intl.plural(count, zero: 'Aucun Participant', one: '1 Participant', other: '${count} Participants')}"; - static String m7(versionValue) => "Version : ${versionValue}"; + static String m10(versionValue) => "Version : ${versionValue}"; - static String m8(freeAmount, storageUnit) => - "${freeAmount} ${storageUnit} libre"; + static String m11(freeAmount, storageUnit) => + "${freeAmount} ${storageUnit} gratuit"; - static String m9(paymentProvider) => + static String m12(paymentProvider) => "Veuillez d\'abord annuler votre abonnement existant de ${paymentProvider}"; - static String m10(user) => - "${user} ne pourra pas ajouter plus de photos à cet album\n\nIl pourrait toujours supprimer les photos existantes ajoutées par eux"; + static String m13(user) => + "${user} ne pourra pas ajouter plus de photos à cet album\n\nIl pourra toujours supprimer les photos existantes ajoutées par eux"; - static String m11(isFamilyMember, storageAmountInGb) => + static String m14(isFamilyMember, storageAmountInGb) => "${Intl.select(isFamilyMember, { 'true': 'Votre famille a demandé ${storageAmountInGb} GB jusqu\'à présent', @@ -57,108 +60,113 @@ class MessageLookup extends MessageLookupByLibrary { 'Vous avez réclamé ${storageAmountInGb} GB jusqu\'à présent!', })}"; - static String m12(albumName) => "Lien collaboratif créé pour ${albumName}"; + static String m15(albumName) => "Lien collaboratif créé pour ${albumName}"; - static String m13(familyAdminEmail) => + static String m16(familyAdminEmail) => "Veuillez contacter ${familyAdminEmail} pour gérer votre abonnement"; - static String m14(provider) => + static String m17(provider) => "Veuillez nous contacter à support@ente.io pour gérer votre abonnement ${provider}."; - static String m16(count) => + static String m18(endpoint) => "Connecté à ${endpoint}"; + + static String m19(count) => "${Intl.plural(count, one: 'Supprimer le fichier', other: 'Supprimer ${count} fichiers')}"; - static String m17(currentlyDeleting, totalCount) => + static String m20(currentlyDeleting, totalCount) => "Suppression de ${currentlyDeleting} / ${totalCount}"; - static String m18(albumName) => + static String m21(albumName) => "Cela supprimera le lien public pour accéder à \"${albumName}\"."; - static String m19(supportEmail) => + static String m22(supportEmail) => "Veuillez envoyer un e-mail à ${supportEmail} depuis votre adresse enregistrée"; - static String m20(count, storageSaved) => + static String m23(count, storageSaved) => "Vous avez nettoyé ${Intl.plural(count, one: '${count} fichier dupliqué', other: '${count} fichiers dupliqués')}, sauvegarde (${storageSaved}!)"; - static String m21(count, formattedSize) => + static String m24(count, formattedSize) => "${count} fichiers, ${formattedSize} chacun"; - static String m22(newEmail) => "L\'e-mail a été changé en ${newEmail}"; + static String m25(newEmail) => "L\'e-mail a été changé en ${newEmail}"; - static String m23(email) => - "${email} n\'a pas de compte ente.\n\nEnvoyez une invitation pour partager des photos."; + static String m26(email) => + "${email} n\'a pas de compte Ente.\n\nEnvoyez une invitation pour partager des photos."; - static String m24(count, formattedNumber) => + static String m27(count, formattedNumber) => "${Intl.plural(count, one: '1 fichier sur cet appareil a été sauvegardé en toute sécurité', other: '${formattedNumber} fichiers sur cet appareil ont été sauvegardés en toute sécurité')}"; - static String m25(count, formattedNumber) => + static String m28(count, formattedNumber) => "${Intl.plural(count, one: '1 fichier dans cet album a été sauvegardé en toute sécurité', other: '${formattedNumber} fichiers dans cet album ont été sauvegardés en toute sécurité')}"; - static String m26(storageAmountInGB) => + static String m29(storageAmountInGB) => "${storageAmountInGB} Go chaque fois que quelqu\'un s\'inscrit à une offre payante et applique votre code"; - static String m27(endDate) => "Essai gratuit valide jusqu’au ${endDate}"; + static String m30(endDate) => "Essai gratuit valide jusqu’au ${endDate}"; - static String m28(count) => + static String m31(count) => "Vous pouvez toujours ${Intl.plural(count, one: 'y', other: 'y')} accéder sur ente tant que vous avez un abonnement actif"; - static String m29(sizeInMBorGB) => "Libérer ${sizeInMBorGB}"; + static String m32(sizeInMBorGB) => "Libérer ${sizeInMBorGB}"; - static String m30(count, formattedSize) => + static String m33(count, formattedSize) => "${Intl.plural(count, one: 'Peut être supprimé de l\'appareil pour libérer ${formattedSize}', other: 'Peuvent être supprimés de l\'appareil pour libérer ${formattedSize}')}"; - static String m32(count) => - "${Intl.plural(count, one: '${count} objet', other: '${count} objets')}"; - - static String m33(expiryTime) => "Le lien expirera le ${expiryTime}"; - - static String m34(count, formattedCount) => - "${Intl.plural(count, one: '${formattedCount} mémoire', other: '${formattedCount} souvenirs')}"; + static String m34(currentlyProcessing, totalCount) => + "Traitement en cours ${currentlyProcessing} / ${totalCount}"; static String m35(count) => + "${Intl.plural(count, one: '${count} objet', other: '${count} objets')}"; + + static String m36(expiryTime) => "Le lien expirera le ${expiryTime}"; + + static String m0(count, formattedCount) => + "${Intl.plural(count, one: '${formattedCount} mémoire', other: '${formattedCount} souvenirs')}"; + + static String m37(count) => "${Intl.plural(count, one: 'Déplacez l\'objet', other: 'Déplacez des objets')}"; - static String m36(albumName) => "Déplacé avec succès vers ${albumName}"; + static String m38(albumName) => "Déplacé avec succès vers ${albumName}"; - static String m39(passwordStrengthValue) => + static String m41(passwordStrengthValue) => "Sécurité du mot de passe : ${passwordStrengthValue}"; - static String m40(providerName) => + static String m42(providerName) => "Veuillez contacter le support ${providerName} si vous avez été facturé"; - static String m41(endDate) => + static String m43(endDate) => "Essai gratuit valable jusqu\'à ${endDate}.\nVous pouvez choisir un plan payant par la suite."; - static String m42(toEmail) => "Merci de nous envoyer un e-mail à ${toEmail}"; + static String m44(toEmail) => "Merci de nous envoyer un e-mail à ${toEmail}"; - static String m43(toEmail) => "Envoyez les logs à ${toEmail}"; + static String m45(toEmail) => "Envoyez les logs à ${toEmail}"; - static String m44(storeName) => "Notez-nous sur ${storeName}"; + static String m46(storeName) => "Notez-nous sur ${storeName}"; - static String m45(storageInGB) => + static String m47(storageInGB) => "3. Vous recevez tous les deux ${storageInGB} GB* gratuits"; - static String m46(userEmail) => + static String m48(userEmail) => "${userEmail} sera retiré de cet album partagé\n\nToutes les photos ajoutées par eux seront également retirées de l\'album"; - static String m47(endDate) => "Renouvellement le ${endDate}"; + static String m49(endDate) => "Renouvellement le ${endDate}"; - static String m48(count) => + static String m50(count) => "${Intl.plural(count, one: '${count} résultat trouvé', other: '${count} résultats trouvés')}"; - static String m49(count) => "${count} sélectionné(s)"; + static String m1(count) => "${count} sélectionné(s)"; - static String m50(count, yourCount) => + static String m51(count, yourCount) => "${count} sélectionné(s) (${yourCount} à vous)"; - static String m51(verificationID) => + static String m52(verificationID) => "Voici mon ID de vérification : ${verificationID} pour ente.io."; - static String m52(verificationID) => + static String m2(verificationID) => "Hé, pouvez-vous confirmer qu\'il s\'agit de votre ID de vérification ente.io : ${verificationID}"; static String m53(referralCode, referralStorageInGB) => - "code de parrainage ente : ${referralCode} \n\nAppliquez le dans Paramètres → Général → Références pour obtenir ${referralStorageInGB} Go gratuitement après votre inscription à un plan payant\n\nhttps://ente.io"; + "Code de parrainage Ente : ${referralCode} \n\nValidez le dans Paramètres → Général → Références pour obtenir ${referralStorageInGB} Go gratuitement après votre inscription à un plan payant\n\nhttps://ente.io"; static String m54(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Partagez avec des personnes spécifiques', one: 'Partagé avec 1 personne', other: 'Partagé avec ${numberOfPeople} des gens')}"; @@ -171,7 +179,7 @@ class MessageLookup extends MessageLookupByLibrary { static String m57(fileType) => "Cette ${fileType} est à la fois sur ente et sur votre appareil."; - static String m58(fileType) => "Ce ${fileType} sera supprimé de ente."; + static String m58(fileType) => "Cette ${fileType} sera supprimée de l\'Ente."; static String m59(storageAmountInGB) => "${storageAmountInGB} Go"; @@ -180,7 +188,7 @@ class MessageLookup extends MessageLookupByLibrary { "${usedAmount} ${usedStorageUnit} sur ${totalAmount} ${totalStorageUnit} utilisé"; static String m61(id) => - "Votre ${id} est déjà lié à un autre compte ente.\nSi vous souhaitez utiliser votre ${id} avec ce compte, veuillez contacter notre support"; + "Votre ${id} est déjà lié à un autre compte Ente.\nSi vous souhaitez utiliser votre ${id} avec ce compte, veuillez contacter notre support"; static String m62(endDate) => "Votre abonnement sera annulé le ${endDate}"; @@ -211,7 +219,7 @@ class MessageLookup extends MessageLookupByLibrary { final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { "aNewVersionOfEnteIsAvailable": MessageLookupByLibrary.simpleMessage( - "Une nouvelle version de ente est disponible."), + "Une nouvelle version de Ente est disponible."), "about": MessageLookupByLibrary.simpleMessage("À propos"), "account": MessageLookupByLibrary.simpleMessage("Compte"), "accountWelcomeBack": @@ -220,21 +228,23 @@ class MessageLookup extends MessageLookupByLibrary { "Je comprends que si je perds mon mot de passe, je perdrai mes données puisque mes données sont chiffrées de bout en bout."), "activeSessions": MessageLookupByLibrary.simpleMessage("Sessions actives"), + "addAName": MessageLookupByLibrary.simpleMessage("Ajouter un nom"), "addANewEmail": MessageLookupByLibrary.simpleMessage("Ajouter un nouvel email"), "addCollaborator": MessageLookupByLibrary.simpleMessage("Ajouter un collaborateur"), - "addCollaborators": m0, + "addCollaborators": m3, "addFromDevice": MessageLookupByLibrary.simpleMessage("Ajouter depuis l\'appareil"), - "addItem": m2, + "addItem": m4, "addLocation": MessageLookupByLibrary.simpleMessage("Ajouter la localisation"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Ajouter"), - "addMore": MessageLookupByLibrary.simpleMessage("Ajouter Plus"), + "addMore": MessageLookupByLibrary.simpleMessage("Ajouter"), "addNew": MessageLookupByLibrary.simpleMessage("Ajouter un nouveau"), "addOnPageSubtitle": MessageLookupByLibrary.simpleMessage( "Détails des modules complémentaires"), + "addOnValidTill": m5, "addOns": MessageLookupByLibrary.simpleMessage("Modules complémentaires"), "addPhotos": MessageLookupByLibrary.simpleMessage("Ajouter des photos"), @@ -242,17 +252,17 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ajouter la sélection"), "addToAlbum": MessageLookupByLibrary.simpleMessage("Ajouter à l\'album"), - "addToEnte": MessageLookupByLibrary.simpleMessage("Ajouter à ente"), + "addToEnte": MessageLookupByLibrary.simpleMessage("Ajouter à Ente"), "addToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Ajouter à un album masqué"), "addViewer": MessageLookupByLibrary.simpleMessage("Ajouter un observateur"), - "addViewers": m1, + "addViewers": m6, "addYourPhotosNow": MessageLookupByLibrary.simpleMessage( "Ajoutez vos photos maintenant"), "addedAs": MessageLookupByLibrary.simpleMessage("Ajouté comme"), - "addedBy": m4, - "addedSuccessfullyTo": m5, + "addedBy": m7, + "addedSuccessfullyTo": m8, "addingToFavorites": MessageLookupByLibrary.simpleMessage("Ajout aux favoris..."), "advanced": MessageLookupByLibrary.simpleMessage("Avancé"), @@ -263,7 +273,7 @@ class MessageLookup extends MessageLookupByLibrary { "after1Week": MessageLookupByLibrary.simpleMessage("Après 1 semaine"), "after1Year": MessageLookupByLibrary.simpleMessage("Après 1 an"), "albumOwner": MessageLookupByLibrary.simpleMessage("Propriétaire"), - "albumParticipantsCount": m6, + "albumParticipantsCount": m9, "albumTitle": MessageLookupByLibrary.simpleMessage("Titre de l\'album"), "albumUpdated": MessageLookupByLibrary.simpleMessage("Album mis à jour"), @@ -298,10 +308,9 @@ class MessageLookup extends MessageLookupByLibrary { "Android, iOS, Web, Ordinateur"), "androidSignInTitle": MessageLookupByLibrary.simpleMessage("Authentification requise"), - "appLock": MessageLookupByLibrary.simpleMessage("App lock"), - "appLockDescriptions": MessageLookupByLibrary.simpleMessage( - "Choose between your device\'s default lock screen and a custom lock screen with a PIN or password."), - "appVersion": m7, + "appLock": MessageLookupByLibrary.simpleMessage( + "Verrouillage d\'applications"), + "appVersion": m10, "appleId": MessageLookupByLibrary.simpleMessage("Apple ID"), "apply": MessageLookupByLibrary.simpleMessage("Appliquer"), "applyCodeTitle": @@ -349,8 +358,6 @@ class MessageLookup extends MessageLookupByLibrary { "Veuillez vous authentifier pour configurer l\'authentification à deux facteurs"), "authToInitiateAccountDeletion": MessageLookupByLibrary.simpleMessage( "Veuillez vous authentifier pour débuter la suppression du compte"), - "authToViewPasskey": MessageLookupByLibrary.simpleMessage( - "Please authenticate to view your passkey"), "authToViewYourActiveSessions": MessageLookupByLibrary.simpleMessage( "Veuillez vous authentifier pour voir vos sessions actives"), "authToViewYourHiddenFiles": MessageLookupByLibrary.simpleMessage( @@ -366,11 +373,22 @@ class MessageLookup extends MessageLookupByLibrary { "L\'authentification a échouée, veuillez réessayer"), "authenticationSuccessful": MessageLookupByLibrary.simpleMessage("Authentification réussie!"), - "autoLock": MessageLookupByLibrary.simpleMessage("Auto lock"), + "autoCastDialogBody": MessageLookupByLibrary.simpleMessage( + "Vous verrez ici les appareils Cast disponibles."), + "autoCastiOSPermission": MessageLookupByLibrary.simpleMessage( + "Assurez-vous que les autorisations de réseau local sont activées pour l\'application Ente Photos, dans les paramètres."), + "autoLock": + MessageLookupByLibrary.simpleMessage("Verrouillage automatique"), "autoLockFeatureDescription": MessageLookupByLibrary.simpleMessage( - "Time after which the app locks after being put in the background"), + "Délai après lequel l\'application se verrouille une fois qu\'elle a été mise en arrière-plan"), + "autoLogoutMessage": MessageLookupByLibrary.simpleMessage( + "En raison d\'un problème technique, vous avez été déconnecté. Veuillez nous excuser pour le désagrément."), + "autoPair": + MessageLookupByLibrary.simpleMessage("Appairage automatique"), + "autoPairDesc": MessageLookupByLibrary.simpleMessage( + "L\'appairage automatique ne fonctionne qu\'avec les appareils qui prennent en charge Chromecast."), "available": MessageLookupByLibrary.simpleMessage("Disponible"), - "availableStorageSpace": m8, + "availableStorageSpace": m11, "backedUpFolders": MessageLookupByLibrary.simpleMessage("Dossiers sauvegardés"), "backup": MessageLookupByLibrary.simpleMessage("Sauvegarde"), @@ -397,49 +415,66 @@ class MessageLookup extends MessageLookupByLibrary { "canOnlyRemoveFilesOwnedByYou": MessageLookupByLibrary.simpleMessage( "Vous ne pouvez supprimer que les fichiers que vous possédez"), "cancel": MessageLookupByLibrary.simpleMessage("Annuler"), - "cancelOtherSubscription": m9, + "cancelOtherSubscription": m12, "cancelSubscription": MessageLookupByLibrary.simpleMessage("Annuler l\'abonnement"), - "cannotAddMorePhotosAfterBecomingViewer": m10, + "cannotAddMorePhotosAfterBecomingViewer": m13, "cannotDeleteSharedFiles": MessageLookupByLibrary.simpleMessage( "Les fichiers partagés ne peuvent pas être supprimés"), + "castIPMismatchBody": MessageLookupByLibrary.simpleMessage( + "Veuillez vous assurer que vous êtes sur le même réseau que la TV."), + "castIPMismatchTitle": MessageLookupByLibrary.simpleMessage( + "Échec de la diffusion de l\'album"), + "castInstruction": MessageLookupByLibrary.simpleMessage( + "Visitez cast.ente.io sur l\'appareil que vous voulez associer.\n\nEntrez le code ci-dessous pour lire l\'album sur votre TV."), "centerPoint": MessageLookupByLibrary.simpleMessage("Point central"), + "change": MessageLookupByLibrary.simpleMessage("Modifier"), "changeEmail": MessageLookupByLibrary.simpleMessage("Modifier l\'e-mail"), "changeLocationOfSelectedItems": MessageLookupByLibrary.simpleMessage( - "Change location of selected items?"), + "Changer l\'emplacement des éléments sélectionnés ?"), "changePassword": MessageLookupByLibrary.simpleMessage("Modifier le mot de passe"), "changePasswordTitle": MessageLookupByLibrary.simpleMessage("Modifier le mot de passe"), "changePermissions": MessageLookupByLibrary.simpleMessage("Modifier les permissions ?"), + "changeYourReferralCode": MessageLookupByLibrary.simpleMessage( + "Modifier votre code de parrainage"), "checkForUpdates": MessageLookupByLibrary.simpleMessage("Vérifier les mises à jour"), "checkInboxAndSpamFolder": MessageLookupByLibrary.simpleMessage( "Veuillez consulter votre boîte de courriels (et les indésirables) pour compléter la vérification"), + "checkStatus": + MessageLookupByLibrary.simpleMessage("Vérifier le statut"), "checking": MessageLookupByLibrary.simpleMessage("Vérification..."), "cl_guest_view_call_to_action": MessageLookupByLibrary.simpleMessage( - "Sélectionnez des photos et essayez la \"Vue Invité\"."), + "Sélectionnez les photos et fixez les en \"Vue Invité\"."), "cl_guest_view_description": MessageLookupByLibrary.simpleMessage( - "Vous montrez des photos à un ami ? Pas de souci, il ne pourra pas trop faire défiler. La vue invité verrouille les photos que vous sélectionnez."), + "Montrer des photos à un ami en les transmettant sur votre téléphone ? Ne vous inquiétez pas si vous les faites glisser trop loin.\nLa vue \"invité\" les verrouillera dans les photos que vous avez sélectionnées."), "cl_guest_view_title": - MessageLookupByLibrary.simpleMessage("Vue Invité"), + MessageLookupByLibrary.simpleMessage("Vue invité"), "cl_panorama_viewer_description": MessageLookupByLibrary.simpleMessage( - "Nous avons ajouté le support pour visionner des photos panoramiques avec des vues à 360 degrés. L\'expérience est immersive avec une navigation basée sur le mouvement !"), + "Nous avons ajouté le support pour visionner des photos panoramiques avec des vues à 360 degrés. L\'expérience est immersive avec la navigation basée sur les mouvements !"), "cl_panorama_viewer_title": - MessageLookupByLibrary.simpleMessage("Visionneuse Panorama"), + MessageLookupByLibrary.simpleMessage("Visionneuse en panorama"), "cl_video_player_description": MessageLookupByLibrary.simpleMessage( - "Découvrez notre nouveau lecteur vidéo avec de meilleurs contrôles de lecture et le support des vidéos HDR."), + "Intégration d\'un nouveau lecteur vidéo, avec de meilleurs contrôles de lecture et la prise en charge des vidéos HDR."), "cl_video_player_title": - MessageLookupByLibrary.simpleMessage("Lecteur Vidéo"), + MessageLookupByLibrary.simpleMessage("Lecteur vidéo"), "claimFreeStorage": MessageLookupByLibrary.simpleMessage( "Réclamer le stockage gratuit"), "claimMore": MessageLookupByLibrary.simpleMessage("Réclamez plus !"), "claimed": MessageLookupByLibrary.simpleMessage("Réclamée"), - "claimedStorageSoFar": m11, + "claimedStorageSoFar": m14, + "cleanUncategorized": MessageLookupByLibrary.simpleMessage( + "Effacer les éléments non classés"), + "cleanUncategorizedDescription": MessageLookupByLibrary.simpleMessage( + "Supprimer tous les fichiers non-catégorisés étant présents dans d\'autres albums"), "clearCaches": MessageLookupByLibrary.simpleMessage("Nettoyer le cache"), + "clearIndexes": + MessageLookupByLibrary.simpleMessage("Effacer les index"), "click": MessageLookupByLibrary.simpleMessage("• Click"), "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage( "• Cliquez sur le menu de débordement"), @@ -449,18 +484,20 @@ class MessageLookup extends MessageLookupByLibrary { "clubByFileName": MessageLookupByLibrary.simpleMessage("Grouper par nom de fichier"), "clusteringProgress": - MessageLookupByLibrary.simpleMessage("Clustering progress"), + MessageLookupByLibrary.simpleMessage("Progression du regroupement"), "codeAppliedPageTitle": MessageLookupByLibrary.simpleMessage("Code appliqué"), + "codeChangeLimitReached": MessageLookupByLibrary.simpleMessage( + "Désolé, vous avez atteint la limite de changements de code."), "codeCopiedToClipboard": MessageLookupByLibrary.simpleMessage( "Code copié dans le presse-papiers"), "codeUsedByYou": MessageLookupByLibrary.simpleMessage("Code utilisé par vous"), "collabLinkSectionDescription": MessageLookupByLibrary.simpleMessage( - "Créez un lien pour permettre aux gens d\'ajouter et de voir des photos dans votre album partagé sans avoir besoin d\'une application ente ou d\'un compte. Idéal pour collecter des photos d\'événement."), + "Créez un lien pour permettre aux gens d\'ajouter et de voir des photos dans votre album partagé sans avoir besoin d\'une application ente ou d\'un compte. Idéal pour récupérer des photos d\'événement."), "collaborativeLink": MessageLookupByLibrary.simpleMessage("Lien collaboratif"), - "collaborativeLinkCreatedFor": m12, + "collaborativeLinkCreatedFor": m15, "collaborator": MessageLookupByLibrary.simpleMessage("Collaborateur"), "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": MessageLookupByLibrary.simpleMessage( @@ -488,10 +525,12 @@ class MessageLookup extends MessageLookupByLibrary { "Confirmer la clé de récupération"), "confirmYourRecoveryKey": MessageLookupByLibrary.simpleMessage( "Confirmer la clé de récupération"), - "contactFamilyAdmin": m13, + "connectToDevice": + MessageLookupByLibrary.simpleMessage("Connexion à l\'appareil"), + "contactFamilyAdmin": m16, "contactSupport": MessageLookupByLibrary.simpleMessage("Contacter l\'assistance"), - "contactToManageSubscription": m14, + "contactToManageSubscription": m17, "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), "contents": MessageLookupByLibrary.simpleMessage("Contenus"), "continueLabel": MessageLookupByLibrary.simpleMessage("Continuer"), @@ -520,7 +559,7 @@ class MessageLookup extends MessageLookupByLibrary { "createAlbumActionHint": MessageLookupByLibrary.simpleMessage( "Appuyez longuement pour sélectionner des photos et cliquez sur + pour créer un album"), "createCollaborativeLink": - MessageLookupByLibrary.simpleMessage("Create collaborative link"), + MessageLookupByLibrary.simpleMessage("Créer un lien collaboratif"), "createCollage": MessageLookupByLibrary.simpleMessage("Créez un collage"), "createNewAccount": @@ -536,6 +575,7 @@ class MessageLookup extends MessageLookupByLibrary { "currentUsageIs": MessageLookupByLibrary.simpleMessage( "L\'utilisation actuelle est "), "custom": MessageLookupByLibrary.simpleMessage("Personnaliser"), + "customEndpoint": m18, "darkTheme": MessageLookupByLibrary.simpleMessage("Sombre"), "dayToday": MessageLookupByLibrary.simpleMessage("Aujourd\'hui"), "dayYesterday": MessageLookupByLibrary.simpleMessage("Hier"), @@ -549,7 +589,7 @@ class MessageLookup extends MessageLookupByLibrary { "deleteAccount": MessageLookupByLibrary.simpleMessage("Supprimer le compte"), "deleteAccountFeedbackPrompt": MessageLookupByLibrary.simpleMessage( - "Nous sommes désolés de vous voir partir. S\'il vous plaît partagez vos commentaires pour nous aider à améliorer le service."), + "Nous sommes désolés de vous voir partir. N\'hésitez pas à partager vos commentaires pour nous aider à améliorer le service."), "deleteAccountPermanentlyButton": MessageLookupByLibrary.simpleMessage( "Supprimer définitivement le compte"), "deleteAlbum": @@ -560,7 +600,7 @@ class MessageLookup extends MessageLookupByLibrary { "Ceci supprimera tous les albums vides. Ceci est utile lorsque vous voulez réduire l\'encombrement dans votre liste d\'albums."), "deleteAll": MessageLookupByLibrary.simpleMessage("Tout Supprimer"), "deleteConfirmDialogBody": MessageLookupByLibrary.simpleMessage( - "Ce compte est lié à d\'autres applications ente, si vous en utilisez une.\\n\\nVos données téléchargées, dans toutes les applications ente, seront planifiées pour suppression, et votre compte sera définitivement supprimé."), + "Ce compte est lié à d\'autres applications Ente, si vous en utilisez une. Vos données téléchargées, dans toutes les applications ente, seront planifiées pour suppression, et votre compte sera définitivement supprimé."), "deleteEmailRequest": MessageLookupByLibrary.simpleMessage( "Veuillez envoyer un e-mail à account-deletion@ente.io à partir de votre adresse e-mail enregistrée."), "deleteEmptyAlbums": @@ -573,13 +613,13 @@ class MessageLookup extends MessageLookupByLibrary { "deleteFromDevice": MessageLookupByLibrary.simpleMessage("Supprimer de l\'appareil"), "deleteFromEnte": - MessageLookupByLibrary.simpleMessage("Supprimer de ente"), - "deleteItemCount": m16, + MessageLookupByLibrary.simpleMessage("Supprimé de Ente"), + "deleteItemCount": m19, "deleteLocation": MessageLookupByLibrary.simpleMessage("Supprimer la localisation"), "deletePhotos": MessageLookupByLibrary.simpleMessage("Supprimer des photos"), - "deleteProgress": m17, + "deleteProgress": m20, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Il manque une fonction clé dont j\'ai besoin"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -600,19 +640,28 @@ class MessageLookup extends MessageLookupByLibrary { "designedToOutlive": MessageLookupByLibrary.simpleMessage("Conçu pour survivre"), "details": MessageLookupByLibrary.simpleMessage("Détails"), + "developerSettings": + MessageLookupByLibrary.simpleMessage("Paramètres du développeur"), + "developerSettingsWarning": MessageLookupByLibrary.simpleMessage( + "Êtes-vous sûr de vouloir modifier les paramètres du développeur ?"), + "deviceCodeHint": + MessageLookupByLibrary.simpleMessage("Saisissez le code"), "deviceFilesAutoUploading": MessageLookupByLibrary.simpleMessage( - "Les fichiers ajoutés à cet album seront automatiquement téléchargés sur ente."), - "deviceLock": MessageLookupByLibrary.simpleMessage("Device lock"), + "Les fichiers ajoutés à cet album seront automatiquement téléchargés sur Ente."), + "deviceLock": + MessageLookupByLibrary.simpleMessage("Verrouillage de l\'appareil"), "deviceLockExplanation": MessageLookupByLibrary.simpleMessage( "Désactiver le verrouillage de l\'écran de l\'appareil lorsque ente est au premier plan et il y a une sauvegarde en cours. Ce n\'est normalement pas nécessaire, mais peut aider les gros téléchargements et les premières importations de grandes bibliothèques plus rapidement."), + "deviceNotFound": + MessageLookupByLibrary.simpleMessage("Appareil non trouvé"), "didYouKnow": MessageLookupByLibrary.simpleMessage("Le savais-tu ?"), "disableAutoLock": MessageLookupByLibrary.simpleMessage( "Désactiver le verrouillage automatique"), "disableDownloadWarningBody": MessageLookupByLibrary.simpleMessage( - "Les téléspectateurs peuvent toujours prendre des captures d\'écran ou enregistrer une copie de vos photos en utilisant des outils externes"), + "Les observateurs peuvent toujours prendre des captures d\'écran ou enregistrer une copie de vos photos en utilisant des outils externes"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Veuillez remarquer"), - "disableLinkMessage": m18, + "disableLinkMessage": m21, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Désactiver la double-authentification"), "disablingTwofactorAuthentication": @@ -621,6 +670,8 @@ class MessageLookup extends MessageLookupByLibrary { "discord": MessageLookupByLibrary.simpleMessage("Discord"), "dismiss": MessageLookupByLibrary.simpleMessage("Rejeter"), "distanceInKMUnit": MessageLookupByLibrary.simpleMessage("km"), + "doNotSignOut": + MessageLookupByLibrary.simpleMessage("Ne pas se déconnecter"), "doThisLater": MessageLookupByLibrary.simpleMessage("Plus tard"), "doYouWantToDiscardTheEditsYouHaveMade": MessageLookupByLibrary.simpleMessage( @@ -633,27 +684,28 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Échec du téléchargement"), "downloading": MessageLookupByLibrary.simpleMessage("Téléchargement en cours..."), - "dropSupportEmail": m19, - "duplicateFileCountWithStorageSaved": m20, - "duplicateItemsGroup": m21, + "dropSupportEmail": m22, + "duplicateFileCountWithStorageSaved": m23, + "duplicateItemsGroup": m24, "edit": MessageLookupByLibrary.simpleMessage("Éditer"), - "editLocation": MessageLookupByLibrary.simpleMessage("Edit location"), + "editLocation": + MessageLookupByLibrary.simpleMessage("Modifier l’emplacement"), "editLocationTagTitle": MessageLookupByLibrary.simpleMessage("Modifier l’emplacement"), "editsSaved": MessageLookupByLibrary.simpleMessage("Modification sauvegardée"), "editsToLocationWillOnlyBeSeenWithinEnte": MessageLookupByLibrary.simpleMessage( - "Edits to location will only be seen within Ente"), + "Les modifications de l\'emplacement ne seront visibles que dans Ente"), "eligible": MessageLookupByLibrary.simpleMessage("éligible"), "email": MessageLookupByLibrary.simpleMessage("E-mail"), - "emailChangedTo": m22, - "emailNoEnteAccount": m23, + "emailChangedTo": m25, + "emailNoEnteAccount": m26, "emailVerificationToggle": MessageLookupByLibrary.simpleMessage( "Vérification de l\'adresse e-mail"), "emailYourLogs": MessageLookupByLibrary.simpleMessage("Envoyez vos logs par e-mail"), - "empty": MessageLookupByLibrary.simpleMessage("Vide"), + "empty": MessageLookupByLibrary.simpleMessage("Vider"), "emptyTrash": MessageLookupByLibrary.simpleMessage("Vider la corbeille ?"), "enableMaps": MessageLookupByLibrary.simpleMessage("Activer la carte"), @@ -664,15 +716,17 @@ class MessageLookup extends MessageLookupByLibrary { "encryption": MessageLookupByLibrary.simpleMessage("Chiffrement"), "encryptionKeys": MessageLookupByLibrary.simpleMessage("Clés de chiffrement"), + "endpointUpdatedMessage": MessageLookupByLibrary.simpleMessage( + "Point de terminaison mis à jour avec succès"), "endtoendEncryptedByDefault": MessageLookupByLibrary.simpleMessage( "Chiffrement de bout en bout par défaut"), "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": MessageLookupByLibrary.simpleMessage( - "ente peut chiffrer et conserver des fichiers que si vous leur accordez l\'accès"), + "Ente peut chiffrer et conserver des fichiers que si vous leur accordez l\'accès"), "entePhotosPerm": MessageLookupByLibrary.simpleMessage( - "ente a besoin d\'une autorisation pour préserver vos photos"), + "Ente a besoin d\'une autorisation pour préserver vos photos"), "enteSubscriptionPitch": MessageLookupByLibrary.simpleMessage( - "ente conserve vos souvenirs, donc ils sont toujours disponibles pour vous, même si vous perdez votre appareil."), + "Ente conserve vos souvenirs, ils sont donc toujours disponibles pour vous, même si vous perdez votre appareil."), "enteSubscriptionShareWithFamily": MessageLookupByLibrary.simpleMessage( "Vous pouvez également ajouter votre famille à votre forfait."), "enterAlbumName": @@ -689,9 +743,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Saisissez le mot de passe"), "enterPasswordToEncrypt": MessageLookupByLibrary.simpleMessage( "Entrez un mot de passe que nous pouvons utiliser pour chiffrer vos données"), - "enterPersonName": - MessageLookupByLibrary.simpleMessage("Enter person name"), - "enterPin": MessageLookupByLibrary.simpleMessage("Enter PIN"), + "enterPersonName": MessageLookupByLibrary.simpleMessage( + "Entrez le nom d\'une personne"), + "enterPin": MessageLookupByLibrary.simpleMessage("Saisir le code PIN"), "enterReferralCode": MessageLookupByLibrary.simpleMessage( "Entrez le code de parrainage"), "enterThe6digitCodeFromnyourAuthenticatorApp": @@ -716,7 +770,7 @@ class MessageLookup extends MessageLookupByLibrary { "exportYourData": MessageLookupByLibrary.simpleMessage("Exportez vos données"), "faceRecognition": - MessageLookupByLibrary.simpleMessage("Face recognition"), + MessageLookupByLibrary.simpleMessage("Reconnaissance faciale"), "faces": MessageLookupByLibrary.simpleMessage("Visages"), "failedToApplyCode": MessageLookupByLibrary.simpleMessage( "Impossible d\'appliquer le code"), @@ -752,35 +806,42 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Types de fichiers"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Types et noms de fichiers"), - "filesBackedUpFromDevice": m24, - "filesBackedUpInAlbum": m25, + "filesBackedUpFromDevice": m27, + "filesBackedUpInAlbum": m28, "filesDeleted": MessageLookupByLibrary.simpleMessage("Fichiers supprimés"), + "filesSavedToGallery": MessageLookupByLibrary.simpleMessage( + "Fichiers enregistrés dans la galerie"), + "findPeopleByName": MessageLookupByLibrary.simpleMessage( + "Trouver des personnes rapidement par leur nom"), "flip": MessageLookupByLibrary.simpleMessage("Retourner"), "forYourMemories": MessageLookupByLibrary.simpleMessage("pour vos souvenirs"), "forgotPassword": MessageLookupByLibrary.simpleMessage("Mot de passe oublié"), - "foundFaces": MessageLookupByLibrary.simpleMessage("Found faces"), + "foundFaces": MessageLookupByLibrary.simpleMessage("Visages trouvés"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("Stockage gratuit réclamé"), - "freeStorageOnReferralSuccess": m26, + "freeStorageOnReferralSuccess": m29, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("Stockage gratuit utilisable"), "freeTrial": MessageLookupByLibrary.simpleMessage("Essai gratuit"), - "freeTrialValidTill": m27, - "freeUpAccessPostDelete": m28, - "freeUpAmount": m29, + "freeTrialValidTill": m30, + "freeUpAccessPostDelete": m31, + "freeUpAmount": m32, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage( "Libérer de l\'espace sur l\'appareil"), + "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( + "Économisez de l\'espace sur votre appareil en effaçant les fichiers qui ont déjà été sauvegardés."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Libérer de l\'espace"), - "freeUpSpaceSaving": m30, + "freeUpSpaceSaving": m33, "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Jusqu\'à 1000 souvenirs affichés dans la galerie"), "general": MessageLookupByLibrary.simpleMessage("Général"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Génération des clés de chiffrement..."), + "genericProgress": m34, "goToSettings": MessageLookupByLibrary.simpleMessage("Allez aux réglages"), "googlePlayId": @@ -791,20 +852,19 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Accorder la permission"), "groupNearbyPhotos": MessageLookupByLibrary.simpleMessage( "Grouper les photos à proximité"), - "guestView": MessageLookupByLibrary.simpleMessage("Guest view"), - "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( - "To enable guest view, please setup device passcode or screen lock in your system settings."), "hearUsExplanation": MessageLookupByLibrary.simpleMessage( "Nous ne suivons pas les installations d\'applications. Il serait utile que vous nous disiez comment vous nous avez trouvés !"), "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( "Comment avez-vous entendu parler de Ente? (facultatif)"), + "help": MessageLookupByLibrary.simpleMessage("Aide"), "hidden": MessageLookupByLibrary.simpleMessage("Masqué"), "hide": MessageLookupByLibrary.simpleMessage("Masquer"), - "hideContent": MessageLookupByLibrary.simpleMessage("Hide content"), + "hideContent": + MessageLookupByLibrary.simpleMessage("Masquer le contenu"), "hideContentDescriptionAndroid": MessageLookupByLibrary.simpleMessage( - "Hides app content in the app switcher and disables screenshots"), + "Masque le contenu de l\'application dans le sélecteur d\'applications et désactive les captures d\'écran"), "hideContentDescriptionIos": MessageLookupByLibrary.simpleMessage( - "Hides app content in the app switcher"), + "Masque le contenu de l\'application dans le sélecteur d\'application"), "hiding": MessageLookupByLibrary.simpleMessage("Masquage en cours..."), "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("Hébergé chez OSM France"), @@ -819,8 +879,8 @@ class MessageLookup extends MessageLookupByLibrary { "iOSOkButton": MessageLookupByLibrary.simpleMessage("Ok"), "ignoreUpdate": MessageLookupByLibrary.simpleMessage("Ignorer"), "ignoredFolderUploadReason": MessageLookupByLibrary.simpleMessage( - "Certains fichiers de cet album sont ignorés parce qu\'ils avaient été précédemment supprimés de ente."), - "immediately": MessageLookupByLibrary.simpleMessage("Immediately"), + "Certains fichiers de cet album sont ignorés parce qu\'ils avaient été précédemment supprimés de Ente."), + "immediately": MessageLookupByLibrary.simpleMessage("Immédiatement"), "importing": MessageLookupByLibrary.simpleMessage("Importation en cours..."), "incorrectCode": @@ -833,33 +893,41 @@ class MessageLookup extends MessageLookupByLibrary { "La clé de secours que vous avez entrée est incorrecte"), "incorrectRecoveryKeyTitle": MessageLookupByLibrary.simpleMessage("Clé de secours non valide"), + "indexedItems": + MessageLookupByLibrary.simpleMessage("Éléments indexés"), "indexingIsPaused": MessageLookupByLibrary.simpleMessage( - "Indexing is paused, will automatically resume when device is ready"), + "L\'indexation est en pause. Elle reprendra automatiquement lorsque l\'appareil sera prêt."), "insecureDevice": MessageLookupByLibrary.simpleMessage("Appareil non sécurisé"), "installManually": MessageLookupByLibrary.simpleMessage("Installation manuelle"), "invalidEmailAddress": MessageLookupByLibrary.simpleMessage("Adresse e-mail invalide"), + "invalidEndpoint": MessageLookupByLibrary.simpleMessage( + "Point de terminaison non valide"), + "invalidEndpointMessage": MessageLookupByLibrary.simpleMessage( + "Désolé, le point de terminaison que vous avez entré n\'est pas valide. Veuillez en entrer un valide puis réessayez."), "invalidKey": MessageLookupByLibrary.simpleMessage("Clé invalide"), "invalidRecoveryKey": MessageLookupByLibrary.simpleMessage( - "La clé de récupération que vous avez saisie n\'est pas valide. Veuillez vous assurer qu\'elle "), + "La clé de récupération que vous avez saisie n\'est pas valide. Veuillez vérifier qu\'elle contient 24 caractères et qu\'ils sont correctement orthographiés.\n\nSi vous avez saisi un ancien code de récupération, veuillez vérifier qu\'il contient 64 caractères et qu\'ils sont correctement orthographiés."), "invite": MessageLookupByLibrary.simpleMessage("Inviter"), - "inviteToEnte": MessageLookupByLibrary.simpleMessage("Inviter à ente"), + "inviteToEnte": + MessageLookupByLibrary.simpleMessage("Inviter à rejoindre Ente"), "inviteYourFriends": MessageLookupByLibrary.simpleMessage("Invite tes ami(e)s"), "inviteYourFriendsToEnte": - MessageLookupByLibrary.simpleMessage("Invitez vos amis sur ente"), + MessageLookupByLibrary.simpleMessage("Invitez vos amis sur Ente"), "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Il semble qu\'une erreur s\'est produite. Veuillez réessayer après un certain temps. Si l\'erreur persiste, veuillez contacter notre équipe d\'assistance."), - "itemCount": m32, + "itemCount": m35, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Les éléments montrent le nombre de jours restants avant la suppression définitive"), "itemsWillBeRemovedFromAlbum": MessageLookupByLibrary.simpleMessage( "Les éléments sélectionnés seront supprimés de cet album"), - "joinDiscord": MessageLookupByLibrary.simpleMessage("Join Discord"), + "joinDiscord": + MessageLookupByLibrary.simpleMessage("Rejoindre Discord"), "keepPhotos": MessageLookupByLibrary.simpleMessage("Conserver les photos"), "kiloMeterUnit": MessageLookupByLibrary.simpleMessage("km"), @@ -874,6 +942,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Quitter le plan familial"), "leaveSharedAlbum": MessageLookupByLibrary.simpleMessage("Quitter l\'album partagé?"), + "left": MessageLookupByLibrary.simpleMessage("Gauche"), "light": MessageLookupByLibrary.simpleMessage("Clair"), "lightTheme": MessageLookupByLibrary.simpleMessage("Clair"), "linkCopiedToClipboard": MessageLookupByLibrary.simpleMessage( @@ -882,7 +951,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Limite d\'appareil"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Activé"), "linkExpired": MessageLookupByLibrary.simpleMessage("Expiré"), - "linkExpiresOn": m33, + "linkExpiresOn": m36, "linkExpiry": MessageLookupByLibrary.simpleMessage("Expiration du lien"), "linkHasExpired": @@ -913,17 +982,23 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Chargement de la galerie..."), "loadingMessage": MessageLookupByLibrary.simpleMessage("Chargement de vos photos..."), + "loadingModel": MessageLookupByLibrary.simpleMessage( + "Téléchargement des modèles..."), "localGallery": MessageLookupByLibrary.simpleMessage("Galerie locale"), "location": MessageLookupByLibrary.simpleMessage("Emplacement"), "locationName": MessageLookupByLibrary.simpleMessage("Nom du lieu"), "locationTagFeatureDescription": MessageLookupByLibrary.simpleMessage( "Un tag d\'emplacement regroupe toutes les photos qui ont été prises dans un certain rayon d\'une photo"), - "locations": MessageLookupByLibrary.simpleMessage("Locations"), + "locations": MessageLookupByLibrary.simpleMessage("Emplacements"), "lockButtonLabel": MessageLookupByLibrary.simpleMessage("Verrouiller"), "lockscreen": - MessageLookupByLibrary.simpleMessage("Ecran de vérouillage"), + MessageLookupByLibrary.simpleMessage("Écran de verrouillage"), "logInLabel": MessageLookupByLibrary.simpleMessage("Se connecter"), "loggingOut": MessageLookupByLibrary.simpleMessage("Deconnexion..."), + "loginSessionExpired": + MessageLookupByLibrary.simpleMessage("Session expirée"), + "loginSessionExpiredDetails": MessageLookupByLibrary.simpleMessage( + "Votre session a expiré. Veuillez vous reconnecter."), "loginTerms": MessageLookupByLibrary.simpleMessage( "En cliquant sur connecter, j\'accepte les conditions d\'utilisation et la politique de confidentialité"), "logout": MessageLookupByLibrary.simpleMessage("Déconnexion"), @@ -931,11 +1006,15 @@ class MessageLookup extends MessageLookupByLibrary { "Cela enverra des logs pour nous aider à déboguer votre problème. Veuillez noter que les noms de fichiers seront inclus pour aider à suivre les problèmes avec des fichiers spécifiques."), "longPressAnEmailToVerifyEndToEndEncryption": MessageLookupByLibrary.simpleMessage( - "Long press an email to verify end to end encryption."), + "Appuyez longuement sur un e-mail pour vérifier le chiffrement de bout en bout."), "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Appuyez longuement sur un élément pour le voir en plein écran"), "lostDevice": MessageLookupByLibrary.simpleMessage("Appareil perdu ?"), + "machineLearning": + MessageLookupByLibrary.simpleMessage("Apprentissage automatique"), + "magicSearch": + MessageLookupByLibrary.simpleMessage("Recherche magique"), "manage": MessageLookupByLibrary.simpleMessage("Gérer"), "manageDeviceStorage": MessageLookupByLibrary.simpleMessage( "Gérer le stockage de l\'appareil"), @@ -945,40 +1024,47 @@ class MessageLookup extends MessageLookupByLibrary { "manageParticipants": MessageLookupByLibrary.simpleMessage("Gérer"), "manageSubscription": MessageLookupByLibrary.simpleMessage("Gérer l\'abonnement"), + "manualPairDesc": MessageLookupByLibrary.simpleMessage( + "L\'appairage avec le code PIN fonctionne avec n\'importe quel écran sur lequel vous souhaitez voir votre album."), "map": MessageLookupByLibrary.simpleMessage("Carte"), "maps": MessageLookupByLibrary.simpleMessage("Cartes"), "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), - "memoryCount": m34, + "memoryCount": m0, "merchandise": MessageLookupByLibrary.simpleMessage("Marchandise"), "mobileWebDesktop": MessageLookupByLibrary.simpleMessage("Mobile, Web, Ordinateur"), - "moderateStrength": - MessageLookupByLibrary.simpleMessage("Sécurité moyenne"), + "moderateStrength": MessageLookupByLibrary.simpleMessage("Moyen"), "modifyYourQueryOrTrySearchingFor": MessageLookupByLibrary.simpleMessage( "Modifiez votre requête, ou essayez de rechercher"), "moments": MessageLookupByLibrary.simpleMessage("Souvenirs"), "monthly": MessageLookupByLibrary.simpleMessage("Mensuel"), - "moveItem": m35, + "moveItem": m37, "moveToAlbum": MessageLookupByLibrary.simpleMessage("Déplacer vers l\'album"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage( "Déplacer vers un album masqué"), - "movedSuccessfullyTo": m36, + "movedSuccessfullyTo": m38, "movedToTrash": MessageLookupByLibrary.simpleMessage("Déplacé dans la corbeille"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Déplacement des fichiers vers l\'album..."), "name": MessageLookupByLibrary.simpleMessage("Nom"), + "networkConnectionRefusedErr": MessageLookupByLibrary.simpleMessage( + "Impossible de se connecter à Ente, veuillez réessayer après un certain temps. Si l\'erreur persiste, veuillez contacter le support."), + "networkHostLookUpErr": MessageLookupByLibrary.simpleMessage( + "Impossible de se connecter à Ente, veuillez vérifier vos paramètres réseau et contacter le support si l\'erreur persiste."), "never": MessageLookupByLibrary.simpleMessage("Jamais"), "newAlbum": MessageLookupByLibrary.simpleMessage("Nouvel album"), - "newToEnte": MessageLookupByLibrary.simpleMessage("Nouveau sur ente"), + "newToEnte": MessageLookupByLibrary.simpleMessage("Nouveau à Ente"), "newest": MessageLookupByLibrary.simpleMessage("Le plus récent"), - "next": MessageLookupByLibrary.simpleMessage("Next"), + "next": MessageLookupByLibrary.simpleMessage("Suivant"), "no": MessageLookupByLibrary.simpleMessage("Non"), "noAlbumsSharedByYouYet": MessageLookupByLibrary.simpleMessage( "Aucun album que vous avez partagé"), + "noDeviceFound": + MessageLookupByLibrary.simpleMessage("Aucun appareil trouvé"), "noDeviceLimit": MessageLookupByLibrary.simpleMessage("Aucune"), "noDeviceThatCanBeDeleted": MessageLookupByLibrary.simpleMessage( "Vous n\'avez pas de fichiers sur cet appareil qui peuvent être supprimés"), @@ -989,22 +1075,24 @@ class MessageLookup extends MessageLookupByLibrary { "Aucune photo ou vidéo cachée"), "noImagesWithLocation": MessageLookupByLibrary.simpleMessage( "Aucune image avec localisation"), + "noInternetConnection": + MessageLookupByLibrary.simpleMessage("Aucune connexion internet"), "noPhotosAreBeingBackedUpRightNow": MessageLookupByLibrary.simpleMessage( "Aucune photo en cours de sauvegarde"), "noPhotosFoundHere": MessageLookupByLibrary.simpleMessage("Aucune photo trouvée"), - "noQuickLinksSelected": - MessageLookupByLibrary.simpleMessage("No quick links selected"), - "noRecoveryKey": - MessageLookupByLibrary.simpleMessage("Aucune clé de récupération?"), + "noQuickLinksSelected": MessageLookupByLibrary.simpleMessage( + "Aucun lien rapide sélectionné"), + "noRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Aucune clé de récupération ?"), "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( "En raison de notre protocole de chiffrement de bout en bout, vos données ne peuvent pas être déchiffré sans votre mot de passe ou clé de récupération"), "noResults": MessageLookupByLibrary.simpleMessage("Aucun résultat"), "noResultsFound": MessageLookupByLibrary.simpleMessage("Aucun résultat trouvé"), "noSystemLockFound": - MessageLookupByLibrary.simpleMessage("No system lock found"), + MessageLookupByLibrary.simpleMessage("Aucun verrou système trouvé"), "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( "Rien n\'a encore été partagé avec vous"), "nothingToSeeHere": MessageLookupByLibrary.simpleMessage( @@ -1029,23 +1117,39 @@ class MessageLookup extends MessageLookupByLibrary { "Optionnel, aussi court que vous le souhaitez..."), "orPickAnExistingOne": MessageLookupByLibrary.simpleMessage( "Sélectionner un fichier existant"), + "pair": MessageLookupByLibrary.simpleMessage("Associer"), + "pairWithPin": + MessageLookupByLibrary.simpleMessage("Appairer avec le code PIN"), + "pairingComplete": + MessageLookupByLibrary.simpleMessage("Appairage terminé"), + "panorama": MessageLookupByLibrary.simpleMessage("Panorama"), + "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage( + "La vérification est toujours en attente"), + "passkey": MessageLookupByLibrary.simpleMessage("Code d\'accès"), + "passkeyAuthTitle": MessageLookupByLibrary.simpleMessage( + "Vérification du code d\'accès"), "password": MessageLookupByLibrary.simpleMessage("Mot de passe"), "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage( "Le mot de passe a été modifié"), "passwordLock": MessageLookupByLibrary.simpleMessage("Mot de passe verrou"), - "passwordStrength": m39, + "passwordStrength": m41, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( - "Password strength is calculated considering the length of the password, used characters, and whether or not the password appears in the top 10,000 most used passwords"), + "La force du mot de passe est calculée en tenant compte de la longueur du mot de passe, des caractères utilisés et du fait que le mot de passe figure ou non parmi les 10 000 mots de passe les plus utilisés"), "passwordWarning": MessageLookupByLibrary.simpleMessage( "Nous ne stockons pas ce mot de passe, donc si vous l\'oubliez, nous ne pouvons pas déchiffrer vos données"), "paymentDetails": MessageLookupByLibrary.simpleMessage("Détails de paiement"), "paymentFailed": MessageLookupByLibrary.simpleMessage("Échec du paiement"), - "paymentFailedTalkToProvider": m40, + "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( + "Malheureusement votre paiement a échoué. Veuillez contacter le support et nous vous aiderons !"), + "paymentFailedTalkToProvider": m42, + "pendingItems": + MessageLookupByLibrary.simpleMessage("Éléments en attente"), "pendingSync": MessageLookupByLibrary.simpleMessage("Synchronisation en attente"), + "people": MessageLookupByLibrary.simpleMessage("Personnes"), "peopleUsingYourCode": MessageLookupByLibrary.simpleMessage( "Personnes utilisant votre code"), "permDeleteWarning": MessageLookupByLibrary.simpleMessage( @@ -1066,24 +1170,30 @@ class MessageLookup extends MessageLookupByLibrary { "pickCenterPoint": MessageLookupByLibrary.simpleMessage( "Sélectionner le point central"), "pinAlbum": MessageLookupByLibrary.simpleMessage("Épingler l\'album"), - "pinLock": MessageLookupByLibrary.simpleMessage("PIN lock"), - "playStoreFreeTrialValidTill": m41, + "pinLock": + MessageLookupByLibrary.simpleMessage("Verrouillage du code PIN"), + "playOnTv": + MessageLookupByLibrary.simpleMessage("Lire l\'album sur la TV"), + "playStoreFreeTrialValidTill": m43, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("Abonnement au PlayStore"), + "pleaseCheckYourInternetConnectionAndTryAgain": + MessageLookupByLibrary.simpleMessage( + "S\'il vous plaît, vérifiez votre connexion à internet et réessayez."), "pleaseContactSupportAndWeWillBeHappyToHelp": MessageLookupByLibrary.simpleMessage( "Veuillez contacter support@ente.io et nous serons heureux de vous aider!"), "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Merci de contacter l\'assistance si cette erreur persiste"), - "pleaseEmailUsAt": m42, + "pleaseEmailUsAt": m44, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage( "Veuillez accorder la permission"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Veuillez vous reconnecter"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( - "Please select quick links to remove"), - "pleaseSendTheLogsTo": m43, + "Veuillez sélectionner les liens rapides à supprimer"), + "pleaseSendTheLogsTo": m45, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Veuillez réessayer"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1119,7 +1229,7 @@ class MessageLookup extends MessageLookupByLibrary { "rateTheApp": MessageLookupByLibrary.simpleMessage("Évaluer l\'application"), "rateUs": MessageLookupByLibrary.simpleMessage("Évaluez-nous"), - "rateUsOnStore": m44, + "rateUsOnStore": m46, "recover": MessageLookupByLibrary.simpleMessage("Récupérer"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Récupérer un compte"), @@ -1145,15 +1255,16 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Recréer le mot de passe"), "reddit": MessageLookupByLibrary.simpleMessage("Reddit"), "reenterPassword": - MessageLookupByLibrary.simpleMessage("Re-enter password"), - "reenterPin": MessageLookupByLibrary.simpleMessage("Re-enter PIN"), + MessageLookupByLibrary.simpleMessage("Ressaisir le mot de passe"), + "reenterPin": + MessageLookupByLibrary.simpleMessage("Ressaisir le code PIN"), "referFriendsAnd2xYourPlan": MessageLookupByLibrary.simpleMessage( "Parrainez des amis et 2x votre abonnement"), "referralStep1": MessageLookupByLibrary.simpleMessage( "1. Donnez ce code à vos amis"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Ils s\'inscrivent à une offre payante"), - "referralStep3": m45, + "referralStep3": m47, "referrals": MessageLookupByLibrary.simpleMessage("Parrainages"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Les recommandations sont actuellement en pause"), @@ -1167,9 +1278,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Miniatures distantes"), "remoteVideos": MessageLookupByLibrary.simpleMessage("Vidéos distantes"), - "remove": MessageLookupByLibrary.simpleMessage("Enlever"), + "remove": MessageLookupByLibrary.simpleMessage("Supprimer"), "removeDuplicates": MessageLookupByLibrary.simpleMessage("Supprimer les doublons"), + "removeDuplicatesDesc": MessageLookupByLibrary.simpleMessage( + "Examiner et supprimer les fichiers qui sont des doublons exacts."), "removeFromAlbum": MessageLookupByLibrary.simpleMessage("Retirer de l\'album"), "removeFromAlbumTitle": @@ -1179,13 +1292,13 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Supprimer le lien"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Supprimer le participant"), - "removeParticipantBody": m46, - "removePersonLabel": - MessageLookupByLibrary.simpleMessage("Remove person label"), + "removeParticipantBody": m48, + "removePersonLabel": MessageLookupByLibrary.simpleMessage( + "Supprimer le libellé d\'une personne"), "removePublicLink": MessageLookupByLibrary.simpleMessage("Supprimer le lien public"), "removePublicLinks": - MessageLookupByLibrary.simpleMessage("Remove public links"), + MessageLookupByLibrary.simpleMessage("Supprimer les liens publics"), "removeShareItemsWarning": MessageLookupByLibrary.simpleMessage( "Certains des éléments que vous êtes en train de retirer ont été ajoutés par d\'autres personnes, vous perdrez l\'accès vers ces éléments"), "removeWithQuestionMark": @@ -1199,7 +1312,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Renommer le fichier"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Renouveler l’abonnement"), - "renewsOn": m47, + "renewsOn": m49, "reportABug": MessageLookupByLibrary.simpleMessage("Signaler un bug"), "reportBug": MessageLookupByLibrary.simpleMessage("Signaler un bug"), "resendEmail": @@ -1218,6 +1331,10 @@ class MessageLookup extends MessageLookupByLibrary { "retry": MessageLookupByLibrary.simpleMessage("Réessayer"), "reviewDeduplicateItems": MessageLookupByLibrary.simpleMessage( "Veuillez vérifier et supprimer les éléments que vous croyez dupliqués."), + "reviewSuggestions": + MessageLookupByLibrary.simpleMessage("Consulter les suggestions"), + "right": MessageLookupByLibrary.simpleMessage("Droite"), + "rotate": MessageLookupByLibrary.simpleMessage("Pivoter"), "rotateLeft": MessageLookupByLibrary.simpleMessage("Pivoter à gauche"), "rotateRight": MessageLookupByLibrary.simpleMessage("Faire pivoter à droite"), @@ -1233,11 +1350,13 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Enregistrez votre clé de récupération si vous ne l\'avez pas déjà fait"), "saving": MessageLookupByLibrary.simpleMessage("Enregistrement..."), + "savingEdits": MessageLookupByLibrary.simpleMessage( + "Enregistrement des modifications..."), "scanCode": MessageLookupByLibrary.simpleMessage("Scanner le code"), "scanThisBarcodeWithnyourAuthenticatorApp": MessageLookupByLibrary.simpleMessage( "Scannez ce code-barres avec\nvotre application d\'authentification"), - "search": MessageLookupByLibrary.simpleMessage("Search"), + "search": MessageLookupByLibrary.simpleMessage("Rechercher"), "searchAlbumsEmptySection": MessageLookupByLibrary.simpleMessage("Albums"), "searchByAlbumNameHint": @@ -1249,7 +1368,7 @@ class MessageLookup extends MessageLookupByLibrary { "searchDatesEmptySection": MessageLookupByLibrary.simpleMessage( "Recherche par date, mois ou année"), "searchFaceEmptySection": MessageLookupByLibrary.simpleMessage( - "Trouver toutes les photos d\'une personne"), + "Les personnes seront affichées ici une fois l\'indexation terminée"), "searchFileTypesAndNamesEmptySection": MessageLookupByLibrary.simpleMessage("Types et noms de fichiers"), "searchHint1": MessageLookupByLibrary.simpleMessage( @@ -1265,12 +1384,12 @@ class MessageLookup extends MessageLookupByLibrary { "Grouper les photos qui sont prises dans un certain angle d\'une photo"), "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage( "Invitez des gens, et vous verrez ici toutes les photos qu\'ils partagent"), - "searchResultCount": m48, + "searchResultCount": m50, "security": MessageLookupByLibrary.simpleMessage("Sécurité"), "selectALocation": - MessageLookupByLibrary.simpleMessage("Select a location"), - "selectALocationFirst": - MessageLookupByLibrary.simpleMessage("Select a location first"), + MessageLookupByLibrary.simpleMessage("Sélectionnez un emplacement"), + "selectALocationFirst": MessageLookupByLibrary.simpleMessage( + "Sélectionnez d\'abord un emplacement"), "selectAlbum": MessageLookupByLibrary.simpleMessage("Sélectionner album"), "selectAll": MessageLookupByLibrary.simpleMessage("Tout sélectionner"), @@ -1287,20 +1406,22 @@ class MessageLookup extends MessageLookupByLibrary { "selectYourPlan": MessageLookupByLibrary.simpleMessage("Sélectionner votre offre"), "selectedFilesAreNotOnEnte": MessageLookupByLibrary.simpleMessage( - "Les fichiers sélectionnés ne sont pas sur ente"), + "Les fichiers sélectionnés ne sont pas sur Ente"), "selectedFoldersWillBeEncryptedAndBackedUp": MessageLookupByLibrary.simpleMessage( "Les dossiers sélectionnés seront cryptés et sauvegardés"), "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage( "Les éléments sélectionnés seront supprimés de tous les albums et déplacés dans la corbeille."), - "selectedPhotos": m49, - "selectedPhotosWithYours": m50, + "selectedPhotos": m1, + "selectedPhotosWithYours": m51, "send": MessageLookupByLibrary.simpleMessage("Envoyer"), "sendEmail": MessageLookupByLibrary.simpleMessage("Envoyer un e-mail"), "sendInvite": MessageLookupByLibrary.simpleMessage("Envoyer Invitations"), "sendLink": MessageLookupByLibrary.simpleMessage("Envoyer le lien"), + "serverEndpoint": MessageLookupByLibrary.simpleMessage( + "Point de terminaison serveur"), "sessionExpired": MessageLookupByLibrary.simpleMessage("Session expirée"), "setAPassword": @@ -1309,14 +1430,15 @@ class MessageLookup extends MessageLookupByLibrary { "setCover": MessageLookupByLibrary.simpleMessage("Définir la couverture"), "setLabel": MessageLookupByLibrary.simpleMessage("Définir"), - "setNewPassword": - MessageLookupByLibrary.simpleMessage("Set new password"), - "setNewPin": MessageLookupByLibrary.simpleMessage("Set new PIN"), + "setNewPassword": MessageLookupByLibrary.simpleMessage( + "Définir un nouveau mot de passe"), + "setNewPin": + MessageLookupByLibrary.simpleMessage("Définir un nouveau code PIN"), "setPasswordTitle": MessageLookupByLibrary.simpleMessage("Définir le mot de passe"), "setRadius": MessageLookupByLibrary.simpleMessage("Définir le rayon"), "setupComplete": - MessageLookupByLibrary.simpleMessage("Configuration fini"), + MessageLookupByLibrary.simpleMessage("Configuration terminée"), "share": MessageLookupByLibrary.simpleMessage("Partager"), "shareALink": MessageLookupByLibrary.simpleMessage("Partager le lien"), "shareAlbumHint": MessageLookupByLibrary.simpleMessage( @@ -1324,20 +1446,20 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage( "Partagez un album maintenant"), "shareLink": MessageLookupByLibrary.simpleMessage("Partager le lien"), - "shareMyVerificationID": m51, + "shareMyVerificationID": m52, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Partager uniquement avec les personnes que vous voulez"), - "shareTextConfirmOthersVerificationID": m52, + "shareTextConfirmOthersVerificationID": m2, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( - "Téléchargez ente pour que nous puissions facilement partager des photos et des vidéos de qualité originale\n\nhttps://ente.io"), + "Téléchargez Ente pour que nous puissions facilement partager des photos et des vidéos de qualité originale\n\nhttps://ente.io"), "shareTextReferralCode": m53, "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( - "Partager avec des utilisateurs non-ente"), + "Partager avec des utilisateurs non-Ente"), "shareWithPeopleSectionTitle": m54, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage( "Partagez votre premier album"), "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( - "Créez des albums partagés et collaboratifs avec d\'autres utilisateurs de ente, y compris des utilisateurs sur des plans gratuits."), + "Créez des albums partagés et collaboratifs avec d\'autres utilisateurs de Ente, y compris des utilisateurs ayant des plans gratuits."), "sharedByMe": MessageLookupByLibrary.simpleMessage("Partagé par moi"), "sharedByYou": MessageLookupByLibrary.simpleMessage("Partagé par vous"), "sharedPhotoNotifications": @@ -1352,6 +1474,12 @@ class MessageLookup extends MessageLookupByLibrary { "sharing": MessageLookupByLibrary.simpleMessage("Partage..."), "showMemories": MessageLookupByLibrary.simpleMessage("Montrer les souvenirs"), + "signOutFromOtherDevices": MessageLookupByLibrary.simpleMessage( + "Se déconnecter d\'autres appareils"), + "signOutOtherBody": MessageLookupByLibrary.simpleMessage( + "Si vous pensez que quelqu\'un peut connaître votre mot de passe, vous pouvez forcer tous les autres appareils utilisant votre compte à se déconnecter."), + "signOutOtherDevices": MessageLookupByLibrary.simpleMessage( + "Déconnecter les autres appareils"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "J\'accepte les conditions d\'utilisation et la politique de confidentialité"), "singleFileDeleteFromDevice": m56, @@ -1363,7 +1491,7 @@ class MessageLookup extends MessageLookupByLibrary { "social": MessageLookupByLibrary.simpleMessage("Réseaux Sociaux"), "someItemsAreInBothEnteAndYourDevice": MessageLookupByLibrary.simpleMessage( - "Certains éléments sont à la fois dans ente et votre appareil."), + "Certains éléments sont à la fois sur Ente et votre appareil."), "someOfTheFilesYouAreTryingToDeleteAre": MessageLookupByLibrary.simpleMessage( "Certains des fichiers que vous essayez de supprimer ne sont disponibles que sur votre appareil et ne peuvent pas être récupérés s\'ils sont supprimés"), @@ -1395,6 +1523,11 @@ class MessageLookup extends MessageLookupByLibrary { "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ Succès"), "startBackup": MessageLookupByLibrary.simpleMessage("Démarrer la sauvegarde"), + "status": MessageLookupByLibrary.simpleMessage("État"), + "stopCastingBody": MessageLookupByLibrary.simpleMessage( + "Voulez-vous arrêter la diffusion ?"), + "stopCastingTitle": + MessageLookupByLibrary.simpleMessage("Arrêter la diffusion"), "storage": MessageLookupByLibrary.simpleMessage("Stockage"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Famille"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Vous"), @@ -1402,8 +1535,7 @@ class MessageLookup extends MessageLookupByLibrary { "storageLimitExceeded": MessageLookupByLibrary.simpleMessage("Limite de stockage atteinte"), "storageUsageInfo": m60, - "strongStrength": - MessageLookupByLibrary.simpleMessage("Securité forte"), + "strongStrength": MessageLookupByLibrary.simpleMessage("Forte"), "subAlreadyLinkedErrMessage": m61, "subWillBeCancelledOn": m62, "subscribe": MessageLookupByLibrary.simpleMessage("S\'abonner"), @@ -1431,7 +1563,8 @@ class MessageLookup extends MessageLookupByLibrary { "tapToCopy": MessageLookupByLibrary.simpleMessage("taper pour copier"), "tapToEnterCode": MessageLookupByLibrary.simpleMessage("Appuyez pour entrer le code"), - "tapToUnlock": MessageLookupByLibrary.simpleMessage("Tap to unlock"), + "tapToUnlock": + MessageLookupByLibrary.simpleMessage("Appuyer pour déverrouiller"), "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Il semble qu\'une erreur s\'est produite. Veuillez réessayer après un certain temps. Si l\'erreur persiste, veuillez contacter notre équipe d\'assistance."), "terminate": MessageLookupByLibrary.simpleMessage("Se déconnecter"), @@ -1478,24 +1611,24 @@ class MessageLookup extends MessageLookupByLibrary { "Cela vous déconnectera de cet appareil !"), "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( - "This will remove public links of all selected quick links."), + "Ceci supprimera les liens publics de tous les liens rapides sélectionnés."), "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": MessageLookupByLibrary.simpleMessage( - "To enable app lock, please setup device passcode or screen lock in your system settings."), + "Pour activer le verrouillage d\'application, veuillez configurer le code d\'accès de l\'appareil ou le verrouillage de l\'écran dans les paramètres de votre système."), "toHideAPhotoOrVideo": MessageLookupByLibrary.simpleMessage( "Cacher une photo ou une vidéo"), "toResetVerifyEmail": MessageLookupByLibrary.simpleMessage( "Pour réinitialiser votre mot de passe, veuillez d\'abord vérifier votre e-mail."), "todaysLogs": MessageLookupByLibrary.simpleMessage("Journaux du jour"), - "tooManyIncorrectAttempts": - MessageLookupByLibrary.simpleMessage("Too many incorrect attempts"), + "tooManyIncorrectAttempts": MessageLookupByLibrary.simpleMessage( + "Trop de tentatives incorrectes"), "total": MessageLookupByLibrary.simpleMessage("total"), "totalSize": MessageLookupByLibrary.simpleMessage("Taille totale"), "trash": MessageLookupByLibrary.simpleMessage("Corbeille"), "trashDaysLeft": m66, "tryAgain": MessageLookupByLibrary.simpleMessage("Réessayer"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( - "Activez la sauvegarde pour télécharger automatiquement les fichiers ajoutés à ce dossier de l\'appareil sur ente."), + "Activez la sauvegarde pour charger automatiquement sur Ente les fichiers ajoutés à ce dossier de l\'appareil."), "twitter": MessageLookupByLibrary.simpleMessage("Twitter"), "twoMonthsFreeOnYearlyPlans": MessageLookupByLibrary.simpleMessage( "2 mois gratuits sur les forfaits annuels"), @@ -1517,6 +1650,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Désarchiver l\'album"), "unarchiving": MessageLookupByLibrary.simpleMessage("Désarchivage en cours..."), + "unavailableReferralCode": MessageLookupByLibrary.simpleMessage( + "Désolé, ce code n\'est pas disponible."), "uncategorized": MessageLookupByLibrary.simpleMessage("Aucune catégorie"), "unhide": MessageLookupByLibrary.simpleMessage("Dévoiler"), @@ -1543,8 +1678,10 @@ class MessageLookup extends MessageLookupByLibrary { "Jusqu\'à 50% de réduction, jusqu\'au 4ème déc."), "usableReferralStorageInfo": MessageLookupByLibrary.simpleMessage( "Le stockage utilisable est limité par votre offre actuelle. Le stockage excédentaire deviendra automatiquement utilisable lorsque vous mettez à niveau votre offre."), + "useAsCover": + MessageLookupByLibrary.simpleMessage("Utiliser comme couverture"), "usePublicLinksForPeopleNotOnEnte": MessageLookupByLibrary.simpleMessage( - "Utiliser des liens publics pour les personnes qui ne sont pas sur ente"), + "Utiliser des liens publics pour les personnes qui ne sont pas sur Ente"), "useRecoveryKey": MessageLookupByLibrary.simpleMessage("Utiliser la clé de secours"), "useSelectedPhoto": MessageLookupByLibrary.simpleMessage( @@ -1561,12 +1698,15 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Vérifier l\'email"), "verifyEmailID": m68, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Vérifier"), + "verifyPasskey": + MessageLookupByLibrary.simpleMessage("Vérifier le code d\'accès"), "verifyPassword": MessageLookupByLibrary.simpleMessage("Vérifier le mot de passe"), "verifying": MessageLookupByLibrary.simpleMessage("Validation en cours..."), "verifyingRecoveryKey": MessageLookupByLibrary.simpleMessage( "Vérification de la clé de récupération..."), + "videoInfo": MessageLookupByLibrary.simpleMessage("Informations vidéo"), "videoSmallCase": MessageLookupByLibrary.simpleMessage("vidéo"), "videos": MessageLookupByLibrary.simpleMessage("Vidéos"), "viewActiveSessions": MessageLookupByLibrary.simpleMessage( @@ -1576,6 +1716,8 @@ class MessageLookup extends MessageLookupByLibrary { "viewAll": MessageLookupByLibrary.simpleMessage("Tout afficher"), "viewAllExifData": MessageLookupByLibrary.simpleMessage( "Visualiser toutes les données EXIF"), + "viewLargeFiles": + MessageLookupByLibrary.simpleMessage("Fichiers volumineux"), "viewLogs": MessageLookupByLibrary.simpleMessage("Afficher les journaux"), "viewRecoveryKey": @@ -1583,6 +1725,10 @@ class MessageLookup extends MessageLookupByLibrary { "viewer": MessageLookupByLibrary.simpleMessage("Observateur"), "visitWebToManage": MessageLookupByLibrary.simpleMessage( "Veuillez visiter web.ente.io pour gérer votre abonnement"), + "waitingForVerification": MessageLookupByLibrary.simpleMessage( + "En attente de vérification..."), + "waitingForWifi": MessageLookupByLibrary.simpleMessage( + "En attente de connexion Wi-Fi..."), "weAreOpenSource": MessageLookupByLibrary.simpleMessage("Nous sommes open source !"), "weDontSupportEditingPhotosAndAlbumsThatYouDont": @@ -1591,6 +1737,7 @@ class MessageLookup extends MessageLookupByLibrary { "weHaveSendEmailTo": m69, "weakStrength": MessageLookupByLibrary.simpleMessage("Securité Faible"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Bienvenue !"), + "whatsNew": MessageLookupByLibrary.simpleMessage("Nouveautés"), "yearly": MessageLookupByLibrary.simpleMessage("Annuel"), "yearsAgo": m70, "yes": MessageLookupByLibrary.simpleMessage("Oui"), diff --git a/mobile/lib/generated/intl/messages_gu.dart b/mobile/lib/generated/intl/messages_gu.dart new file mode 100644 index 0000000000..6c1d7e4d90 --- /dev/null +++ b/mobile/lib/generated/intl/messages_gu.dart @@ -0,0 +1,25 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a gu locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'gu'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => {}; +} diff --git a/mobile/lib/generated/intl/messages_he.dart b/mobile/lib/generated/intl/messages_he.dart new file mode 100644 index 0000000000..e27bbe712b --- /dev/null +++ b/mobile/lib/generated/intl/messages_he.dart @@ -0,0 +1,975 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a he locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'he'; + + static String m4(count) => + "${Intl.plural(count, one: 'הוסף פריט', two: 'הוסף פריטים', many: 'הוסף פריטים', other: 'הוסף פריטים')}"; + + static String m9(count) => + "${Intl.plural(count, zero: 'אין משתתפים', one: '1 משתתף', two: '${count} משתתפים', many: '${count} משתתפים', other: '${count} משתתפים')}"; + + static String m12(paymentProvider) => + "אנא בטל את המנוי הקיים מ-${paymentProvider} קודם"; + + static String m13(user) => + "${user} לא יוכל להוסיף עוד תמונות לאלבום זה\n\nהם עדיין יכולו להסיר תמונות קיימות שנוספו על ידיהם"; + + static String m14(isFamilyMember, storageAmountInGb) => + "${Intl.select(isFamilyMember, { + 'true': 'קיבלת ${storageAmountInGb} GB עד כה', + 'false': 'קיבלת ${storageAmountInGb} GB עד כה', + 'other': 'קיבלת ${storageAmountInGb} GB עד כה!', + })}"; + + static String m16(familyAdminEmail) => + "אנא צור קשר עם ${familyAdminEmail} על מנת לנהל את המנוי שלך"; + + static String m17(provider) => + "אנא צור איתנו קשר ב-support@ente.io על מנת לנהל את המנוי ${provider}."; + + static String m19(count) => + "${Intl.plural(count, one: 'מחק ${count} פריט', two: 'מחק ${count} פריטים', many: 'מחק ${count} פריטים', other: 'מחק ${count} פריטים')}"; + + static String m20(currentlyDeleting, totalCount) => + "מוחק ${currentlyDeleting} / ${totalCount}"; + + static String m21(albumName) => + "זה יסיר את הלינק הפומבי שדרכו ניתן לגשת ל\"${albumName}\"."; + + static String m22(supportEmail) => + "אנא תשלח דוא\"ל ל${supportEmail} מהכתובת דוא\"ל שנרשמת איתה"; + + static String m24(count, formattedSize) => + "${count} קבצים, כל אחד ${formattedSize}"; + + static String m26(email) => + "לא נמצא חשבון ente ל-${email}.\n\nשלח להם הזמנה על מנת לשתף תמונות."; + + static String m29(storageAmountInGB) => + "${storageAmountInGB} GB כל פעם שמישהו נרשם עבור תוכנית בתשלום ומחיל את הקוד שלך"; + + static String m30(endDate) => "ניסיון חינם בתוקף עד ל-${endDate}"; + + static String m35(count) => + "${Intl.plural(count, one: '${count} פריט', two: '${count} פריטים', many: '${count} פריטים', other: '${count} פריטים')}"; + + static String m36(expiryTime) => "תוקף הקישור יפוג ב-${expiryTime}"; + + static String m0(count, formattedCount) => + "${Intl.plural(count, one: '${formattedCount} זכרון', two: '${formattedCount} זכרונות', many: '${formattedCount} זכרונות', other: '${formattedCount} זכרונות')}"; + + static String m37(count) => + "${Intl.plural(count, one: 'הזז פריט', two: 'הזז פריטים', many: 'הזז פריטים', other: 'הזז פריטים')}"; + + static String m41(passwordStrengthValue) => + "חוזק הסיסמא: ${passwordStrengthValue}"; + + static String m42(providerName) => + "אנא דבר עם התמיכה של ${providerName} אם אתה חוייבת"; + + static String m46(storeName) => "דרג אותנו ב-${storeName}"; + + static String m47(storageInGB) => "3. שניכים מקבלים ${storageInGB} GB* בחינם"; + + static String m48(userEmail) => + "${userEmail} יוסר מהאלבום המשותף הזה\n\nגם תמונות שנוספו על ידיהם יוסרו מהאלבום"; + + static String m1(count) => "${count} נבחרו"; + + static String m51(count, yourCount) => "${count} נבחרו (${yourCount} שלך)"; + + static String m52(verificationID) => + "הנה מזהה האימות שלי: ${verificationID} עבור ente.io."; + + static String m2(verificationID) => + "היי, תוכל לוודא שזה מזהה האימות שלך של ente.io: ${verificationID}"; + + static String m54(numberOfPeople) => + "${Intl.plural(numberOfPeople, zero: 'שתף עם אנשים ספציפיים', one: 'שותף עם איש 1', two: 'שותף עם ${numberOfPeople} אנשים', many: 'שותף עם ${numberOfPeople} אנשים', other: 'שותף עם ${numberOfPeople} אנשים')}"; + + static String m55(emailIDs) => "הושתף ע\"י ${emailIDs}"; + + static String m56(fileType) => "${fileType} יימחק מהמכשיר שלך."; + + static String m59(storageAmountInGB) => "${storageAmountInGB} GB"; + + static String m62(endDate) => "המנוי שלך יבוטל ב-${endDate}"; + + static String m63(completed, total) => "${completed}/${total} זכרונות נשמרו"; + + static String m64(storageAmountInGB) => "הם גם יקבלו ${storageAmountInGB} GB"; + + static String m65(email) => "זה מזהה האימות של ${email}"; + + static String m68(email) => "אמת ${email}"; + + static String m69(email) => "שלחנו דוא\"ל ל${email}"; + + static String m70(count) => + "${Intl.plural(count, one: 'לפני ${count} שנה', two: 'לפני ${count} שנים', many: 'לפני ${count} שנים', other: 'לפני ${count} שנים')}"; + + static String m71(storageSaved) => "הצלחת לפנות ${storageSaved}!"; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "about": MessageLookupByLibrary.simpleMessage("אודות"), + "account": MessageLookupByLibrary.simpleMessage("חשבון"), + "accountWelcomeBack": + MessageLookupByLibrary.simpleMessage("ברוך שובך!"), + "ackPasswordLostWarning": MessageLookupByLibrary.simpleMessage( + "אני מבין שאם אאבד את הסיסמא, אני עלול לאבד את המידע שלי מכיוון שהמידע שלי מוצפן מקצה אל קצה."), + "activeSessions": + MessageLookupByLibrary.simpleMessage("חיבורים פעילים"), + "addANewEmail": MessageLookupByLibrary.simpleMessage("הוסף דוא\"ל חדש"), + "addCollaborator": + MessageLookupByLibrary.simpleMessage("הוסף משתף פעולה"), + "addItem": m4, + "addLocationButton": MessageLookupByLibrary.simpleMessage("הוסף"), + "addMore": MessageLookupByLibrary.simpleMessage("הוסף עוד"), + "addPhotos": MessageLookupByLibrary.simpleMessage("הוסף תמונות"), + "addToAlbum": MessageLookupByLibrary.simpleMessage("הוסף לאלבום"), + "addViewer": MessageLookupByLibrary.simpleMessage("הוסף צופה"), + "addedAs": MessageLookupByLibrary.simpleMessage("הוסף בתור"), + "addingToFavorites": + MessageLookupByLibrary.simpleMessage("מוסיף למועדפים..."), + "advanced": MessageLookupByLibrary.simpleMessage("מתקדם"), + "advancedSettings": MessageLookupByLibrary.simpleMessage("מתקדם"), + "after1Day": MessageLookupByLibrary.simpleMessage("אחרי יום 1"), + "after1Hour": MessageLookupByLibrary.simpleMessage("אחרי שעה 1"), + "after1Month": MessageLookupByLibrary.simpleMessage("אחרי חודש 1"), + "after1Week": MessageLookupByLibrary.simpleMessage("אחרי שבוע 1"), + "after1Year": MessageLookupByLibrary.simpleMessage("אחרי שנה 1"), + "albumOwner": MessageLookupByLibrary.simpleMessage("בעלים"), + "albumParticipantsCount": m9, + "albumTitle": MessageLookupByLibrary.simpleMessage("כותרת האלבום"), + "albumUpdated": MessageLookupByLibrary.simpleMessage("האלבום עודכן"), + "albums": MessageLookupByLibrary.simpleMessage("אלבומים"), + "allClear": MessageLookupByLibrary.simpleMessage("✨ הכל נוקה"), + "allMemoriesPreserved": + MessageLookupByLibrary.simpleMessage("כל הזכרונות נשמרו"), + "allowAddPhotosDescription": MessageLookupByLibrary.simpleMessage( + "בנוסף אפשר לאנשים עם הלינק להוסיף תמונות לאלבום המשותף."), + "allowAddingPhotos": + MessageLookupByLibrary.simpleMessage("אפשר הוספת תמונות"), + "allowDownloads": MessageLookupByLibrary.simpleMessage("אפשר הורדות"), + "allowPeopleToAddPhotos": + MessageLookupByLibrary.simpleMessage("תן לאנשים להוסיף תמונות"), + "androidBiometricSuccess": + MessageLookupByLibrary.simpleMessage("הצלחה"), + "androidCancelButton": MessageLookupByLibrary.simpleMessage("בטל"), + "androidIosWebDesktop": MessageLookupByLibrary.simpleMessage( + "Android, iOS, דפדפן, שולחן עבודה"), + "appleId": MessageLookupByLibrary.simpleMessage("Apple ID"), + "apply": MessageLookupByLibrary.simpleMessage("החל"), + "applyCodeTitle": MessageLookupByLibrary.simpleMessage("החל קוד"), + "appstoreSubscription": + MessageLookupByLibrary.simpleMessage("מנוי AppStore"), + "archive": MessageLookupByLibrary.simpleMessage("שמירה בארכיון"), + "areYouSureThatYouWantToLeaveTheFamily": + MessageLookupByLibrary.simpleMessage( + "אתה בטוח שאתה רוצה לעזוב את התוכנית המשפתחית?"), + "areYouSureYouWantToCancel": + MessageLookupByLibrary.simpleMessage("אתה בטוח שאתה רוצה לבטל?"), + "areYouSureYouWantToChangeYourPlan": + MessageLookupByLibrary.simpleMessage( + "אתה בטוח שאתה רוצה לשנות את התוכנית שלך?"), + "areYouSureYouWantToExit": + MessageLookupByLibrary.simpleMessage("האם אתה בטוח שברצונך לצאת?"), + "areYouSureYouWantToLogout": + MessageLookupByLibrary.simpleMessage("אתה בטוח שאתה רוצה להתנתק?"), + "areYouSureYouWantToRenew": + MessageLookupByLibrary.simpleMessage("אתה בטוח שאתה רוצה לחדש?"), + "askCancelReason": MessageLookupByLibrary.simpleMessage( + "המנוי שלך בוטל. תרצה לשתף את הסיבה?"), + "askDeleteReason": MessageLookupByLibrary.simpleMessage( + "מה הסיבה העיקרית שבגללה אתה מוחק את החשבון שלך?"), + "atAFalloutShelter": + MessageLookupByLibrary.simpleMessage("במקלט גרעיני"), + "authToChangeEmailVerificationSetting": + MessageLookupByLibrary.simpleMessage( + "אנא התאמת על מנת לשנות את הדוא\"ל שלך"), + "authToChangeLockscreenSetting": MessageLookupByLibrary.simpleMessage( + "אנא התאמת כדי לשנות את הגדרות מסך הנעילה"), + "authToChangeYourEmail": MessageLookupByLibrary.simpleMessage( + "אנא אנא התאמת על מנת לשנות את הדוא\"ל שלך"), + "authToChangeYourPassword": MessageLookupByLibrary.simpleMessage( + "אנא התאמת על מנת לשנות את הסיסמא שלך"), + "authToConfigureTwofactorAuthentication": + MessageLookupByLibrary.simpleMessage( + "אנא התאמת כדי להגדיר את האימות הדו-גורמי"), + "authToInitiateAccountDeletion": MessageLookupByLibrary.simpleMessage( + "אנא התאמת על מנת להתחיל את מחיקת החשבון שלך"), + "authToViewYourActiveSessions": MessageLookupByLibrary.simpleMessage( + "אנא התאמת על מנת לראות את החיבורים הפעילים שלך"), + "authToViewYourHiddenFiles": MessageLookupByLibrary.simpleMessage( + "אנא התאמת על מנת לראות את הקבצים החבויים שלך"), + "authToViewYourMemories": MessageLookupByLibrary.simpleMessage( + "אנא אמת על מנת לצפות בזכרונות שלך"), + "authToViewYourRecoveryKey": MessageLookupByLibrary.simpleMessage( + "אנא התאמת על מנת לראות את מפתח השחזור שלך"), + "available": MessageLookupByLibrary.simpleMessage("זמין"), + "backedUpFolders": MessageLookupByLibrary.simpleMessage("תיקיות שגובו"), + "backup": MessageLookupByLibrary.simpleMessage("גיבוי"), + "backupFailed": MessageLookupByLibrary.simpleMessage("הגיבוי נכשל"), + "backupOverMobileData": + MessageLookupByLibrary.simpleMessage("גבה על רשת סלולרית"), + "backupSettings": MessageLookupByLibrary.simpleMessage("הגדרות גיבוי"), + "backupVideos": MessageLookupByLibrary.simpleMessage("גבה סרטונים"), + "blog": MessageLookupByLibrary.simpleMessage("בלוג"), + "cachedData": MessageLookupByLibrary.simpleMessage("נתונים מוטמנים"), + "canNotUploadToAlbumsOwnedByOthers": + MessageLookupByLibrary.simpleMessage( + "לא ניתן להעלות לאלבומים שבבעלות אחרים"), + "canOnlyCreateLinkForFilesOwnedByYou": + MessageLookupByLibrary.simpleMessage( + "ניתן אך ורק ליצור קישור לקבצים שאתה בבעולתם"), + "canOnlyRemoveFilesOwnedByYou": MessageLookupByLibrary.simpleMessage( + "יכול להסיר רק קבצים שבבעלותך"), + "cancel": MessageLookupByLibrary.simpleMessage("בטל"), + "cancelOtherSubscription": m12, + "cancelSubscription": MessageLookupByLibrary.simpleMessage("בטל מנוי"), + "cannotAddMorePhotosAfterBecomingViewer": m13, + "cannotDeleteSharedFiles": MessageLookupByLibrary.simpleMessage( + "לא ניתן למחוק את הקבצים המשותפים"), + "changeEmail": MessageLookupByLibrary.simpleMessage("שנה דוא\"ל"), + "changePassword": MessageLookupByLibrary.simpleMessage("שנה סיסמה"), + "changePasswordTitle": + MessageLookupByLibrary.simpleMessage("שנה סיסמה"), + "changePermissions": MessageLookupByLibrary.simpleMessage("שנה הרשאה?"), + "checkForUpdates": MessageLookupByLibrary.simpleMessage("בדוק עדכונים"), + "checkInboxAndSpamFolder": MessageLookupByLibrary.simpleMessage( + "אנא בדוק את תיבת הדואר שלך (והספאם) כדי להשלים את האימות"), + "checking": MessageLookupByLibrary.simpleMessage("בודק..."), + "claimFreeStorage": + MessageLookupByLibrary.simpleMessage("תבע מקום אחסון בחינם"), + "claimMore": MessageLookupByLibrary.simpleMessage("תבע עוד!"), + "claimed": MessageLookupByLibrary.simpleMessage("נתבע"), + "claimedStorageSoFar": m14, + "click": MessageLookupByLibrary.simpleMessage("• לחץ"), + "close": MessageLookupByLibrary.simpleMessage("סגור"), + "clubByCaptureTime": + MessageLookupByLibrary.simpleMessage("קבץ לפי זמן הצילום"), + "clubByFileName": + MessageLookupByLibrary.simpleMessage("קבץ לפי שם הקובץ"), + "codeAppliedPageTitle": + MessageLookupByLibrary.simpleMessage("הקוד הוחל"), + "codeCopiedToClipboard": + MessageLookupByLibrary.simpleMessage("הקוד הועתק ללוח"), + "codeUsedByYou": + MessageLookupByLibrary.simpleMessage("הקוד שומש על ידיך"), + "collabLinkSectionDescription": MessageLookupByLibrary.simpleMessage( + "צור קישור על מנת לאפשר לאנשים להוסיף ולצפות בתמונות באלבום ששיתפת בלי צורך באפליקציית ente או חשבון. נהדר לאיסוף תמונות של אירועים."), + "collaborativeLink": + MessageLookupByLibrary.simpleMessage("קישור לשיתוף פעולה"), + "collaborator": MessageLookupByLibrary.simpleMessage("משתף פעולה"), + "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": + MessageLookupByLibrary.simpleMessage( + "משתפי פעולה יכולים להוסיף תמונות וסרטונים לאלבום המשותף."), + "collageLayout": MessageLookupByLibrary.simpleMessage("פריסה"), + "collageSaved": + MessageLookupByLibrary.simpleMessage("הקולז נשמר לגלריה"), + "collectEventPhotos": + MessageLookupByLibrary.simpleMessage("אסף תמונות מאירוע"), + "collectPhotos": MessageLookupByLibrary.simpleMessage("אסוף תמונות"), + "color": MessageLookupByLibrary.simpleMessage("צבע"), + "confirm": MessageLookupByLibrary.simpleMessage("אשר"), + "confirm2FADisable": MessageLookupByLibrary.simpleMessage( + "האם אתה בטוח שאתה רוצה להשבית את האימות הדו-גורמי?"), + "confirmAccountDeletion": + MessageLookupByLibrary.simpleMessage("אשר את מחיקת החשבון"), + "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( + "כן, אני רוצה למחוק לצמיתות את החשבון הזה וכל המידע שלו."), + "confirmPassword": MessageLookupByLibrary.simpleMessage("אמת סיסמא"), + "confirmPlanChange": + MessageLookupByLibrary.simpleMessage("אשר שינוי תוכנית"), + "confirmRecoveryKey": + MessageLookupByLibrary.simpleMessage("אמת את מפתח השחזור"), + "confirmYourRecoveryKey": + MessageLookupByLibrary.simpleMessage("אמת את מפתח השחזור"), + "contactFamilyAdmin": m16, + "contactSupport": + MessageLookupByLibrary.simpleMessage("צור קשר עם התמיכה"), + "contactToManageSubscription": m17, + "continueLabel": MessageLookupByLibrary.simpleMessage("המשך"), + "continueOnFreeTrial": + MessageLookupByLibrary.simpleMessage("המשך עם ניסיון חינמי"), + "copyLink": MessageLookupByLibrary.simpleMessage("העתק קישור"), + "copypasteThisCodentoYourAuthenticatorApp": + MessageLookupByLibrary.simpleMessage( + "תעתיק ותדביק את הקוד הזה\nלאפליקציית האימות שלך"), + "couldNotBackUpTryLater": MessageLookupByLibrary.simpleMessage( + "לא יכולנו לגבות את המידע שלך.\nאנא נסה שוב מאוחר יותר."), + "couldNotUpdateSubscription": + MessageLookupByLibrary.simpleMessage("לא ניתן לעדכן את המנוי"), + "count": MessageLookupByLibrary.simpleMessage("כמות"), + "create": MessageLookupByLibrary.simpleMessage("צור"), + "createAccount": MessageLookupByLibrary.simpleMessage("צור חשבון"), + "createAlbumActionHint": MessageLookupByLibrary.simpleMessage( + "לחץ לחיצה ארוכה על מנת לבחור תמונות ולחץ על + על מנת ליצור אלבום"), + "createCollage": MessageLookupByLibrary.simpleMessage("צור קולז"), + "createNewAccount": + MessageLookupByLibrary.simpleMessage("צור חשבון חדש"), + "createOrSelectAlbum": + MessageLookupByLibrary.simpleMessage("צור או בחר אלבום"), + "createPublicLink": + MessageLookupByLibrary.simpleMessage("צור קישור ציבורי"), + "creatingLink": MessageLookupByLibrary.simpleMessage("יוצר קישור..."), + "criticalUpdateAvailable": + MessageLookupByLibrary.simpleMessage("עדכון חשוב זמין"), + "currentUsageIs": MessageLookupByLibrary.simpleMessage( + "השימוש במקום האחסון כרגע הוא "), + "custom": MessageLookupByLibrary.simpleMessage("מותאם אישית"), + "darkTheme": MessageLookupByLibrary.simpleMessage("כהה"), + "dayToday": MessageLookupByLibrary.simpleMessage("היום"), + "dayYesterday": MessageLookupByLibrary.simpleMessage("אתמול"), + "decrypting": MessageLookupByLibrary.simpleMessage("מפענח..."), + "decryptingVideo": + MessageLookupByLibrary.simpleMessage("מפענח את הסרטון..."), + "deduplicateFiles": + MessageLookupByLibrary.simpleMessage("הסר קבצים כפולים"), + "delete": MessageLookupByLibrary.simpleMessage("מחק"), + "deleteAccount": MessageLookupByLibrary.simpleMessage("מחק חשבון"), + "deleteAccountFeedbackPrompt": MessageLookupByLibrary.simpleMessage( + "אנחנו מצטערים לראות שאתה עוזב. אנא תחלוק את המשוב שלך כדי לעזור לנו להשתפר."), + "deleteAccountPermanentlyButton": + MessageLookupByLibrary.simpleMessage("מחק את החשבון לצמיתות"), + "deleteAlbum": MessageLookupByLibrary.simpleMessage("מחק אלבום"), + "deleteAlbumDialog": MessageLookupByLibrary.simpleMessage( + "גם להסיר תמונות (וסרטונים) שנמצאים באלבום הזה מכל שאר האלבומים שהם שייכים אליהם?"), + "deleteAlbumsDialogBody": MessageLookupByLibrary.simpleMessage( + "זה ימחק את כל האלבומים הריקים. זה שימושי כשאתה רוצה להפחית את כמות האי סדר ברשימת האלבומים שלך."), + "deleteAll": MessageLookupByLibrary.simpleMessage("מחק הכל"), + "deleteEmailRequest": MessageLookupByLibrary.simpleMessage( + "אנא תשלח דוא\"ל לaccount-deletion@ente.io מהכתובת דוא\"ל שנרשמת איתה."), + "deleteEmptyAlbums": + MessageLookupByLibrary.simpleMessage("למחוק אלבומים ריקים"), + "deleteEmptyAlbumsWithQuestionMark": + MessageLookupByLibrary.simpleMessage("למחוק אלבומים ריקים?"), + "deleteFromBoth": MessageLookupByLibrary.simpleMessage("מחק משניהם"), + "deleteFromDevice": MessageLookupByLibrary.simpleMessage("מחק מהמכשיר"), + "deleteItemCount": m19, + "deletePhotos": MessageLookupByLibrary.simpleMessage("מחק תמונות"), + "deleteProgress": m20, + "deleteReason1": + MessageLookupByLibrary.simpleMessage("חסר מאפיין מרכזי שאני צריך"), + "deleteReason2": MessageLookupByLibrary.simpleMessage( + "היישומון או מאפיין מסוים לא מתנהג כמו שאני חושב שהוא צריך"), + "deleteReason3": MessageLookupByLibrary.simpleMessage( + "מצאתי שירות אחר שאני יותר מחבב"), + "deleteReason4": + MessageLookupByLibrary.simpleMessage("הסיבה שלי לא כלולה"), + "deleteRequestSLAText": MessageLookupByLibrary.simpleMessage( + "הבקשה שלך תועבד תוך 72 שעות."), + "deleteSharedAlbum": + MessageLookupByLibrary.simpleMessage("מחק את האלבום המשותף?"), + "deleteSharedAlbumDialogBody": MessageLookupByLibrary.simpleMessage( + "האלבום הזה יימחק עבור כולם\n\nאתה תאבד גישה לתמונות משותפות באלבום הזה שבבעלות של אחרים"), + "deselectAll": MessageLookupByLibrary.simpleMessage("בטל בחירה של הכל"), + "designedToOutlive": + MessageLookupByLibrary.simpleMessage("עוצב על מנת לשרוד"), + "details": MessageLookupByLibrary.simpleMessage("פרטים"), + "disableAutoLock": + MessageLookupByLibrary.simpleMessage("השבת נעילה אוטומטית"), + "disableDownloadWarningBody": MessageLookupByLibrary.simpleMessage( + "צופים יכולים עדיין לקחת צילומי מסך או לשמור עותק של התמונות שלך בעזרת כלים חיצוניים"), + "disableDownloadWarningTitle": + MessageLookupByLibrary.simpleMessage("שים לב"), + "disableLinkMessage": m21, + "disableTwofactor": + MessageLookupByLibrary.simpleMessage("השבת דו-גורמי"), + "discord": MessageLookupByLibrary.simpleMessage("Discord"), + "dismiss": MessageLookupByLibrary.simpleMessage("התעלם"), + "distanceInKMUnit": MessageLookupByLibrary.simpleMessage("ק\"מ"), + "doThisLater": MessageLookupByLibrary.simpleMessage("מאוחר יותר"), + "done": MessageLookupByLibrary.simpleMessage("בוצע"), + "download": MessageLookupByLibrary.simpleMessage("הורד"), + "downloadFailed": MessageLookupByLibrary.simpleMessage("ההורדה נכשלה"), + "downloading": MessageLookupByLibrary.simpleMessage("מוריד..."), + "dropSupportEmail": m22, + "duplicateItemsGroup": m24, + "edit": MessageLookupByLibrary.simpleMessage("ערוך"), + "eligible": MessageLookupByLibrary.simpleMessage("זכאי"), + "email": MessageLookupByLibrary.simpleMessage("דוא\"ל"), + "emailNoEnteAccount": m26, + "emailVerificationToggle": + MessageLookupByLibrary.simpleMessage("אימות מייל"), + "empty": MessageLookupByLibrary.simpleMessage("ריק"), + "encryption": MessageLookupByLibrary.simpleMessage("הצפנה"), + "encryptionKeys": MessageLookupByLibrary.simpleMessage("מפתחות ההצפנה"), + "endtoendEncryptedByDefault": MessageLookupByLibrary.simpleMessage( + "מוצפן מקצה אל קצה כברירת מחדל"), + "entePhotosPerm": MessageLookupByLibrary.simpleMessage( + "Ente צריך הרשאות על מנת לשמור את התמונות שלך"), + "enteSubscriptionShareWithFamily": MessageLookupByLibrary.simpleMessage( + "אפשר להוסיף גם את המשפחה שלך לתוכנית."), + "enterAlbumName": MessageLookupByLibrary.simpleMessage("הזן שם אלבום"), + "enterCode": MessageLookupByLibrary.simpleMessage("הזן קוד"), + "enterCodeDescription": MessageLookupByLibrary.simpleMessage( + "הכנס את הקוד שנמסר לך מחברך בשביל לקבל מקום אחסון בחינם עבורך ועבורו"), + "enterEmail": MessageLookupByLibrary.simpleMessage("הזן דוא\"ל"), + "enterNewPasswordToEncrypt": MessageLookupByLibrary.simpleMessage( + "הזן סיסמא חדשה שנוכל להשתמש בה כדי להצפין את המידע שלך"), + "enterPassword": MessageLookupByLibrary.simpleMessage("הזן את הסיסמה"), + "enterPasswordToEncrypt": MessageLookupByLibrary.simpleMessage( + "הזן סיסמא כדי שנוכל לפענח את המידע שלך"), + "enterReferralCode": + MessageLookupByLibrary.simpleMessage("הזן קוד הפניה"), + "enterThe6digitCodeFromnyourAuthenticatorApp": + MessageLookupByLibrary.simpleMessage( + "הכנס את הקוד בעל 6 ספרות מתוך\nאפליקציית האימות שלך"), + "enterValidEmail": MessageLookupByLibrary.simpleMessage( + "אנא הכנס כתובת דוא\"ל חוקית."), + "enterYourEmailAddress": + MessageLookupByLibrary.simpleMessage("הכנס את כתובת הדוא״ל שלך"), + "enterYourPassword": MessageLookupByLibrary.simpleMessage("הכנס סיסמא"), + "enterYourRecoveryKey": + MessageLookupByLibrary.simpleMessage("הזן את מפתח השחזור שלך"), + "error": MessageLookupByLibrary.simpleMessage("שגיאה"), + "everywhere": MessageLookupByLibrary.simpleMessage("בכל מקום"), + "exif": MessageLookupByLibrary.simpleMessage("EXIF"), + "existingUser": MessageLookupByLibrary.simpleMessage("משתמש קיים"), + "expiredLinkInfo": MessageLookupByLibrary.simpleMessage( + "פג תוקף הקישור. אנא בחר בתאריך תפוגה חדש או השבת את תאריך התפוגה של הקישור."), + "exportLogs": MessageLookupByLibrary.simpleMessage("ייצוא לוגים"), + "exportYourData": + MessageLookupByLibrary.simpleMessage("ייצוא הנתונים שלך"), + "failedToApplyCode": + MessageLookupByLibrary.simpleMessage("נכשל בהחלת הקוד"), + "failedToCancel": MessageLookupByLibrary.simpleMessage("הביטול נכשל"), + "failedToFetchReferralDetails": MessageLookupByLibrary.simpleMessage( + "אחזור פרטי ההפניה נכשל. אנא נסה שוב מאוחר יותר."), + "failedToLoadAlbums": + MessageLookupByLibrary.simpleMessage("נכשל בטעינת האלבומים"), + "failedToRenew": MessageLookupByLibrary.simpleMessage("החידוש נכשל"), + "failedToVerifyPaymentStatus": + MessageLookupByLibrary.simpleMessage("נכשל באימות סטטוס התשלום"), + "familyPlanPortalTitle": MessageLookupByLibrary.simpleMessage("משפחה"), + "familyPlans": MessageLookupByLibrary.simpleMessage("תוכניות משפחה"), + "faq": MessageLookupByLibrary.simpleMessage("שאלות נפוצות"), + "faqs": MessageLookupByLibrary.simpleMessage("שאלות נפוצות"), + "favorite": MessageLookupByLibrary.simpleMessage("מועדף"), + "feedback": MessageLookupByLibrary.simpleMessage("משוב"), + "fileFailedToSaveToGallery": + MessageLookupByLibrary.simpleMessage("נכשל בעת שמירת הקובץ לגלריה"), + "fileSavedToGallery": + MessageLookupByLibrary.simpleMessage("הקובץ נשמר לגלריה"), + "flip": MessageLookupByLibrary.simpleMessage("הפוך"), + "forYourMemories": + MessageLookupByLibrary.simpleMessage("עבור הזכורונות שלך"), + "forgotPassword": MessageLookupByLibrary.simpleMessage("שכחתי סיסמה"), + "freeStorageClaimed": + MessageLookupByLibrary.simpleMessage("מקום אחסון בחינם נתבע"), + "freeStorageOnReferralSuccess": m29, + "freeStorageUsable": + MessageLookupByLibrary.simpleMessage("מקום אחסון שמיש"), + "freeTrial": MessageLookupByLibrary.simpleMessage("ניסיון חינמי"), + "freeTrialValidTill": m30, + "freeUpDeviceSpace": + MessageLookupByLibrary.simpleMessage("פנה אחסון במכשיר"), + "freeUpSpace": MessageLookupByLibrary.simpleMessage("פנה מקום"), + "general": MessageLookupByLibrary.simpleMessage("כללי"), + "generatingEncryptionKeys": + MessageLookupByLibrary.simpleMessage("יוצר מפתחות הצפנה..."), + "googlePlayId": MessageLookupByLibrary.simpleMessage("Google Play ID"), + "grantFullAccessPrompt": MessageLookupByLibrary.simpleMessage( + "נא לתת גישה לכל התמונות בתוך ההגדרות של הטלפון"), + "grantPermission": MessageLookupByLibrary.simpleMessage("הענק הרשאה"), + "hidden": MessageLookupByLibrary.simpleMessage("מוסתר"), + "hide": MessageLookupByLibrary.simpleMessage("הסתר"), + "hiding": MessageLookupByLibrary.simpleMessage("מחביא..."), + "howItWorks": MessageLookupByLibrary.simpleMessage("איך זה עובד"), + "howToViewShareeVerificationID": MessageLookupByLibrary.simpleMessage( + "אנא בקש מהם ללחוץ לחיצה ארוכה על הכתובת אימייל שלהם בעמוד ההגדרות, וודא שהמזההים בשני המכשירים תואמים."), + "iOSOkButton": MessageLookupByLibrary.simpleMessage("אישור"), + "ignoreUpdate": MessageLookupByLibrary.simpleMessage("התעלם"), + "importing": MessageLookupByLibrary.simpleMessage("מייבא...."), + "incorrectPasswordTitle": + MessageLookupByLibrary.simpleMessage("סיסמא לא נכונה"), + "incorrectRecoveryKeyBody": + MessageLookupByLibrary.simpleMessage("המפתח שחזור שהזנת שגוי"), + "incorrectRecoveryKeyTitle": + MessageLookupByLibrary.simpleMessage("מפתח שחזור שגוי"), + "insecureDevice": + MessageLookupByLibrary.simpleMessage("מכשיר בלתי מאובטח"), + "installManually": + MessageLookupByLibrary.simpleMessage("התקן באופן ידני"), + "invalidEmailAddress": + MessageLookupByLibrary.simpleMessage("כתובת דוא״ל לא תקינה"), + "invalidKey": MessageLookupByLibrary.simpleMessage("מפתח לא חוקי"), + "invalidRecoveryKey": MessageLookupByLibrary.simpleMessage( + "מפתח השחזור שהזמנת אינו תקין. אנא וודא שהוא מכיל 24 מילים, ותבדוק את האיות של כל אחת.\n\nאם הכנסת קוד שחזור ישן, וודא שהוא בעל 64 אותיות, ותבדוק כל אחת מהן."), + "invite": MessageLookupByLibrary.simpleMessage("הזמן"), + "inviteYourFriends": + MessageLookupByLibrary.simpleMessage("הזמן את חברייך"), + "itemCount": m35, + "itemsWillBeRemovedFromAlbum": MessageLookupByLibrary.simpleMessage( + "הפריטים שנבחרו יוסרו מהאלבום הזה"), + "keepPhotos": MessageLookupByLibrary.simpleMessage("השאר תמונות"), + "kiloMeterUnit": MessageLookupByLibrary.simpleMessage("ק\"מ"), + "kindlyHelpUsWithThisInformation": + MessageLookupByLibrary.simpleMessage("אנא עזור לנו עם המידע הזה"), + "language": MessageLookupByLibrary.simpleMessage("שפה"), + "lastUpdated": MessageLookupByLibrary.simpleMessage("עדכון אחרון"), + "leave": MessageLookupByLibrary.simpleMessage("עזוב"), + "leaveAlbum": MessageLookupByLibrary.simpleMessage("צא מהאלבום"), + "leaveFamily": MessageLookupByLibrary.simpleMessage("עזוב משפחה"), + "leaveSharedAlbum": + MessageLookupByLibrary.simpleMessage("לעזוב את האלבום המשותף?"), + "light": MessageLookupByLibrary.simpleMessage("אור"), + "lightTheme": MessageLookupByLibrary.simpleMessage("בהיר"), + "linkCopiedToClipboard": + MessageLookupByLibrary.simpleMessage("הקישור הועתק ללוח"), + "linkDeviceLimit": + MessageLookupByLibrary.simpleMessage("מגבלת כמות מכשירים"), + "linkEnabled": MessageLookupByLibrary.simpleMessage("מאופשר"), + "linkExpired": MessageLookupByLibrary.simpleMessage("פג תוקף"), + "linkExpiresOn": m36, + "linkExpiry": MessageLookupByLibrary.simpleMessage("תאריך תפוגה ללינק"), + "linkHasExpired": + MessageLookupByLibrary.simpleMessage("הקישור פג תוקף"), + "linkNeverExpires": MessageLookupByLibrary.simpleMessage("לעולם לא"), + "location": MessageLookupByLibrary.simpleMessage("מקום"), + "lockButtonLabel": MessageLookupByLibrary.simpleMessage("נעל"), + "lockscreen": MessageLookupByLibrary.simpleMessage("מסך נעילה"), + "logInLabel": MessageLookupByLibrary.simpleMessage("התחבר"), + "loggingOut": MessageLookupByLibrary.simpleMessage("מתנתק..."), + "loginTerms": MessageLookupByLibrary.simpleMessage( + "על ידי לחיצה על התחברות, אני מסכים לתנאי שירות ולמדיניות הפרטיות"), + "logout": MessageLookupByLibrary.simpleMessage("התנתק"), + "longpressOnAnItemToViewInFullscreen": + MessageLookupByLibrary.simpleMessage( + "לחץ לחיצה ארוכה על פריט על מנת לראות אותו במסך מלא"), + "lostDevice": MessageLookupByLibrary.simpleMessage("איבדת את המכשיר?"), + "manage": MessageLookupByLibrary.simpleMessage("נהל"), + "manageDeviceStorage": + MessageLookupByLibrary.simpleMessage("נהל את מקום אחסון המכשיר"), + "manageFamily": MessageLookupByLibrary.simpleMessage("נהל משפחה"), + "manageLink": MessageLookupByLibrary.simpleMessage("ניהול קישור"), + "manageParticipants": MessageLookupByLibrary.simpleMessage("נהל"), + "manageSubscription": MessageLookupByLibrary.simpleMessage("נהל מנוי"), + "map": MessageLookupByLibrary.simpleMessage("מפה"), + "maps": MessageLookupByLibrary.simpleMessage("מפות"), + "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), + "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), + "memoryCount": m0, + "merchandise": MessageLookupByLibrary.simpleMessage("סחורה"), + "mobileWebDesktop": + MessageLookupByLibrary.simpleMessage("פלאפון, דפדפן, שולחן עבודה"), + "moderateStrength": MessageLookupByLibrary.simpleMessage("מתונה"), + "monthly": MessageLookupByLibrary.simpleMessage("חודשי"), + "moveItem": m37, + "moveToAlbum": MessageLookupByLibrary.simpleMessage("הזז לאלבום"), + "movedToTrash": MessageLookupByLibrary.simpleMessage("הועבר לאשפה"), + "movingFilesToAlbum": + MessageLookupByLibrary.simpleMessage("מעביר קבצים לאלבום..."), + "name": MessageLookupByLibrary.simpleMessage("שם"), + "never": MessageLookupByLibrary.simpleMessage("לעולם לא"), + "newAlbum": MessageLookupByLibrary.simpleMessage("אלבום חדש"), + "newest": MessageLookupByLibrary.simpleMessage("החדש ביותר"), + "no": MessageLookupByLibrary.simpleMessage("לא"), + "noDeviceLimit": MessageLookupByLibrary.simpleMessage("אין"), + "noDeviceThatCanBeDeleted": MessageLookupByLibrary.simpleMessage( + "אין לך קבצים במכשיר הזה שניתן למחוק אותם"), + "noDuplicates": MessageLookupByLibrary.simpleMessage("✨ אין כפילויות"), + "noPhotosAreBeingBackedUpRightNow": + MessageLookupByLibrary.simpleMessage( + "אף תמונה אינה נמצאת בתהליך גיבוי כרגע"), + "noRecoveryKey": + MessageLookupByLibrary.simpleMessage("אין מפתח שחזור?"), + "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( + "בשל טבע הפרוטוקול של ההצפנת קצה-אל-קצה שלנו, אין אפשרות לפענח את הנתונים שלך בלי הסיסמה או מפתח השחזור שלך"), + "noResults": MessageLookupByLibrary.simpleMessage("אין תוצאות"), + "notifications": MessageLookupByLibrary.simpleMessage("התראות"), + "ok": MessageLookupByLibrary.simpleMessage("אוקיי"), + "onDevice": MessageLookupByLibrary.simpleMessage("על המכשיר"), + "onEnte": + MessageLookupByLibrary.simpleMessage("באנטע"), + "oops": MessageLookupByLibrary.simpleMessage("אופס"), + "oopsSomethingWentWrong": + MessageLookupByLibrary.simpleMessage("אופס, משהו השתבש"), + "openSettings": MessageLookupByLibrary.simpleMessage("פתח הגדרות"), + "optionalAsShortAsYouLike": + MessageLookupByLibrary.simpleMessage("אופציונלי, קצר ככל שתרצה..."), + "orPickAnExistingOne": + MessageLookupByLibrary.simpleMessage("או בחר באחד קיים"), + "password": MessageLookupByLibrary.simpleMessage("סיסמא"), + "passwordChangedSuccessfully": + MessageLookupByLibrary.simpleMessage("הססמה הוחלפה בהצלחה"), + "passwordLock": MessageLookupByLibrary.simpleMessage("נעילת סיסמא"), + "passwordStrength": m41, + "passwordWarning": MessageLookupByLibrary.simpleMessage( + "אנחנו לא שומרים את הסיסמא הזו, לכן אם אתה שוכח אותה, אנחנו לא יכולים לפענח את המידע שלך"), + "paymentDetails": MessageLookupByLibrary.simpleMessage("פרטי תשלום"), + "paymentFailed": MessageLookupByLibrary.simpleMessage("התשלום נכשל"), + "paymentFailedTalkToProvider": m42, + "peopleUsingYourCode": + MessageLookupByLibrary.simpleMessage("אנשים משתמשים בקוד שלך"), + "permanentlyDelete": + MessageLookupByLibrary.simpleMessage("למחוק לצמיתות?"), + "photoGridSize": + MessageLookupByLibrary.simpleMessage("גודל לוח של התמונה"), + "photoSmallCase": MessageLookupByLibrary.simpleMessage("תמונה"), + "playstoreSubscription": + MessageLookupByLibrary.simpleMessage("מנוי PlayStore"), + "pleaseContactSupportAndWeWillBeHappyToHelp": + MessageLookupByLibrary.simpleMessage( + "אנא צור קשר עם support@ente.io ואנחנו נשמח לעזור!"), + "pleaseGrantPermissions": + MessageLookupByLibrary.simpleMessage("נא הענק את ההרשאות"), + "pleaseLoginAgain": + MessageLookupByLibrary.simpleMessage("אנא התחבר שוב"), + "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("אנא נסה שנית"), + "pleaseWait": MessageLookupByLibrary.simpleMessage("אנא המתן..."), + "pleaseWaitForSometimeBeforeRetrying": + MessageLookupByLibrary.simpleMessage( + "אנא חכה מעט לפני שאתה מנסה שוב"), + "preparingLogs": MessageLookupByLibrary.simpleMessage("מכין לוגים..."), + "preserveMore": MessageLookupByLibrary.simpleMessage("שמור עוד"), + "pressAndHoldToPlayVideo": MessageLookupByLibrary.simpleMessage( + "לחץ והחזק על מנת להריץ את הסרטון"), + "pressAndHoldToPlayVideoDetailed": MessageLookupByLibrary.simpleMessage( + "לחץ והחזק על התמונה על מנת להריץ את הסרטון"), + "privacy": MessageLookupByLibrary.simpleMessage("פרטיות"), + "privacyPolicyTitle": + MessageLookupByLibrary.simpleMessage("מדיניות פרטיות"), + "privateBackups": + MessageLookupByLibrary.simpleMessage("גיבויים פרטיים"), + "privateSharing": MessageLookupByLibrary.simpleMessage("שיתוף פרטי"), + "publicLinkCreated": + MessageLookupByLibrary.simpleMessage("קישור ציבורי נוצר"), + "publicLinkEnabled": + MessageLookupByLibrary.simpleMessage("לינק ציבורי אופשר"), + "radius": MessageLookupByLibrary.simpleMessage("רדיוס"), + "raiseTicket": MessageLookupByLibrary.simpleMessage("צור ticket"), + "rateTheApp": MessageLookupByLibrary.simpleMessage("דרג את האפליקציה"), + "rateUs": MessageLookupByLibrary.simpleMessage("דרג אותנו"), + "rateUsOnStore": m46, + "recover": MessageLookupByLibrary.simpleMessage("שחזר"), + "recoverAccount": MessageLookupByLibrary.simpleMessage("שחזר חשבון"), + "recoverButton": MessageLookupByLibrary.simpleMessage("שחזר"), + "recoveryKey": MessageLookupByLibrary.simpleMessage("מפתח שחזור"), + "recoveryKeyCopiedToClipboard": + MessageLookupByLibrary.simpleMessage("מפתח השחזור הועתק ללוח"), + "recoveryKeyOnForgotPassword": MessageLookupByLibrary.simpleMessage( + "אם אתה שוכח את הסיסמא שלך, הדרך היחידה שתוכל לשחזר את המידע שלך היא עם המפתח הזה."), + "recoveryKeySaveDescription": MessageLookupByLibrary.simpleMessage( + "אנחנו לא מאחסנים את המפתח הזה, אנא שמור את המפתח 24 מילים הזה במקום בטוח."), + "recoveryKeySuccessBody": MessageLookupByLibrary.simpleMessage( + "נהדר! מפתח השחזור תקין. אנחנו מודים לך על האימות.\n\nאנא תזכור לגבות את מפתח השחזור שלך באופן בטוח."), + "recoveryKeyVerified": + MessageLookupByLibrary.simpleMessage("מפתח השחזור אומת"), + "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( + "מפתח השחזור שלך הוא הדרך היחידה לשחזר את התמונות שלך במקרה ותשכח את הסיסמא שלך. אתה יכול למצוא את מפתח השחזור שלך ב-הגדרות > אבטחה.\n\nאנא הכנס את מפתח השחזור שלך כאן על מנת לוודא ששמרת אותו כשורה."), + "recoverySuccessful": + MessageLookupByLibrary.simpleMessage("השחזור עבר בהצלחה!"), + "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( + "המכשיר הנוכחי אינו חזק מספיק כדי לאמת את הסיסמא שלך, אבל אנחנו יכולים ליצור בצורה שתעבוד עם כל המכשירים.\n\nאנא התחבר בעזרת המפתח שחזור שלך וצור מחדש את הסיסמא שלך (אתה יכול להשתמש באותה אחת אם אתה רוצה)."), + "recreatePasswordTitle": + MessageLookupByLibrary.simpleMessage("צור סיסמא מחדש"), + "reddit": MessageLookupByLibrary.simpleMessage("Reddit"), + "referralStep1": MessageLookupByLibrary.simpleMessage( + "1. תמסור את הקוד הזה לחברייך"), + "referralStep2": MessageLookupByLibrary.simpleMessage( + "2. הם נרשמים עבור תוכנית בתשלום"), + "referralStep3": m47, + "referrals": MessageLookupByLibrary.simpleMessage("הפניות"), + "referralsAreCurrentlyPaused": + MessageLookupByLibrary.simpleMessage("הפניות כרגע מושהות"), + "remindToEmptyDeviceTrash": MessageLookupByLibrary.simpleMessage( + "גם נקה \"נמחק לאחרונה\" מ-\"הגדרות\" -> \"אחסון\" על מנת לקבל המקום אחסון שהתפנה"), + "remindToEmptyEnteTrash": MessageLookupByLibrary.simpleMessage( + "גם נקה את ה-\"אשפה\" שלך על מנת לקבל את המקום אחסון שהתפנה"), + "remove": MessageLookupByLibrary.simpleMessage("הסר"), + "removeDuplicates": + MessageLookupByLibrary.simpleMessage("הסר כפילויות"), + "removeFromAlbum": MessageLookupByLibrary.simpleMessage("הסר מהאלבום"), + "removeFromAlbumTitle": + MessageLookupByLibrary.simpleMessage("הסר מהאלבום?"), + "removeLink": MessageLookupByLibrary.simpleMessage("הסרת קישור"), + "removeParticipant": MessageLookupByLibrary.simpleMessage("הסר משתתף"), + "removeParticipantBody": m48, + "removePublicLink": + MessageLookupByLibrary.simpleMessage("הסר לינק ציבורי"), + "removeShareItemsWarning": MessageLookupByLibrary.simpleMessage( + "חלק מהפריטים שאתה מסיר הוספו על ידי אנשים אחרים, ואתה תאבד גישה אליהם"), + "removeWithQuestionMark": MessageLookupByLibrary.simpleMessage("הסר?"), + "removingFromFavorites": + MessageLookupByLibrary.simpleMessage("מסיר מהמועדפים..."), + "rename": MessageLookupByLibrary.simpleMessage("שנה שם"), + "renameFile": MessageLookupByLibrary.simpleMessage("שנה שם הקובץ"), + "renewSubscription": MessageLookupByLibrary.simpleMessage("חדש מנוי"), + "reportABug": MessageLookupByLibrary.simpleMessage("דווח על באג"), + "reportBug": MessageLookupByLibrary.simpleMessage("דווח על באג"), + "resendEmail": MessageLookupByLibrary.simpleMessage("שלח דוא\"ל מחדש"), + "resetPasswordTitle": + MessageLookupByLibrary.simpleMessage("איפוס סיסמה"), + "restore": MessageLookupByLibrary.simpleMessage("שחזר"), + "restoreToAlbum": MessageLookupByLibrary.simpleMessage("שחזר לאלבום"), + "restoringFiles": + MessageLookupByLibrary.simpleMessage("משחזר קבצים..."), + "retry": MessageLookupByLibrary.simpleMessage("נסה שוב"), + "reviewDeduplicateItems": MessageLookupByLibrary.simpleMessage( + "אנא בחן והסר את הפריטים שאתה מאמין שהם כפלים."), + "rotateLeft": MessageLookupByLibrary.simpleMessage("סובב שמאלה"), + "safelyStored": MessageLookupByLibrary.simpleMessage("נשמר באופן בטוח"), + "save": MessageLookupByLibrary.simpleMessage("שמור"), + "saveCollage": MessageLookupByLibrary.simpleMessage("שמור קולז"), + "saveCopy": MessageLookupByLibrary.simpleMessage("שמירת עותק"), + "saveKey": MessageLookupByLibrary.simpleMessage("שמור מפתח"), + "saveYourRecoveryKeyIfYouHaventAlready": + MessageLookupByLibrary.simpleMessage( + "שמור את מפתח השחזור שלך אם לא שמרת כבר"), + "saving": MessageLookupByLibrary.simpleMessage("שומר..."), + "scanCode": MessageLookupByLibrary.simpleMessage("סרוק קוד"), + "scanThisBarcodeWithnyourAuthenticatorApp": + MessageLookupByLibrary.simpleMessage( + "סרוק את הברקוד הזה\nבעזרת אפליקציית האימות שלך"), + "searchByAlbumNameHint": + MessageLookupByLibrary.simpleMessage("שם האלבום"), + "security": MessageLookupByLibrary.simpleMessage("אבטחה"), + "selectAlbum": MessageLookupByLibrary.simpleMessage("בחר אלבום"), + "selectAll": MessageLookupByLibrary.simpleMessage("בחר הכל"), + "selectFoldersForBackup": + MessageLookupByLibrary.simpleMessage("בחר תיקיות לגיבוי"), + "selectMorePhotos": + MessageLookupByLibrary.simpleMessage("בחר תמונות נוספות"), + "selectReason": MessageLookupByLibrary.simpleMessage("בחר סיבה"), + "selectYourPlan": MessageLookupByLibrary.simpleMessage("בחר תוכנית"), + "selectedFoldersWillBeEncryptedAndBackedUp": + MessageLookupByLibrary.simpleMessage( + "התיקיות שנבחרו יוצפנו ויגובו"), + "selectedPhotos": m1, + "selectedPhotosWithYours": m51, + "send": MessageLookupByLibrary.simpleMessage("שלח"), + "sendEmail": MessageLookupByLibrary.simpleMessage("שלח דוא\"ל"), + "sendInvite": MessageLookupByLibrary.simpleMessage("שלח הזמנה"), + "sendLink": MessageLookupByLibrary.simpleMessage("שלח קישור"), + "sessionExpired": + MessageLookupByLibrary.simpleMessage("פג תוקף החיבור"), + "setAPassword": MessageLookupByLibrary.simpleMessage("הגדר סיסמה"), + "setAs": MessageLookupByLibrary.simpleMessage("הגדר בתור"), + "setCover": MessageLookupByLibrary.simpleMessage("הגדר כרקע"), + "setLabel": MessageLookupByLibrary.simpleMessage("הגדר"), + "setPasswordTitle": MessageLookupByLibrary.simpleMessage("הגדר סיסמא"), + "setRadius": MessageLookupByLibrary.simpleMessage("הגדר רדיוס"), + "setupComplete": MessageLookupByLibrary.simpleMessage("ההתקנה הושלמה"), + "share": MessageLookupByLibrary.simpleMessage("שתף"), + "shareALink": MessageLookupByLibrary.simpleMessage("שתף קישור"), + "shareAnAlbumNow": + MessageLookupByLibrary.simpleMessage("שתף אלבום עכשיו"), + "shareLink": MessageLookupByLibrary.simpleMessage("שתף קישור"), + "shareMyVerificationID": m52, + "shareOnlyWithThePeopleYouWant": + MessageLookupByLibrary.simpleMessage("שתף רק אם אנשים שאתה בוחר"), + "shareTextConfirmOthersVerificationID": m2, + "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( + "הורד את ente על מנת שנוכל לשתף תמונות וסרטונים באיכות המקור באופן קל\n\nhttps://ente.io"), + "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( + "שתף עם משתמשים שהם לא של ente"), + "shareWithPeopleSectionTitle": m54, + "shareYourFirstAlbum": + MessageLookupByLibrary.simpleMessage("שתף את האלבום הראשון שלך"), + "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( + "צור אלבומים הניתנים לשיתוף ושיתוף פעולה עם משתמשי ente אחרים, כולל משתמשים בתוכניות החינמיות."), + "sharedByMe": MessageLookupByLibrary.simpleMessage("שותף על ידי"), + "sharedPhotoNotifications": + MessageLookupByLibrary.simpleMessage("אלבומים משותפים חדשים"), + "sharedPhotoNotificationsExplanation": + MessageLookupByLibrary.simpleMessage( + "קבל התראות כשמישהו מוסיף תמונה לאלבום משותף שאתה חלק ממנו"), + "sharedWith": m55, + "sharedWithMe": MessageLookupByLibrary.simpleMessage("שותף איתי"), + "sharing": MessageLookupByLibrary.simpleMessage("משתף..."), + "showMemories": MessageLookupByLibrary.simpleMessage("הצג זכרונות"), + "signUpTerms": MessageLookupByLibrary.simpleMessage( + "אני מסכים לתנאי שירות ולמדיניות הפרטיות"), + "singleFileDeleteFromDevice": m56, + "singleFileDeleteHighlight": + MessageLookupByLibrary.simpleMessage("זה יימחק מכל האלבומים."), + "skip": MessageLookupByLibrary.simpleMessage("דלג"), + "social": MessageLookupByLibrary.simpleMessage("חברתי"), + "someoneSharingAlbumsWithYouShouldSeeTheSameId": + MessageLookupByLibrary.simpleMessage( + "מי שמשתף איתך אלבומים יוכל לראות את אותו המזהה במכשיר שלהם."), + "somethingWentWrong": + MessageLookupByLibrary.simpleMessage("משהו השתבש"), + "somethingWentWrongPleaseTryAgain": + MessageLookupByLibrary.simpleMessage("משהו השתבש, אנא נסה שנית"), + "sorry": MessageLookupByLibrary.simpleMessage("מצטער"), + "sorryCouldNotAddToFavorites": MessageLookupByLibrary.simpleMessage( + "סליחה, לא ניתן להוסיף למועדפים!"), + "sorryCouldNotRemoveFromFavorites": + MessageLookupByLibrary.simpleMessage( + "סליחה, לא ניתן להסיר מהמועדפים!"), + "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": + MessageLookupByLibrary.simpleMessage( + "אנחנו מצטערים, לא הצלחנו ליצור מפתחות מאובטחים על מכשיר זה.\n\nאנא הירשם ממכשיר אחר."), + "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("מיין לפי"), + "sortOldestFirst": + MessageLookupByLibrary.simpleMessage("הישן ביותר קודם"), + "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ הצלחה"), + "startBackup": MessageLookupByLibrary.simpleMessage("התחל גיבוי"), + "storage": MessageLookupByLibrary.simpleMessage("אחסון"), + "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("משפחה"), + "storageBreakupYou": MessageLookupByLibrary.simpleMessage("אתה"), + "storageInGB": m59, + "storageLimitExceeded": + MessageLookupByLibrary.simpleMessage("גבול מקום האחסון נחרג"), + "strongStrength": MessageLookupByLibrary.simpleMessage("חזקה"), + "subWillBeCancelledOn": m62, + "subscribe": MessageLookupByLibrary.simpleMessage("הרשם"), + "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( + "נראה שהמנוי שלך עומד לפוג. אנא הירשם כדי לאפשר שיתוף."), + "subscription": MessageLookupByLibrary.simpleMessage("מנוי"), + "success": MessageLookupByLibrary.simpleMessage("הצלחה"), + "suggestFeatures": + MessageLookupByLibrary.simpleMessage("הציעו מאפיינים"), + "support": MessageLookupByLibrary.simpleMessage("תמיכה"), + "syncProgress": m63, + "syncing": MessageLookupByLibrary.simpleMessage("מסנכרן..."), + "systemTheme": MessageLookupByLibrary.simpleMessage("מערכת"), + "tapToCopy": MessageLookupByLibrary.simpleMessage("הקש כדי להעתיק"), + "tapToEnterCode": + MessageLookupByLibrary.simpleMessage("הקש כדי להזין את הקוד"), + "terminate": MessageLookupByLibrary.simpleMessage("סיים"), + "terminateSession": MessageLookupByLibrary.simpleMessage("סיים חיבור?"), + "terms": MessageLookupByLibrary.simpleMessage("תנאים"), + "termsOfServicesTitle": MessageLookupByLibrary.simpleMessage("תנאים"), + "thankYou": MessageLookupByLibrary.simpleMessage("תודה"), + "thankYouForSubscribing": + MessageLookupByLibrary.simpleMessage("תודה שנרשמת!"), + "theDownloadCouldNotBeCompleted": + MessageLookupByLibrary.simpleMessage("לא ניתן להשלים את ההורדה"), + "theme": MessageLookupByLibrary.simpleMessage("ערכת נושא"), + "theyAlsoGetXGb": m64, + "thisCanBeUsedToRecoverYourAccountIfYou": + MessageLookupByLibrary.simpleMessage( + "זה יכול לשמש לשחזור החשבון שלך במקרה ותאבד את הגורם השני"), + "thisDevice": MessageLookupByLibrary.simpleMessage("מכשיר זה"), + "thisIsPersonVerificationId": m65, + "thisIsYourVerificationId": + MessageLookupByLibrary.simpleMessage("זה מזהה האימות שלך"), + "thisWillLogYouOutOfTheFollowingDevice": + MessageLookupByLibrary.simpleMessage("זה ינתק אותך מהמכשיר הבא:"), + "thisWillLogYouOutOfThisDevice": + MessageLookupByLibrary.simpleMessage("זה ינתק אותך במכשיר זה!"), + "toResetVerifyEmail": MessageLookupByLibrary.simpleMessage( + "כדי לאפס את הסיסמא שלך, אנא אמת את האימייל שלך קודם."), + "total": MessageLookupByLibrary.simpleMessage("סך הכל"), + "totalSize": MessageLookupByLibrary.simpleMessage("גודל כולל"), + "trash": MessageLookupByLibrary.simpleMessage("אשפה"), + "tryAgain": MessageLookupByLibrary.simpleMessage("נסה שוב"), + "twitter": MessageLookupByLibrary.simpleMessage("Twitter"), + "twoMonthsFreeOnYearlyPlans": MessageLookupByLibrary.simpleMessage( + "חודשיים בחינם בתוכניות שנתיות"), + "twofactor": MessageLookupByLibrary.simpleMessage("דו-גורמי"), + "twofactorAuthenticationPageTitle": + MessageLookupByLibrary.simpleMessage("אימות דו-גורמי"), + "twofactorSetup": MessageLookupByLibrary.simpleMessage("אימות דו-שלבי"), + "unarchive": MessageLookupByLibrary.simpleMessage("הוצאה מארכיון"), + "uncategorized": MessageLookupByLibrary.simpleMessage("ללא קטגוריה"), + "unhide": MessageLookupByLibrary.simpleMessage("בטל הסתרה"), + "unhideToAlbum": + MessageLookupByLibrary.simpleMessage("בטל הסתרה בחזרה לאלבום"), + "unhidingFilesToAlbum": + MessageLookupByLibrary.simpleMessage("מבטל הסתרת הקבצים לאלבום"), + "unlock": MessageLookupByLibrary.simpleMessage("ביטול נעילה"), + "unselectAll": MessageLookupByLibrary.simpleMessage("בטל בחירה של הכל"), + "update": MessageLookupByLibrary.simpleMessage("עדכן"), + "updateAvailable": MessageLookupByLibrary.simpleMessage("עדכון זמין"), + "updatingFolderSelection": + MessageLookupByLibrary.simpleMessage("מעדכן את בחירת התיקיות..."), + "upgrade": MessageLookupByLibrary.simpleMessage("שדרג"), + "uploadingFilesToAlbum": + MessageLookupByLibrary.simpleMessage("מעלה קבצים לאלבום..."), + "usableReferralStorageInfo": MessageLookupByLibrary.simpleMessage( + "כמות האחסון השמישה שלך מוגבלת בתוכנית הנוכחית. אחסון עודף יהפוך שוב לשמיש אחרי שתשדרג את התוכנית שלך."), + "useRecoveryKey": + MessageLookupByLibrary.simpleMessage("השתמש במפתח שחזור"), + "usedSpace": MessageLookupByLibrary.simpleMessage("מקום בשימוש"), + "verificationId": MessageLookupByLibrary.simpleMessage("מזהה אימות"), + "verify": MessageLookupByLibrary.simpleMessage("אמת"), + "verifyEmail": MessageLookupByLibrary.simpleMessage("אימות דוא\"ל"), + "verifyEmailID": m68, + "verifyIDLabel": MessageLookupByLibrary.simpleMessage("אמת"), + "verifyPassword": MessageLookupByLibrary.simpleMessage("אמת סיסמא"), + "verifyingRecoveryKey": + MessageLookupByLibrary.simpleMessage("מוודא את מפתח השחזור..."), + "videoSmallCase": MessageLookupByLibrary.simpleMessage("וידאו"), + "viewActiveSessions": + MessageLookupByLibrary.simpleMessage("צפה בחיבורים פעילים"), + "viewAll": MessageLookupByLibrary.simpleMessage("הצג הכל"), + "viewLogs": MessageLookupByLibrary.simpleMessage("צפייה בלוגים"), + "viewRecoveryKey": + MessageLookupByLibrary.simpleMessage("צפה במפתח השחזור"), + "viewer": MessageLookupByLibrary.simpleMessage("צפיין"), + "visitWebToManage": MessageLookupByLibrary.simpleMessage( + "אנא בקר ב-web.ente.io על מנת לנהל את המנוי שלך"), + "weAreOpenSource": + MessageLookupByLibrary.simpleMessage("הקוד שלנו פתוח!"), + "weHaveSendEmailTo": m69, + "weakStrength": MessageLookupByLibrary.simpleMessage("חלשה"), + "welcomeBack": MessageLookupByLibrary.simpleMessage("ברוך שובך!"), + "yearly": MessageLookupByLibrary.simpleMessage("שנתי"), + "yearsAgo": m70, + "yes": MessageLookupByLibrary.simpleMessage("כן"), + "yesCancel": MessageLookupByLibrary.simpleMessage("כן, בטל"), + "yesConvertToViewer": + MessageLookupByLibrary.simpleMessage("כן, המר לצפיין"), + "yesDelete": MessageLookupByLibrary.simpleMessage("כן, מחק"), + "yesLogout": MessageLookupByLibrary.simpleMessage("כן, התנתק"), + "yesRemove": MessageLookupByLibrary.simpleMessage("כן, הסר"), + "yesRenew": MessageLookupByLibrary.simpleMessage("כן, חדש"), + "you": MessageLookupByLibrary.simpleMessage("אתה"), + "youAreOnAFamilyPlan": + MessageLookupByLibrary.simpleMessage("אתה על תוכנית משפחתית!"), + "youAreOnTheLatestVersion": + MessageLookupByLibrary.simpleMessage("אתה על הגרסא הכי עדכנית"), + "youCanAtMaxDoubleYourStorage": MessageLookupByLibrary.simpleMessage( + "* אתה יכול במקסימום להכפיל את מקום האחסון שלך"), + "youCanManageYourLinksInTheShareTab": + MessageLookupByLibrary.simpleMessage( + "אתה יכול לנהת את הקישורים שלך בלשונית שיתוף."), + "youCannotDowngradeToThisPlan": MessageLookupByLibrary.simpleMessage( + "אתה לא יכול לשנמך לתוכנית הזו"), + "youCannotShareWithYourself": + MessageLookupByLibrary.simpleMessage("אתה לא יכול לשתף עם עצמך"), + "youHaveSuccessfullyFreedUp": m71, + "yourAccountHasBeenDeleted": + MessageLookupByLibrary.simpleMessage("החשבון שלך נמחק"), + "yourPlanWasSuccessfullyDowngraded": + MessageLookupByLibrary.simpleMessage("התוכנית שלך שונמכה בהצלחה"), + "yourPlanWasSuccessfullyUpgraded": + MessageLookupByLibrary.simpleMessage("התוכנית שלך שודרגה בהצלחה"), + "yourPurchaseWasSuccessful": + MessageLookupByLibrary.simpleMessage("התשלום שלך עבר בהצלחה"), + "yourStorageDetailsCouldNotBeFetched": + MessageLookupByLibrary.simpleMessage( + "לא ניתן לאחזר את פרטי מקום האחסון"), + "yourSubscriptionHasExpired": + MessageLookupByLibrary.simpleMessage("פג תוקף המנוי שלך"), + "yourSubscriptionWasUpdatedSuccessfully": + MessageLookupByLibrary.simpleMessage("המנוי שלך עודכן בהצלחה"), + "youveNoDuplicateFilesThatCanBeCleared": + MessageLookupByLibrary.simpleMessage( + "אין לך קבצים כפולים שניתן לנקות אותם") + }; +} diff --git a/mobile/lib/generated/intl/messages_hi.dart b/mobile/lib/generated/intl/messages_hi.dart new file mode 100644 index 0000000000..ce390ea7e0 --- /dev/null +++ b/mobile/lib/generated/intl/messages_hi.dart @@ -0,0 +1,113 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a hi locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'hi'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "accountWelcomeBack": + MessageLookupByLibrary.simpleMessage("आपका पुनः स्वागत है"), + "activeSessions": MessageLookupByLibrary.simpleMessage("एक्टिव सेशन"), + "askDeleteReason": MessageLookupByLibrary.simpleMessage( + "आपका अकाउंट हटाने का मुख्य कारण क्या है?"), + "cancel": MessageLookupByLibrary.simpleMessage("रद्द करें"), + "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage( + "अकाउंट डिलीट करने की पुष्टि करें"), + "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( + "हां, मैं इस अकाउंट और इसके सभी डेटा को स्थायी रूप से हटाना चाहता/चाहती हूं।"), + "confirmPassword": + MessageLookupByLibrary.simpleMessage("पासवर्ड की पुष्टि करें"), + "createAccount": MessageLookupByLibrary.simpleMessage("अकाउंट बनायें"), + "createNewAccount": + MessageLookupByLibrary.simpleMessage("नया अकाउंट बनाएँ"), + "decrypting": + MessageLookupByLibrary.simpleMessage("डिक्रिप्ट हो रहा है..."), + "deleteAccount": + MessageLookupByLibrary.simpleMessage("अकाउंट डिलीट करें"), + "deleteAccountFeedbackPrompt": MessageLookupByLibrary.simpleMessage( + "आपको जाता हुए देख कर हमें खेद है। कृपया हमें बेहतर बनने में सहायता के लिए अपनी प्रतिक्रिया साझा करें।"), + "deleteAccountPermanentlyButton": MessageLookupByLibrary.simpleMessage( + "अकाउंट स्थायी रूप से डिलीट करें"), + "deleteEmailRequest": MessageLookupByLibrary.simpleMessage( + "कृपया account-deletion@ente.io पर अपने पंजीकृत ईमेल एड्रेस से ईमेल भेजें।"), + "deleteReason1": MessageLookupByLibrary.simpleMessage( + "इसमें एक मुख्य विशेषता गायब है जिसकी मुझे आवश्यकता है"), + "deleteReason2": MessageLookupByLibrary.simpleMessage( + "यह ऐप या इसका कोई एक फीचर मेरे विचारानुसार काम नहीं करता है"), + "deleteReason3": MessageLookupByLibrary.simpleMessage( + "मुझे कहीं और कोई दूरी सेवा मिली जो मुझे बेहतर लगी"), + "deleteReason4": MessageLookupByLibrary.simpleMessage( + "मेरा कारण इस लिस्ट में नहीं है"), + "deleteRequestSLAText": MessageLookupByLibrary.simpleMessage( + "आपका अनुरोध 72 घंटों के भीतर संसाधित किया जाएगा।"), + "email": MessageLookupByLibrary.simpleMessage("ईमेल"), + "entePhotosPerm": MessageLookupByLibrary.simpleMessage( + "Ente को आपकी तस्वीरों को संरक्षित करने के लिए अनुमति की आवश्यकता है"), + "enterValidEmail": MessageLookupByLibrary.simpleMessage( + "कृपया वैद्य ईमेल ऐड्रेस डालें"), + "enterYourEmailAddress": + MessageLookupByLibrary.simpleMessage("अपना ईमेल ऐड्रेस डालें"), + "enterYourRecoveryKey": + MessageLookupByLibrary.simpleMessage("अपनी रिकवरी कुंजी दर्ज करें"), + "feedback": MessageLookupByLibrary.simpleMessage("प्रतिपुष्टि"), + "forgotPassword": + MessageLookupByLibrary.simpleMessage("पासवर्ड भूल गए"), + "incorrectRecoveryKeyBody": MessageLookupByLibrary.simpleMessage( + "आपके द्वारा दर्ज रिकवरी कुंजी ग़लत है"), + "incorrectRecoveryKeyTitle": + MessageLookupByLibrary.simpleMessage("रिकवरी कुंजी ग़लत है"), + "invalidEmailAddress": + MessageLookupByLibrary.simpleMessage("अमान्य ईमेल ऐड्रेस"), + "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( + "कृपया हमें इस जानकारी के लिए सहायता करें"), + "noRecoveryKey": + MessageLookupByLibrary.simpleMessage("रिकवरी कुंजी नहीं है?"), + "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( + "हमारे एंड-टू-एंड एन्क्रिप्शन प्रोटोकॉल की प्रकृति के कारण, आपके डेटा को आपके पासवर्ड या रिकवरी कुंजी के बिना डिक्रिप्ट नहीं किया जा सकता है"), + "ok": MessageLookupByLibrary.simpleMessage("ठीक है"), + "oops": MessageLookupByLibrary.simpleMessage("ओह!"), + "password": MessageLookupByLibrary.simpleMessage("पासवर्ड"), + "recoverButton": MessageLookupByLibrary.simpleMessage("पुनः प्राप्त"), + "recoverySuccessful": + MessageLookupByLibrary.simpleMessage("रिकवरी सफल हुई!"), + "selectReason": MessageLookupByLibrary.simpleMessage("कारण चुनें"), + "sendEmail": MessageLookupByLibrary.simpleMessage("ईमेल भेजें"), + "somethingWentWrongPleaseTryAgain": + MessageLookupByLibrary.simpleMessage( + "कुछ गड़बड़ हुई है। कृपया दोबारा प्रयास करें।"), + "sorry": MessageLookupByLibrary.simpleMessage("क्षमा करें!"), + "terminate": MessageLookupByLibrary.simpleMessage("रद्द करें"), + "terminateSession": + MessageLookupByLibrary.simpleMessage("सेशन रद्द करें?"), + "thisDevice": MessageLookupByLibrary.simpleMessage("यह डिवाइस"), + "thisWillLogYouOutOfTheFollowingDevice": + MessageLookupByLibrary.simpleMessage( + "इससे आप इन डिवाइसों से लॉग आउट हो जाएँगे:"), + "thisWillLogYouOutOfThisDevice": MessageLookupByLibrary.simpleMessage( + "इससे आप इस डिवाइस से लॉग आउट हो जाएँगे!"), + "toResetVerifyEmail": MessageLookupByLibrary.simpleMessage( + "अपना पासवर्ड रीसेट करने के लिए, कृपया पहले अपना ईमेल सत्यापित करें।"), + "verify": MessageLookupByLibrary.simpleMessage("सत्यापित करें"), + "verifyEmail": + MessageLookupByLibrary.simpleMessage("ईमेल सत्यापित करें"), + "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage( + "आपका अकाउंट डिलीट कर दिया गया है") + }; +} diff --git a/mobile/lib/generated/intl/messages_id.dart b/mobile/lib/generated/intl/messages_id.dart new file mode 100644 index 0000000000..3d0cee4c14 --- /dev/null +++ b/mobile/lib/generated/intl/messages_id.dart @@ -0,0 +1,1448 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a id locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'id'; + + static String m3(count) => + "${Intl.plural(count, other: 'Tambahkan kolaborator')}"; + + static String m4(count) => "${Intl.plural(count, other: 'Tambahkan item')}"; + + static String m7(emailOrName) => "Ditambahkan oleh ${emailOrName}"; + + static String m8(albumName) => "Berhasil ditambahkan ke ${albumName}"; + + static String m9(count) => + "${Intl.plural(count, zero: '0 Peserta', one: '1 Peserta', other: '${count} Peserta')}"; + + static String m10(versionValue) => "Versi: ${versionValue}"; + + static String m11(freeAmount, storageUnit) => + "${freeAmount} ${storageUnit} tersedia"; + + static String m13(user) => + "${user} tidak akan dapat menambahkan foto lagi di album ini\n\nMereka masih dapat menghapus foto yang sudah ada yang ditambahkan oleh mereka"; + + static String m14(isFamilyMember, storageAmountInGb) => + "${Intl.select(isFamilyMember, { + 'true': + 'Keluargamu saat ini telah memperoleh ${storageAmountInGb} GB', + 'false': 'Kamu saat ini telah memperoleh ${storageAmountInGb} GB', + 'other': 'Kamu saat ini telah memperoleh ${storageAmountInGb} GB!', + })}"; + + static String m15(albumName) => "Link kolaborasi terbuat untuk ${albumName}"; + + static String m16(familyAdminEmail) => + "Silakan hubungi ${familyAdminEmail} untuk mengatur langgananmu"; + + static String m17(provider) => + "Silakan hubungi kami di support@ente.io untuk mengatur langganan ${provider} kamu."; + + static String m18(endpoint) => "Terhubung ke ${endpoint}"; + + static String m19(count) => + "${Intl.plural(count, one: 'Hapus ${count} item', other: 'Hapus ${count} item')}"; + + static String m20(currentlyDeleting, totalCount) => + "Menghapus ${currentlyDeleting} / ${totalCount}"; + + static String m21(albumName) => + "Ini akan menghapus link publik yang digunakan untuk mengakses \"${albumName}\"."; + + static String m22(supportEmail) => + "Silakan kirimkan email ke ${supportEmail} dari alamat email terdaftar kamu"; + + static String m23(count, storageSaved) => + "Kamu telah menghapus ${Intl.plural(count, other: '${count} file duplikat')} dan membersihkan (${storageSaved}!)"; + + static String m25(newEmail) => "Email diubah menjadi ${newEmail}"; + + static String m26(email) => + "${email} tidak punya akun Ente.\n\nUndang dia untuk berbagi foto."; + + static String m27(count, formattedNumber) => + "${Intl.plural(count, other: '${formattedNumber} file')} di perangkat ini telah berhasil dicadangkan"; + + static String m28(count, formattedNumber) => + "${Intl.plural(count, other: '${formattedNumber} file')} dalam album ini telah berhasil dicadangkan"; + + static String m29(storageAmountInGB) => + "${storageAmountInGB} GB setiap kali orang mendaftar dengan paket berbayar lalu menerapkan kode milikmu"; + + static String m30(endDate) => "Percobaan gratis berlaku hingga ${endDate}"; + + static String m31(count) => + "Kamu masih bisa mengakses ${Intl.plural(count, other: 'filenya')} di Ente selama kamu masih berlangganan"; + + static String m32(sizeInMBorGB) => "Bersihkan ${sizeInMBorGB}"; + + static String m33(count, formattedSize) => + "${Intl.plural(count, other: 'File tersebut bisa dihapus dari perangkat ini untuk membersihkan ${formattedSize}')}"; + + static String m34(currentlyProcessing, totalCount) => + "Memproses ${currentlyProcessing} / ${totalCount}"; + + static String m35(count) => "${Intl.plural(count, other: '${count} item')}"; + + static String m36(expiryTime) => "Link akan kedaluwarsa pada ${expiryTime}"; + + static String m0(count, formattedCount) => + "${Intl.plural(count, zero: 'tanpa kenangan', one: '${formattedCount} kenangan', other: '${formattedCount} kenangan')}"; + + static String m37(count) => "${Intl.plural(count, other: 'Pindahkan item')}"; + + static String m38(albumName) => "Berhasil dipindahkan ke ${albumName}"; + + static String m40(familyAdminEmail) => + "Harap hubungi ${familyAdminEmail} untuk mengubah kode kamu."; + + static String m41(passwordStrengthValue) => + "Keamanan sandi: ${passwordStrengthValue}"; + + static String m43(endDate) => + "Percobaan gratis berlaku hingga ${endDate}.\nKamu dapat memilih paket berbayar setelahnya."; + + static String m44(toEmail) => "Silakan kirimi kami email di ${toEmail}"; + + static String m45(toEmail) => "Silakan kirim log-nya ke \n${toEmail}"; + + static String m46(storeName) => "Beri nilai di ${storeName}"; + + static String m47(storageInGB) => + "3. Kalian berdua mendapat ${storageInGB} GB* gratis"; + + static String m48(userEmail) => + "${userEmail} akan dikeluarkan dari album berbagi ini\n\nSemua foto yang ia tambahkan juga akan dihapus dari album ini"; + + static String m49(endDate) => "Langganan akan diperpanjang pada ${endDate}"; + + static String m50(count) => + "${Intl.plural(count, other: '${count} hasil ditemukan')}"; + + static String m1(count) => "${count} terpilih"; + + static String m51(count, yourCount) => + "${count} dipilih (${yourCount} milikmu)"; + + static String m52(verificationID) => + "Ini ID Verifikasi saya di ente.io: ${verificationID}."; + + static String m2(verificationID) => + "Halo, bisakah kamu pastikan bahwa ini adalah ID Verifikasi ente.io milikmu: ${verificationID}"; + + static String m53(referralCode, referralStorageInGB) => + "Kode rujukan Ente: ${referralCode} \n\nTerapkan pada Pengaturan → Umum → Rujukan untuk mendapatkan ${referralStorageInGB} GB gratis setelah kamu mendaftar paket berbayar\n\nhttps://ente.io"; + + static String m54(numberOfPeople) => + "${Intl.plural(numberOfPeople, zero: 'Bagikan dengan orang tertentu', one: 'Berbagi dengan 1 orang', other: 'Berbagi dengan ${numberOfPeople} orang')}"; + + static String m55(emailIDs) => "Dibagikan dengan ${emailIDs}"; + + static String m56(fileType) => + "${fileType} ini akan dihapus dari perangkat ini."; + + static String m57(fileType) => + "${fileType} ini tersimpan di Ente dan juga di perangkat ini."; + + static String m58(fileType) => "${fileType} ini akan dihapus dari Ente."; + + static String m59(storageAmountInGB) => "${storageAmountInGB} GB"; + + static String m60( + usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => + "${usedAmount} ${usedStorageUnit} dari ${totalAmount} ${totalStorageUnit} terpakai"; + + static String m61(id) => + "${id} kamu telah terhubung dengan akun Ente lain.\nJika kamu ingin menggunakan ${id} kamu untuk akun ini, silahkan hubungi tim bantuan kami"; + + static String m62(endDate) => + "Langganan kamu akan dibatalkan pada ${endDate}"; + + static String m64(storageAmountInGB) => + "Ia juga mendapat ${storageAmountInGB} GB"; + + static String m65(email) => "Ini adalah ID Verifikasi milik ${email}"; + + static String m66(count) => + "${Intl.plural(count, zero: '', one: '1 hari', other: '${count} hari')}"; + + static String m67(endDate) => "Berlaku hingga ${endDate}"; + + static String m68(email) => "Verifikasi ${email}"; + + static String m69(email) => + "Kami telah mengirimkan email ke ${email}"; + + static String m70(count) => + "${Intl.plural(count, other: '${count} tahun lalu')}"; + + static String m71(storageSaved) => + "Kamu telah berhasil membersihkan ${storageSaved}!"; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "aNewVersionOfEnteIsAvailable": MessageLookupByLibrary.simpleMessage( + "Versi baru dari Ente telah tersedia."), + "account": MessageLookupByLibrary.simpleMessage("Akun"), + "accountWelcomeBack": + MessageLookupByLibrary.simpleMessage("Selamat datang kembali!"), + "ackPasswordLostWarning": MessageLookupByLibrary.simpleMessage( + "Saya mengerti bahwa jika saya lupa sandi saya, data saya bisa hilang karena dienkripsi dari ujung ke ujung."), + "activeSessions": MessageLookupByLibrary.simpleMessage("Sesi aktif"), + "addAName": MessageLookupByLibrary.simpleMessage("Tambahkan nama"), + "addANewEmail": + MessageLookupByLibrary.simpleMessage("Tambah email baru"), + "addCollaborator": + MessageLookupByLibrary.simpleMessage("Tambah kolaborator"), + "addCollaborators": m3, + "addFromDevice": + MessageLookupByLibrary.simpleMessage("Tambahkan dari perangkat"), + "addItem": m4, + "addLocation": MessageLookupByLibrary.simpleMessage("Tambah tempat"), + "addLocationButton": MessageLookupByLibrary.simpleMessage("Tambah"), + "addMore": MessageLookupByLibrary.simpleMessage("Tambah lagi"), + "addPhotos": MessageLookupByLibrary.simpleMessage("Tambah foto"), + "addSelected": + MessageLookupByLibrary.simpleMessage("Tambahkan yang dipilih"), + "addToAlbum": MessageLookupByLibrary.simpleMessage("Tambah ke album"), + "addToEnte": MessageLookupByLibrary.simpleMessage("Tambah ke Ente"), + "addToHiddenAlbum": + MessageLookupByLibrary.simpleMessage("Tambah ke album tersembunyi"), + "addViewer": MessageLookupByLibrary.simpleMessage("Tambahkan pemirsa"), + "addedAs": MessageLookupByLibrary.simpleMessage("Ditambahkan sebagai"), + "addedBy": m7, + "addedSuccessfullyTo": m8, + "addingToFavorites": + MessageLookupByLibrary.simpleMessage("Menambahkan ke favorit..."), + "advanced": MessageLookupByLibrary.simpleMessage("Lanjutan"), + "advancedSettings": MessageLookupByLibrary.simpleMessage("Lanjutan"), + "after1Day": MessageLookupByLibrary.simpleMessage("Setelah 1 hari"), + "after1Hour": MessageLookupByLibrary.simpleMessage("Setelah 1 jam"), + "after1Month": MessageLookupByLibrary.simpleMessage("Setelah 1 bulan"), + "after1Week": MessageLookupByLibrary.simpleMessage("Setelah 1 minggu"), + "after1Year": MessageLookupByLibrary.simpleMessage("Setelah 1 tahun"), + "albumOwner": MessageLookupByLibrary.simpleMessage("Pemilik"), + "albumParticipantsCount": m9, + "albumTitle": MessageLookupByLibrary.simpleMessage("Judul album"), + "albumUpdated": + MessageLookupByLibrary.simpleMessage("Album diperbarui"), + "albums": MessageLookupByLibrary.simpleMessage("Album"), + "allClear": MessageLookupByLibrary.simpleMessage("✨ Sudah bersih"), + "allMemoriesPreserved": + MessageLookupByLibrary.simpleMessage("Semua kenangan terpelihara"), + "allowAddPhotosDescription": MessageLookupByLibrary.simpleMessage( + "Izinkan orang yang memiliki link untuk menambahkan foto ke album berbagi ini."), + "allowAddingPhotos": + MessageLookupByLibrary.simpleMessage("Izinkan menambah foto"), + "allowDownloads": + MessageLookupByLibrary.simpleMessage("Izinkan pengunduhan"), + "allowPeopleToAddPhotos": MessageLookupByLibrary.simpleMessage( + "Izinkan orang lain menambahkan foto"), + "androidBiometricHint": + MessageLookupByLibrary.simpleMessage("Verifikasi identitas"), + "androidBiometricNotRecognized": + MessageLookupByLibrary.simpleMessage("Tidak dikenal. Coba lagi."), + "androidBiometricRequiredTitle": + MessageLookupByLibrary.simpleMessage("Biometrik diperlukan"), + "androidBiometricSuccess": + MessageLookupByLibrary.simpleMessage("Berhasil"), + "androidCancelButton": MessageLookupByLibrary.simpleMessage("Batal"), + "androidGoToSettingsDescription": MessageLookupByLibrary.simpleMessage( + "Autentikasi biometrik belum aktif di perangkatmu. Buka \'Setelan > Keamanan\' untuk mengaktifkan autentikasi biometrik."), + "androidIosWebDesktop": + MessageLookupByLibrary.simpleMessage("Android, iOS, Web, Desktop"), + "androidSignInTitle": + MessageLookupByLibrary.simpleMessage("Autentikasi diperlukan"), + "appVersion": m10, + "appleId": MessageLookupByLibrary.simpleMessage("ID Apple"), + "apply": MessageLookupByLibrary.simpleMessage("Terapkan"), + "applyCodeTitle": MessageLookupByLibrary.simpleMessage("Terapkan kode"), + "archive": MessageLookupByLibrary.simpleMessage("Arsip"), + "archiveAlbum": MessageLookupByLibrary.simpleMessage("Arsipkan album"), + "archiving": MessageLookupByLibrary.simpleMessage("Mengarsipkan..."), + "areYouSureThatYouWantToLeaveTheFamily": + MessageLookupByLibrary.simpleMessage( + "Apakah kamu yakin ingin meninggalkan paket keluarga ini?"), + "areYouSureYouWantToCancel": MessageLookupByLibrary.simpleMessage( + "Apakah kamu yakin ingin membatalkan?"), + "areYouSureYouWantToChangeYourPlan": + MessageLookupByLibrary.simpleMessage( + "Apakah kamu yakin ingin mengubah paket kamu?"), + "areYouSureYouWantToExit": MessageLookupByLibrary.simpleMessage( + "Apakah kamu yakin ingin keluar?"), + "areYouSureYouWantToLogout": MessageLookupByLibrary.simpleMessage( + "Apakah kamu yakin ingin keluar akun?"), + "areYouSureYouWantToRenew": MessageLookupByLibrary.simpleMessage( + "Apakah kamu yakin ingin memperpanjang?"), + "askCancelReason": MessageLookupByLibrary.simpleMessage( + "Langganan kamu telah dibatalkan. Apakah kamu ingin membagikan alasannya?"), + "askDeleteReason": MessageLookupByLibrary.simpleMessage( + "Apa alasan utama kamu dalam menghapus akun?"), + "atAFalloutShelter": + MessageLookupByLibrary.simpleMessage("di tempat pengungsian"), + "authToChangeEmailVerificationSetting": + MessageLookupByLibrary.simpleMessage( + "Harap autentikasi untuk mengatur verifikasi email"), + "authToChangeYourEmail": MessageLookupByLibrary.simpleMessage( + "Harap autentikasi untuk mengubah email kamu"), + "authToChangeYourPassword": MessageLookupByLibrary.simpleMessage( + "Harap autentikasi untuk mengubah sandi kamu"), + "authToConfigureTwofactorAuthentication": + MessageLookupByLibrary.simpleMessage( + "Harap autentikasi untuk mengatur autentikasi dua langkah"), + "authToInitiateAccountDeletion": MessageLookupByLibrary.simpleMessage( + "Harap autentikasi untuk mulai penghapusan akun"), + "authToViewYourActiveSessions": MessageLookupByLibrary.simpleMessage( + "Harap autentikasi untuk melihat sesi aktif kamu"), + "authToViewYourHiddenFiles": MessageLookupByLibrary.simpleMessage( + "Harap autentikasi untuk melihat file tersembunyi kamu"), + "authToViewYourMemories": MessageLookupByLibrary.simpleMessage( + "Harap autentikasi untuk melihat kenanganmu"), + "authToViewYourRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Harap autentikasi untuk melihat kunci pemulihan kamu"), + "authenticationFailedPleaseTryAgain": + MessageLookupByLibrary.simpleMessage( + "Autentikasi gagal, silakan coba lagi"), + "authenticationSuccessful": + MessageLookupByLibrary.simpleMessage("Autentikasi berhasil!"), + "autoCastDialogBody": MessageLookupByLibrary.simpleMessage( + "Perangkat Cast yang tersedia akan ditampilkan di sini."), + "autoCastiOSPermission": MessageLookupByLibrary.simpleMessage( + "Pastikan izin Jaringan Lokal untuk app Ente Foto aktif di Pengaturan."), + "autoLogoutMessage": MessageLookupByLibrary.simpleMessage( + "Akibat kesalahan teknis, kamu telah keluar dari akunmu. Kami mohon maaf atas ketidaknyamanannya."), + "autoPair": MessageLookupByLibrary.simpleMessage("Taut otomatis"), + "autoPairDesc": MessageLookupByLibrary.simpleMessage( + "Taut otomatis hanya tersedia di perangkat yang mendukung Chromecast."), + "available": MessageLookupByLibrary.simpleMessage("Tersedia"), + "availableStorageSpace": m11, + "backedUpFolders": + MessageLookupByLibrary.simpleMessage("Folder yang dicadangkan"), + "backup": MessageLookupByLibrary.simpleMessage("Pencadangan"), + "backupFailed": + MessageLookupByLibrary.simpleMessage("Pencadangan gagal"), + "backupOverMobileData": MessageLookupByLibrary.simpleMessage( + "Cadangkan dengan data seluler"), + "backupSettings": + MessageLookupByLibrary.simpleMessage("Pengaturan pencadangan"), + "backupVideos": MessageLookupByLibrary.simpleMessage("Cadangkan video"), + "blackFridaySale": + MessageLookupByLibrary.simpleMessage("Penawaran Black Friday"), + "blog": MessageLookupByLibrary.simpleMessage("Blog"), + "cachedData": MessageLookupByLibrary.simpleMessage("Data cache"), + "calculating": MessageLookupByLibrary.simpleMessage("Menghitung..."), + "canOnlyRemoveFilesOwnedByYou": MessageLookupByLibrary.simpleMessage( + "Hanya dapat menghapus berkas yang dimiliki oleh mu"), + "cancel": MessageLookupByLibrary.simpleMessage("Batal"), + "cancelSubscription": + MessageLookupByLibrary.simpleMessage("Batalkan langganan"), + "cannotAddMorePhotosAfterBecomingViewer": m13, + "castIPMismatchBody": MessageLookupByLibrary.simpleMessage( + "Harap pastikan kamu berada pada jaringan yang sama dengan TV-nya."), + "castIPMismatchTitle": + MessageLookupByLibrary.simpleMessage("Gagal mentransmisikan album"), + "castInstruction": MessageLookupByLibrary.simpleMessage( + "Buka cast.ente.io pada perangkat yang ingin kamu tautkan.\n\nMasukkan kode yang ditampilkan untuk memutar album di TV."), + "change": MessageLookupByLibrary.simpleMessage("Ganti"), + "changeEmail": MessageLookupByLibrary.simpleMessage("Ubah email"), + "changeLocationOfSelectedItems": MessageLookupByLibrary.simpleMessage( + "Ubah lokasi pada item terpilih?"), + "changePassword": MessageLookupByLibrary.simpleMessage("Ubah sandi"), + "changePasswordTitle": + MessageLookupByLibrary.simpleMessage("Ubah sandi"), + "changePermissions": MessageLookupByLibrary.simpleMessage("Ubah izin?"), + "changeYourReferralCode": + MessageLookupByLibrary.simpleMessage("Ganti kode rujukan kamu"), + "checkInboxAndSpamFolder": MessageLookupByLibrary.simpleMessage( + "Silakan periksa kotak masuk (serta kotak spam) untuk menyelesaikan verifikasi"), + "checking": MessageLookupByLibrary.simpleMessage("Memeriksa..."), + "claimFreeStorage": + MessageLookupByLibrary.simpleMessage("Peroleh kuota gratis"), + "claimMore": + MessageLookupByLibrary.simpleMessage("Peroleh lebih banyak!"), + "claimed": MessageLookupByLibrary.simpleMessage("Diperoleh"), + "claimedStorageSoFar": m14, + "click": MessageLookupByLibrary.simpleMessage("• Click"), + "close": MessageLookupByLibrary.simpleMessage("Tutup"), + "codeAppliedPageTitle": + MessageLookupByLibrary.simpleMessage("Kode diterapkan"), + "codeChangeLimitReached": MessageLookupByLibrary.simpleMessage( + "Maaf, anda telah mencapai batas rubah kode."), + "codeCopiedToClipboard": + MessageLookupByLibrary.simpleMessage("Kode tersalin ke papan klip"), + "codeUsedByYou": MessageLookupByLibrary.simpleMessage( + "Kode yang telah kamu gunakan"), + "collabLinkSectionDescription": MessageLookupByLibrary.simpleMessage( + "Buat link untuk memungkinkan orang lain menambahkan dan melihat foto yang ada pada album bersama kamu tanpa memerlukan app atau akun Ente. Ideal untuk mengumpulkan foto pada suatu acara."), + "collaborativeLink": + MessageLookupByLibrary.simpleMessage("Link kolaborasi"), + "collaborativeLinkCreatedFor": m15, + "collaborator": MessageLookupByLibrary.simpleMessage("Kolaborator"), + "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": + MessageLookupByLibrary.simpleMessage( + "Kolaborator bisa menambahkan foto dan video ke album bersama ini."), + "collectEventPhotos": + MessageLookupByLibrary.simpleMessage("Kumpulkan foto acara"), + "collectPhotos": MessageLookupByLibrary.simpleMessage("Kumpulkan foto"), + "color": MessageLookupByLibrary.simpleMessage("Warna"), + "confirm": MessageLookupByLibrary.simpleMessage("Konfirmasi"), + "confirm2FADisable": MessageLookupByLibrary.simpleMessage( + "Apakah kamu yakin ingin menonaktifkan autentikasi dua langkah?"), + "confirmAccountDeletion": + MessageLookupByLibrary.simpleMessage("Konfirmasi Penghapusan Akun"), + "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( + "Ya, saya ingin menghapus akun ini dan seluruh data yang terkait secara permanen."), + "confirmPassword": + MessageLookupByLibrary.simpleMessage("Konfirmasi sandi"), + "confirmPlanChange": + MessageLookupByLibrary.simpleMessage("Konfirmasi perubahan paket"), + "confirmRecoveryKey": + MessageLookupByLibrary.simpleMessage("Konfirmasi kunci pemulihan"), + "confirmYourRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Konfirmasi kunci pemulihan kamu"), + "connectToDevice": + MessageLookupByLibrary.simpleMessage("Hubungkan ke perangkat"), + "contactFamilyAdmin": m16, + "contactSupport": + MessageLookupByLibrary.simpleMessage("Hubungi dukungan"), + "contactToManageSubscription": m17, + "contacts": MessageLookupByLibrary.simpleMessage("Kontak"), + "continueLabel": MessageLookupByLibrary.simpleMessage("Lanjut"), + "continueOnFreeTrial": MessageLookupByLibrary.simpleMessage( + "Lanjut dengan percobaan gratis"), + "convertToAlbum": + MessageLookupByLibrary.simpleMessage("Ubah menjadi album"), + "copyEmailAddress": + MessageLookupByLibrary.simpleMessage("Salin alamat email"), + "copyLink": MessageLookupByLibrary.simpleMessage("Salin link"), + "copypasteThisCodentoYourAuthenticatorApp": + MessageLookupByLibrary.simpleMessage( + "Salin lalu tempel kode ini\ndi app autentikator kamu"), + "couldNotBackUpTryLater": MessageLookupByLibrary.simpleMessage( + "Kami tidak dapat mencadangkan data kamu.\nKami akan coba lagi nanti."), + "couldNotFreeUpSpace": MessageLookupByLibrary.simpleMessage( + "Tidak dapat membersihkan ruang"), + "count": MessageLookupByLibrary.simpleMessage("Jumlah"), + "crashReporting": + MessageLookupByLibrary.simpleMessage("Pelaporan crash"), + "create": MessageLookupByLibrary.simpleMessage("Buat"), + "createAccount": MessageLookupByLibrary.simpleMessage("Buat akun"), + "createAlbumActionHint": MessageLookupByLibrary.simpleMessage( + "Tekan dan tahan foto lalu klik + untuk membuat album baru"), + "createCollaborativeLink": + MessageLookupByLibrary.simpleMessage("Buat link kolaborasi"), + "createNewAccount": + MessageLookupByLibrary.simpleMessage("Buat akun baru"), + "createOrSelectAlbum": + MessageLookupByLibrary.simpleMessage("Buat atau pilih album"), + "createPublicLink": + MessageLookupByLibrary.simpleMessage("Buat link publik"), + "creatingLink": MessageLookupByLibrary.simpleMessage("Membuat link..."), + "criticalUpdateAvailable": + MessageLookupByLibrary.simpleMessage("Pembaruan penting tersedia"), + "crop": MessageLookupByLibrary.simpleMessage("Potong"), + "currentUsageIs": + MessageLookupByLibrary.simpleMessage("Pemakaian saat ini sebesar "), + "custom": MessageLookupByLibrary.simpleMessage("Kustom"), + "customEndpoint": m18, + "darkTheme": MessageLookupByLibrary.simpleMessage("Gelap"), + "dayToday": MessageLookupByLibrary.simpleMessage("Hari Ini"), + "dayYesterday": MessageLookupByLibrary.simpleMessage("Kemarin"), + "decrypting": MessageLookupByLibrary.simpleMessage("Mendekripsi..."), + "decryptingVideo": + MessageLookupByLibrary.simpleMessage("Mendekripsi video..."), + "delete": MessageLookupByLibrary.simpleMessage("Hapus"), + "deleteAccount": MessageLookupByLibrary.simpleMessage("Hapus akun"), + "deleteAccountFeedbackPrompt": MessageLookupByLibrary.simpleMessage( + "Kami sedih kamu pergi. Silakan bagikan masukanmu agar kami bisa jadi lebih baik."), + "deleteAccountPermanentlyButton": + MessageLookupByLibrary.simpleMessage("Hapus Akun Secara Permanen"), + "deleteAlbum": MessageLookupByLibrary.simpleMessage("Hapus album"), + "deleteAlbumDialog": MessageLookupByLibrary.simpleMessage( + "Hapus foto (dan video) yang ada dalam album ini dari semua album lain yang juga menampungnya?"), + "deleteAll": MessageLookupByLibrary.simpleMessage("Hapus Semua"), + "deleteEmailRequest": MessageLookupByLibrary.simpleMessage( + "Silakan kirim email ke account-deletion@ente.io dari alamat email kamu yang terdaftar."), + "deleteEmptyAlbums": + MessageLookupByLibrary.simpleMessage("Hapus album kosong"), + "deleteEmptyAlbumsWithQuestionMark": + MessageLookupByLibrary.simpleMessage("Hapus album yang kosong?"), + "deleteFromBoth": + MessageLookupByLibrary.simpleMessage("Hapus dari keduanya"), + "deleteFromDevice": + MessageLookupByLibrary.simpleMessage("Hapus dari perangkat ini"), + "deleteFromEnte": + MessageLookupByLibrary.simpleMessage("Hapus dari Ente"), + "deleteItemCount": m19, + "deletePhotos": MessageLookupByLibrary.simpleMessage("Hapus foto"), + "deleteProgress": m20, + "deleteReason1": MessageLookupByLibrary.simpleMessage( + "Fitur penting yang saya perlukan tidak ada"), + "deleteReason2": MessageLookupByLibrary.simpleMessage( + "App ini atau fitur tertentu tidak bekerja sesuai harapan saya"), + "deleteReason3": MessageLookupByLibrary.simpleMessage( + "Saya menemukan layanan lain yang lebih baik"), + "deleteReason4": MessageLookupByLibrary.simpleMessage( + "Alasan saya tidak ada di daftar"), + "deleteRequestSLAText": MessageLookupByLibrary.simpleMessage( + "Permintaan kamu akan diproses dalam waktu 72 jam."), + "deleteSharedAlbum": + MessageLookupByLibrary.simpleMessage("Hapus album bersama?"), + "deleteSharedAlbumDialogBody": MessageLookupByLibrary.simpleMessage( + "Album ini akan di hapus untuk semua\n\nKamu akan kehilangan akses ke foto yang di bagikan dalam album ini yang di miliki oleh pengguna lain"), + "descriptions": MessageLookupByLibrary.simpleMessage("Keterangan"), + "designedToOutlive": + MessageLookupByLibrary.simpleMessage("Dibuat untuk melestarikan"), + "details": MessageLookupByLibrary.simpleMessage("Rincian"), + "developerSettings": + MessageLookupByLibrary.simpleMessage("Pengaturan pengembang"), + "developerSettingsWarning": MessageLookupByLibrary.simpleMessage( + "Apakah kamu yakin ingin mengubah pengaturan pengembang?"), + "deviceCodeHint": MessageLookupByLibrary.simpleMessage("Masukkan kode"), + "deviceFilesAutoUploading": MessageLookupByLibrary.simpleMessage( + "File yang ditambahkan ke album perangkat ini akan diunggah ke Ente secara otomatis."), + "deviceNotFound": + MessageLookupByLibrary.simpleMessage("Perangkat tidak ditemukan"), + "didYouKnow": MessageLookupByLibrary.simpleMessage("Tahukah kamu?"), + "disableAutoLock": + MessageLookupByLibrary.simpleMessage("Nonaktifkan kunci otomatis"), + "disableDownloadWarningBody": MessageLookupByLibrary.simpleMessage( + "Orang yang melihat masih bisa mengambil tangkapan layar atau menyalin foto kamu menggunakan alat eksternal"), + "disableDownloadWarningTitle": + MessageLookupByLibrary.simpleMessage("Harap dicatat"), + "disableLinkMessage": m21, + "disableTwofactor": MessageLookupByLibrary.simpleMessage( + "Nonaktifkan autentikasi dua langkah"), + "disablingTwofactorAuthentication": + MessageLookupByLibrary.simpleMessage( + "Menonaktifkan autentikasi dua langkah..."), + "discord": MessageLookupByLibrary.simpleMessage("Discord"), + "distanceInKMUnit": MessageLookupByLibrary.simpleMessage("km"), + "doNotSignOut": + MessageLookupByLibrary.simpleMessage("Jangan keluarkan akun"), + "doThisLater": + MessageLookupByLibrary.simpleMessage("Lakukan lain kali"), + "doYouWantToDiscardTheEditsYouHaveMade": + MessageLookupByLibrary.simpleMessage( + "Apakah kamu ingin membuang edit yang telah kamu buat?"), + "done": MessageLookupByLibrary.simpleMessage("Selesai"), + "doubleYourStorage": + MessageLookupByLibrary.simpleMessage("Gandakan kuota kamu"), + "download": MessageLookupByLibrary.simpleMessage("Unduh"), + "downloadFailed": + MessageLookupByLibrary.simpleMessage("Gagal mengunduh"), + "downloading": MessageLookupByLibrary.simpleMessage("Mengunduh..."), + "dropSupportEmail": m22, + "duplicateFileCountWithStorageSaved": m23, + "edit": MessageLookupByLibrary.simpleMessage("Edit"), + "editLocation": MessageLookupByLibrary.simpleMessage("Edit lokasi"), + "editLocationTagTitle": + MessageLookupByLibrary.simpleMessage("Edit lokasi"), + "editsSaved": + MessageLookupByLibrary.simpleMessage("Perubahan tersimpan"), + "editsToLocationWillOnlyBeSeenWithinEnte": + MessageLookupByLibrary.simpleMessage( + "Perubahan lokasi hanya akan terlihat di Ente"), + "eligible": MessageLookupByLibrary.simpleMessage("memenuhi syarat"), + "email": MessageLookupByLibrary.simpleMessage("Email"), + "emailChangedTo": m25, + "emailNoEnteAccount": m26, + "emailVerificationToggle": + MessageLookupByLibrary.simpleMessage("Verifikasi email"), + "empty": MessageLookupByLibrary.simpleMessage("Kosongkan"), + "emptyTrash": MessageLookupByLibrary.simpleMessage("Kosongkan sampah?"), + "enableMaps": MessageLookupByLibrary.simpleMessage("Aktifkan Peta"), + "encryptingBackup": + MessageLookupByLibrary.simpleMessage("Mengenkripsi cadangan..."), + "encryption": MessageLookupByLibrary.simpleMessage("Enkripsi"), + "encryptionKeys": + MessageLookupByLibrary.simpleMessage("Kunci enkripsi"), + "endpointUpdatedMessage": + MessageLookupByLibrary.simpleMessage("Endpoint berhasil diubah"), + "endtoendEncryptedByDefault": MessageLookupByLibrary.simpleMessage( + "Dirancang dengan enkripsi ujung ke ujung"), + "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": + MessageLookupByLibrary.simpleMessage( + "Ente hanya dapat mengenkripsi dan menyimpan file jika kamu berikan izin"), + "entePhotosPerm": MessageLookupByLibrary.simpleMessage( + "Ente memerlukan izin untuk menyimpan fotomu"), + "enteSubscriptionPitch": MessageLookupByLibrary.simpleMessage( + "Ente memelihara kenanganmu, sehingga ia selalu tersedia untukmu, bahkan jika kamu kehilangan perangkatmu."), + "enteSubscriptionShareWithFamily": MessageLookupByLibrary.simpleMessage( + "Anggota keluargamu juga bisa ditambahkan ke paketmu."), + "enterAlbumName": + MessageLookupByLibrary.simpleMessage("Masukkan nama album"), + "enterCode": MessageLookupByLibrary.simpleMessage("Masukkan kode"), + "enterCodeDescription": MessageLookupByLibrary.simpleMessage( + "Masukkan kode yang diberikan temanmu untuk memperoleh kuota gratis untuk kalian berdua"), + "enterEmail": MessageLookupByLibrary.simpleMessage("Masukkan email"), + "enterFileName": + MessageLookupByLibrary.simpleMessage("Masukkan nama file"), + "enterNewPasswordToEncrypt": MessageLookupByLibrary.simpleMessage( + "Masukkan sandi baru yang bisa kami gunakan untuk mengenkripsi data kamu"), + "enterPassword": MessageLookupByLibrary.simpleMessage("Masukkan sandi"), + "enterPasswordToEncrypt": MessageLookupByLibrary.simpleMessage( + "Masukkan sandi yang bisa kami gunakan untuk mengenkripsi data kamu"), + "enterPersonName": + MessageLookupByLibrary.simpleMessage("Masukkan nama orang"), + "enterReferralCode": + MessageLookupByLibrary.simpleMessage("Masukkan kode rujukan"), + "enterThe6digitCodeFromnyourAuthenticatorApp": + MessageLookupByLibrary.simpleMessage( + "Masukkan kode 6 angka dari\napp autentikator kamu"), + "enterValidEmail": MessageLookupByLibrary.simpleMessage( + "Harap masukkan alamat email yang sah."), + "enterYourEmailAddress": + MessageLookupByLibrary.simpleMessage("Masukkan alamat email kamu"), + "enterYourPassword": + MessageLookupByLibrary.simpleMessage("Masukkan sandi kamu"), + "enterYourRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Masukkan kunci pemulihan kamu"), + "error": MessageLookupByLibrary.simpleMessage("Kesalahan"), + "everywhere": MessageLookupByLibrary.simpleMessage("di mana saja"), + "exif": MessageLookupByLibrary.simpleMessage("EXIF"), + "existingUser": MessageLookupByLibrary.simpleMessage("Masuk"), + "expiredLinkInfo": MessageLookupByLibrary.simpleMessage( + "Link ini telah kedaluwarsa. Silakan pilih waktu kedaluwarsa baru atau nonaktifkan waktu kedaluwarsa."), + "exportLogs": MessageLookupByLibrary.simpleMessage("Ekspor log"), + "exportYourData": + MessageLookupByLibrary.simpleMessage("Ekspor data kamu"), + "faceRecognition": + MessageLookupByLibrary.simpleMessage("Pengenalan wajah"), + "faces": MessageLookupByLibrary.simpleMessage("Wajah"), + "failedToApplyCode": + MessageLookupByLibrary.simpleMessage("Gagal menerapkan kode"), + "failedToCancel": + MessageLookupByLibrary.simpleMessage("Gagal membatalkan"), + "failedToDownloadVideo": + MessageLookupByLibrary.simpleMessage("Gagal mengunduh video"), + "failedToFetchOriginalForEdit": MessageLookupByLibrary.simpleMessage( + "Gagal memuat file asli untuk mengedit"), + "failedToFetchReferralDetails": MessageLookupByLibrary.simpleMessage( + "Tidak dapat mengambil kode rujukan. Harap ulang lagi nanti."), + "failedToLoadAlbums": + MessageLookupByLibrary.simpleMessage("Gagal memuat album"), + "failedToRenew": + MessageLookupByLibrary.simpleMessage("Gagal memperpanjang"), + "failedToVerifyPaymentStatus": MessageLookupByLibrary.simpleMessage( + "Gagal memeriksa status pembayaran"), + "familyPlanOverview": MessageLookupByLibrary.simpleMessage( + "Tambahkan 5 anggota keluarga ke paket kamu tanpa perlu bayar lebih.\n\nSetiap anggota mendapat ruang pribadi mereka sendiri, dan tidak dapat melihat file orang lain kecuali dibagikan.\n\nPaket keluarga tersedia bagi pelanggan yang memiliki langganan berbayar Ente.\n\nLangganan sekarang untuk mulai!"), + "familyPlanPortalTitle": + MessageLookupByLibrary.simpleMessage("Keluarga"), + "familyPlans": MessageLookupByLibrary.simpleMessage("Paket keluarga"), + "faq": MessageLookupByLibrary.simpleMessage("Tanya Jawab Umum"), + "faqs": MessageLookupByLibrary.simpleMessage("Tanya Jawab Umum"), + "feedback": MessageLookupByLibrary.simpleMessage("Masukan"), + "fileFailedToSaveToGallery": MessageLookupByLibrary.simpleMessage( + "Gagal menyimpan file ke galeri"), + "fileInfoAddDescHint": + MessageLookupByLibrary.simpleMessage("Tambahkan keterangan..."), + "fileSavedToGallery": + MessageLookupByLibrary.simpleMessage("File tersimpan ke galeri"), + "fileTypes": MessageLookupByLibrary.simpleMessage("Jenis file"), + "fileTypesAndNames": + MessageLookupByLibrary.simpleMessage("Nama dan jenis file"), + "filesBackedUpFromDevice": m27, + "filesBackedUpInAlbum": m28, + "filesDeleted": MessageLookupByLibrary.simpleMessage("File terhapus"), + "filesSavedToGallery": + MessageLookupByLibrary.simpleMessage("File tersimpan ke galeri"), + "findPeopleByName": MessageLookupByLibrary.simpleMessage( + "Telusuri orang dengan mudah menggunakan nama"), + "flip": MessageLookupByLibrary.simpleMessage("Balik"), + "forYourMemories": + MessageLookupByLibrary.simpleMessage("untuk kenanganmu"), + "forgotPassword": MessageLookupByLibrary.simpleMessage("Lupa sandi"), + "foundFaces": + MessageLookupByLibrary.simpleMessage("Wajah yang ditemukan"), + "freeStorageClaimed": + MessageLookupByLibrary.simpleMessage("Kuota gratis diperoleh"), + "freeStorageOnReferralSuccess": m29, + "freeStorageUsable": MessageLookupByLibrary.simpleMessage( + "Kuota gratis yang dapat digunakan"), + "freeTrial": MessageLookupByLibrary.simpleMessage("Percobaan gratis"), + "freeTrialValidTill": m30, + "freeUpAccessPostDelete": m31, + "freeUpAmount": m32, + "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage( + "Bersihkan penyimpanan perangkat"), + "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( + "Hemat ruang penyimpanan di perangkatmu dengan membersihkan file yang sudah tercadangkan."), + "freeUpSpace": MessageLookupByLibrary.simpleMessage("Bersihkan ruang"), + "freeUpSpaceSaving": m33, + "general": MessageLookupByLibrary.simpleMessage("Umum"), + "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( + "Menghasilkan kunci enkripsi..."), + "genericProgress": m34, + "goToSettings": MessageLookupByLibrary.simpleMessage("Buka pengaturan"), + "googlePlayId": MessageLookupByLibrary.simpleMessage("ID Google Play"), + "grantFullAccessPrompt": MessageLookupByLibrary.simpleMessage( + "Harap berikan akses ke semua foto di app Pengaturan"), + "grantPermission": MessageLookupByLibrary.simpleMessage("Berikan izin"), + "groupNearbyPhotos": MessageLookupByLibrary.simpleMessage( + "Kelompokkan foto yang berdekatan"), + "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( + "Dari mana Anda menemukan Ente? (opsional)"), + "help": MessageLookupByLibrary.simpleMessage("Bantuan"), + "hidden": MessageLookupByLibrary.simpleMessage("Tersembunyi"), + "hide": MessageLookupByLibrary.simpleMessage("Sembunyikan"), + "hiding": MessageLookupByLibrary.simpleMessage("Menyembunyikan..."), + "hostedAtOsmFrance": + MessageLookupByLibrary.simpleMessage("Dihosting oleh OSM France"), + "howItWorks": MessageLookupByLibrary.simpleMessage("Cara kerjanya"), + "howToViewShareeVerificationID": MessageLookupByLibrary.simpleMessage( + "Silakan minta dia untuk menekan lama alamat email-nya di layar pengaturan, dan pastikan bahwa ID di perangkatnya sama."), + "iOSGoToSettingsDescription": MessageLookupByLibrary.simpleMessage( + "Autentikasi biometrik belum aktif di perangkatmu. Silakan aktifkan Touch ID atau Face ID pada ponselmu."), + "iOSOkButton": MessageLookupByLibrary.simpleMessage("OK"), + "ignoreUpdate": MessageLookupByLibrary.simpleMessage("Abaikan"), + "ignoredFolderUploadReason": MessageLookupByLibrary.simpleMessage( + "Sejumlah file di album ini tidak terunggah karena telah dihapus sebelumnya dari Ente."), + "importing": MessageLookupByLibrary.simpleMessage("Mengimpor...."), + "incorrectCode": MessageLookupByLibrary.simpleMessage("Kode salah"), + "incorrectPasswordTitle": + MessageLookupByLibrary.simpleMessage("Sandi salah"), + "incorrectRecoveryKey": + MessageLookupByLibrary.simpleMessage("Kunci pemulihan salah"), + "incorrectRecoveryKeyBody": MessageLookupByLibrary.simpleMessage( + "Kunci pemulihan yang kamu masukkan salah"), + "incorrectRecoveryKeyTitle": + MessageLookupByLibrary.simpleMessage("Kunci pemulihan salah"), + "indexedItems": MessageLookupByLibrary.simpleMessage("Item terindeks"), + "indexingIsPaused": MessageLookupByLibrary.simpleMessage( + "Proses indeks dijeda, dan akan otomatis dilanjutkan saat perangkat siap."), + "insecureDevice": + MessageLookupByLibrary.simpleMessage("Perangkat tidak aman"), + "invalidEmailAddress": + MessageLookupByLibrary.simpleMessage("Alamat email tidak sah"), + "invalidEndpoint": + MessageLookupByLibrary.simpleMessage("Endpoint tidak sah"), + "invalidEndpointMessage": MessageLookupByLibrary.simpleMessage( + "Maaf, endpoint yang kamu masukkan tidak sah. Harap masukkan endpoint yang sah dan coba lagi."), + "invalidKey": MessageLookupByLibrary.simpleMessage("Kunci tidak sah"), + "invalidRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Kunci pemulihan yang kamu masukkan tidak sah. Pastikan kunci tersebut berisi 24 kata, dan teliti ejaan masing-masing kata.\n\nJika kamu memasukkan kode pemulihan lama, pastikan kode tersebut berisi 64 karakter, dan teliti setiap karakter yang ada."), + "invite": MessageLookupByLibrary.simpleMessage("Undang"), + "inviteToEnte": MessageLookupByLibrary.simpleMessage("Undang ke Ente"), + "inviteYourFriends": + MessageLookupByLibrary.simpleMessage("Undang teman-temanmu"), + "inviteYourFriendsToEnte": + MessageLookupByLibrary.simpleMessage("Undang temanmu ke Ente"), + "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": + MessageLookupByLibrary.simpleMessage( + "Sepertinya terjadi kesalahan. Silakan coba lagi setelah beberapa saat. Jika kesalahan terus terjadi, silakan hubungi tim dukungan kami."), + "itemCount": m35, + "itemsWillBeRemovedFromAlbum": MessageLookupByLibrary.simpleMessage( + "Item yang dipilih akan dihapus dari album ini"), + "joinDiscord": + MessageLookupByLibrary.simpleMessage("Bergabung ke Discord"), + "keepPhotos": MessageLookupByLibrary.simpleMessage("Simpan foto"), + "kiloMeterUnit": MessageLookupByLibrary.simpleMessage("km"), + "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( + "Harap bantu kami dengan informasi ini"), + "language": MessageLookupByLibrary.simpleMessage("Bahasa"), + "leave": MessageLookupByLibrary.simpleMessage("Tinggalkan"), + "leaveAlbum": MessageLookupByLibrary.simpleMessage("Tinggalkan album"), + "leaveFamily": + MessageLookupByLibrary.simpleMessage("Tinggalkan keluarga"), + "leaveSharedAlbum": + MessageLookupByLibrary.simpleMessage("Tinggalkan album bersama?"), + "left": MessageLookupByLibrary.simpleMessage("Kiri"), + "light": MessageLookupByLibrary.simpleMessage("Cahaya"), + "lightTheme": MessageLookupByLibrary.simpleMessage("Cerah"), + "linkCopiedToClipboard": + MessageLookupByLibrary.simpleMessage("Link tersalin ke papan klip"), + "linkDeviceLimit": + MessageLookupByLibrary.simpleMessage("Batas perangkat"), + "linkEnabled": MessageLookupByLibrary.simpleMessage("Aktif"), + "linkExpired": MessageLookupByLibrary.simpleMessage("Kedaluwarsa"), + "linkExpiresOn": m36, + "linkExpiry": + MessageLookupByLibrary.simpleMessage("Waktu kedaluwarsa link"), + "linkHasExpired": + MessageLookupByLibrary.simpleMessage("Link telah kedaluwarsa"), + "linkNeverExpires": + MessageLookupByLibrary.simpleMessage("Tidak pernah"), + "loadMessage1": MessageLookupByLibrary.simpleMessage( + "Kamu bisa membagikan langgananmu dengan keluarga"), + "loadMessage2": MessageLookupByLibrary.simpleMessage( + "Kami telah memelihara lebih dari 30 juta kenangan saat ini"), + "loadMessage3": MessageLookupByLibrary.simpleMessage( + "Kami menyimpan 3 salinan dari data kamu, salah satunya di tempat pengungsian bawah tanah"), + "loadMessage7": MessageLookupByLibrary.simpleMessage( + "App seluler kami berjalan di latar belakang untuk mengenkripsi dan mencadangkan foto yang kamu potret"), + "loadMessage8": MessageLookupByLibrary.simpleMessage( + "web.ente.io menyediakan alat pengunggah yang bagus"), + "loadMessage9": MessageLookupByLibrary.simpleMessage( + "Kami menggunakan Xchacha20Poly1305 untuk mengenkripsi data-mu dengan aman"), + "loadingExifData": + MessageLookupByLibrary.simpleMessage("Memuat data EXIF..."), + "loadingGallery": + MessageLookupByLibrary.simpleMessage("Memuat galeri..."), + "loadingMessage": + MessageLookupByLibrary.simpleMessage("Memuat fotomu..."), + "loadingModel": + MessageLookupByLibrary.simpleMessage("Mengunduh model..."), + "locationName": MessageLookupByLibrary.simpleMessage("Nama tempat"), + "lockButtonLabel": MessageLookupByLibrary.simpleMessage("Kunci"), + "logInLabel": MessageLookupByLibrary.simpleMessage("Masuk akun"), + "loggingOut": + MessageLookupByLibrary.simpleMessage("Mengeluarkan akun..."), + "loginSessionExpired": + MessageLookupByLibrary.simpleMessage("Sesi berakhir"), + "loginSessionExpiredDetails": MessageLookupByLibrary.simpleMessage( + "Sesi kamu telah berakhir. Silakan masuk akun kembali."), + "loginTerms": MessageLookupByLibrary.simpleMessage( + "Dengan mengklik masuk akun, saya menyetujui ketentuan layanan dan kebijakan privasi Ente"), + "logout": MessageLookupByLibrary.simpleMessage("Keluar akun"), + "longPressAnEmailToVerifyEndToEndEncryption": + MessageLookupByLibrary.simpleMessage( + "Tekan dan tahan email untuk membuktikan enkripsi ujung ke ujung."), + "lostDevice": MessageLookupByLibrary.simpleMessage("Perangkat hilang?"), + "machineLearning": + MessageLookupByLibrary.simpleMessage("Pemelajaran mesin"), + "magicSearch": + MessageLookupByLibrary.simpleMessage("Penelusuran ajaib"), + "manage": MessageLookupByLibrary.simpleMessage("Atur"), + "manageDeviceStorage": + MessageLookupByLibrary.simpleMessage("Atur penyimpanan perangkat"), + "manageFamily": MessageLookupByLibrary.simpleMessage("Atur Keluarga"), + "manageLink": MessageLookupByLibrary.simpleMessage("Atur link"), + "manageParticipants": MessageLookupByLibrary.simpleMessage("Atur"), + "manageSubscription": + MessageLookupByLibrary.simpleMessage("Atur langganan"), + "manualPairDesc": MessageLookupByLibrary.simpleMessage( + "Tautkan dengan PIN berfungsi di layar mana pun yang kamu inginkan."), + "map": MessageLookupByLibrary.simpleMessage("Peta"), + "maps": MessageLookupByLibrary.simpleMessage("Peta"), + "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), + "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), + "memoryCount": m0, + "mlConsent": + MessageLookupByLibrary.simpleMessage("Aktifkan pemelajaran mesin"), + "mlConsentConfirmation": MessageLookupByLibrary.simpleMessage( + "Saya memahami, dan bersedia mengaktifkan pemelajaran mesin"), + "mlConsentDescription": MessageLookupByLibrary.simpleMessage( + "Jika kamu mengaktifkan pemelajaran mesin, maka Ente akan mengambil informasi seperti geometri wajah dari berkas, termasuk berkas yg dibagikan kepada mu.\n\nIni akan dilakukan pada perangkat kamu, dan setiap informasi geometrik yang di buat akan ter enskripsi ujung ke ujung."), + "mlConsentPrivacy": MessageLookupByLibrary.simpleMessage( + "Klik di sini untuk detail lebih lanjut tentang fitur ini pada kebijakan privasi kami"), + "mlConsentTitle": + MessageLookupByLibrary.simpleMessage("Aktifkan pemelajaran mesin?"), + "mlIndexingDescription": MessageLookupByLibrary.simpleMessage( + "Harap diperhatikan bahwa pemelajaran mesin dapat meningkatkan penggunaan data dan baterai perangkat hingga seluruh items terindeks kan. Dianjurkan menggunakan aplikasi dekstop untuk pengindeksan lebih cepat, seluruh hasil akan tersinkronkan secara otomatis."), + "mobileWebDesktop": + MessageLookupByLibrary.simpleMessage("Seluler, Web, Desktop"), + "moderateStrength": MessageLookupByLibrary.simpleMessage("Sedang"), + "moments": MessageLookupByLibrary.simpleMessage("Momen"), + "monthly": MessageLookupByLibrary.simpleMessage("Bulanan"), + "moveItem": m37, + "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage( + "Pindahkan ke album tersembunyi"), + "movedSuccessfullyTo": m38, + "movedToTrash": + MessageLookupByLibrary.simpleMessage("Pindah ke sampah"), + "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( + "Memindahkan file ke album..."), + "networkConnectionRefusedErr": MessageLookupByLibrary.simpleMessage( + "Tidak dapat terhubung dengan Ente, silakan coba lagi setelah beberapa saat. Jika masalah berlanjut, harap hubungi dukungan."), + "networkHostLookUpErr": MessageLookupByLibrary.simpleMessage( + "Tidak dapat terhubung dengan Ente, harap periksa pengaturan jaringan kamu dan hubungi dukungan jika masalah berlanjut."), + "never": MessageLookupByLibrary.simpleMessage("Tidak pernah"), + "newAlbum": MessageLookupByLibrary.simpleMessage("Album baru"), + "no": MessageLookupByLibrary.simpleMessage("Tidak"), + "noAlbumsSharedByYouYet": MessageLookupByLibrary.simpleMessage( + "Belum ada album yang kamu bagikan"), + "noDeviceFound": + MessageLookupByLibrary.simpleMessage("Tidak ditemukan perangkat"), + "noDeviceLimit": MessageLookupByLibrary.simpleMessage("Tidak ada"), + "noDeviceThatCanBeDeleted": MessageLookupByLibrary.simpleMessage( + "Tidak ada file yang perlu dihapus dari perangkat ini"), + "noDuplicates": + MessageLookupByLibrary.simpleMessage("✨ Tak ada file duplikat"), + "noExifData": + MessageLookupByLibrary.simpleMessage("Tidak ada data EXIF"), + "noHiddenPhotosOrVideos": MessageLookupByLibrary.simpleMessage( + "Tidak ada foto atau video tersembunyi"), + "noInternetConnection": + MessageLookupByLibrary.simpleMessage("Tidak ada koneksi internet"), + "noPhotosFoundHere": + MessageLookupByLibrary.simpleMessage("Tidak ada foto di sini"), + "noRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Tidak punya kunci pemulihan?"), + "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( + "Karena sifat protokol enkripsi ujung ke ujung kami, data kamu tidak dapat didekripsi tanpa sandi atau kunci pemulihan kamu"), + "noResults": MessageLookupByLibrary.simpleMessage("Tidak ada hasil"), + "noResultsFound": + MessageLookupByLibrary.simpleMessage("Tidak ditemukan hasil"), + "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( + "Belum ada yang dibagikan denganmu"), + "nothingToSeeHere": MessageLookupByLibrary.simpleMessage( + "Tidak ada apa-apa di sini! 👀"), + "notifications": MessageLookupByLibrary.simpleMessage("Notifikasi"), + "ok": MessageLookupByLibrary.simpleMessage("Oke"), + "onDevice": MessageLookupByLibrary.simpleMessage("Di perangkat ini"), + "onEnte": MessageLookupByLibrary.simpleMessage( + "Di ente"), + "onlyFamilyAdminCanChangeCode": m40, + "oops": MessageLookupByLibrary.simpleMessage("Aduh"), + "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( + "Aduh, tidak dapat menyimpan perubahan"), + "oopsSomethingWentWrong": + MessageLookupByLibrary.simpleMessage("Aduh, terjadi kesalahan"), + "openSettings": MessageLookupByLibrary.simpleMessage("Buka Pengaturan"), + "openTheItem": MessageLookupByLibrary.simpleMessage("• Buka item-nya"), + "openstreetmapContributors": + MessageLookupByLibrary.simpleMessage("Kontributor OpenStreetMap"), + "optionalAsShortAsYouLike": MessageLookupByLibrary.simpleMessage( + "Opsional, pendek pun tak apa..."), + "orPickAnExistingOne": + MessageLookupByLibrary.simpleMessage("Atau pilih yang sudah ada"), + "pair": MessageLookupByLibrary.simpleMessage("Tautkan"), + "pairWithPin": + MessageLookupByLibrary.simpleMessage("Tautkan dengan PIN"), + "pairingComplete": + MessageLookupByLibrary.simpleMessage("Penautan berhasil"), + "passkey": MessageLookupByLibrary.simpleMessage("Passkey"), + "passkeyAuthTitle": + MessageLookupByLibrary.simpleMessage("Verifikasi passkey"), + "password": MessageLookupByLibrary.simpleMessage("Sandi"), + "passwordChangedSuccessfully": + MessageLookupByLibrary.simpleMessage("Sandi berhasil diubah"), + "passwordLock": + MessageLookupByLibrary.simpleMessage("Kunci dengan sandi"), + "passwordStrength": m41, + "passwordWarning": MessageLookupByLibrary.simpleMessage( + "Kami tidak menyimpan sandi ini, jadi jika kamu melupakannya, kami tidak akan bisa mendekripsi data kamu"), + "paymentDetails": + MessageLookupByLibrary.simpleMessage("Rincian pembayaran"), + "paymentFailed": + MessageLookupByLibrary.simpleMessage("Pembayaran gagal"), + "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( + "Sayangnya, pembayaranmu gagal. Silakan hubungi tim bantuan agar dapat kami bantu!"), + "pendingItems": MessageLookupByLibrary.simpleMessage("Item menunggu"), + "people": MessageLookupByLibrary.simpleMessage("Orang"), + "peopleUsingYourCode": MessageLookupByLibrary.simpleMessage( + "Orang yang telah menggunakan kodemu"), + "permDeleteWarning": MessageLookupByLibrary.simpleMessage( + "Semua item di sampah akan dihapus secara permanen\n\nTindakan ini tidak dapat dibatalkan"), + "permanentlyDelete": + MessageLookupByLibrary.simpleMessage("Hapus secara permanen"), + "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage( + "Hapus dari perangkat secara permanen?"), + "photoDescriptions": + MessageLookupByLibrary.simpleMessage("Keterangan foto"), + "photoGridSize": + MessageLookupByLibrary.simpleMessage("Ukuran kotak foto"), + "photoSmallCase": MessageLookupByLibrary.simpleMessage("foto"), + "photos": MessageLookupByLibrary.simpleMessage("Foto"), + "photosAddedByYouWillBeRemovedFromTheAlbum": + MessageLookupByLibrary.simpleMessage( + "Foto yang telah kamu tambahkan akan dihapus dari album ini"), + "playOnTv": MessageLookupByLibrary.simpleMessage("Putar album di TV"), + "playStoreFreeTrialValidTill": m43, + "pleaseCheckYourInternetConnectionAndTryAgain": + MessageLookupByLibrary.simpleMessage( + "Silakan periksa koneksi internet kamu, lalu coba lagi."), + "pleaseContactSupportAndWeWillBeHappyToHelp": + MessageLookupByLibrary.simpleMessage( + "Silakan hubungi support@ente.io dan kami akan dengan senang hati membantu!"), + "pleaseContactSupportIfTheProblemPersists": + MessageLookupByLibrary.simpleMessage( + "Silakan hubungi tim bantuan jika masalah terus terjadi"), + "pleaseEmailUsAt": m44, + "pleaseGrantPermissions": + MessageLookupByLibrary.simpleMessage("Harap berikan izin"), + "pleaseLoginAgain": + MessageLookupByLibrary.simpleMessage("Silakan masuk akun lagi"), + "pleaseSendTheLogsTo": m45, + "pleaseTryAgain": + MessageLookupByLibrary.simpleMessage("Silakan coba lagi"), + "pleaseVerifyTheCodeYouHaveEntered": + MessageLookupByLibrary.simpleMessage( + "Harap periksa kode yang kamu masukkan"), + "pleaseWait": MessageLookupByLibrary.simpleMessage("Harap tunggu..."), + "pleaseWaitDeletingAlbum": MessageLookupByLibrary.simpleMessage( + "Harap tunggu, sedang menghapus album"), + "pleaseWaitForSometimeBeforeRetrying": + MessageLookupByLibrary.simpleMessage( + "Harap tunggu beberapa saat sebelum mencoba lagi"), + "preparingLogs": + MessageLookupByLibrary.simpleMessage("Menyiapkan log..."), + "pressAndHoldToPlayVideo": MessageLookupByLibrary.simpleMessage( + "Tekan dan tahan untuk memutar video"), + "pressAndHoldToPlayVideoDetailed": MessageLookupByLibrary.simpleMessage( + "Tekan dan tahan gambar untuk memutar video"), + "privacy": MessageLookupByLibrary.simpleMessage("Privasi"), + "privacyPolicyTitle": + MessageLookupByLibrary.simpleMessage("Kebijakan Privasi"), + "privateBackups": + MessageLookupByLibrary.simpleMessage("Cadangan pribadi"), + "publicLinkCreated": + MessageLookupByLibrary.simpleMessage("Link publik dibuat"), + "publicLinkEnabled": + MessageLookupByLibrary.simpleMessage("Link publik aktif"), + "radius": MessageLookupByLibrary.simpleMessage("Radius"), + "rateTheApp": MessageLookupByLibrary.simpleMessage("Nilai app ini"), + "rateUsOnStore": m46, + "recover": MessageLookupByLibrary.simpleMessage("Pulihkan"), + "recoverAccount": MessageLookupByLibrary.simpleMessage("Pulihkan akun"), + "recoverButton": MessageLookupByLibrary.simpleMessage("Pulihkan"), + "recoveryKey": MessageLookupByLibrary.simpleMessage("Kunci pemulihan"), + "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( + "Kunci pemulihan tersalin ke papan klip"), + "recoveryKeyOnForgotPassword": MessageLookupByLibrary.simpleMessage( + "Saat kamu lupa sandi, satu-satunya cara untuk memulihkan data kamu adalah dengan kunci ini."), + "recoveryKeySaveDescription": MessageLookupByLibrary.simpleMessage( + "Kami tidak menyimpan kunci ini, jadi harap simpan kunci yang berisi 24 kata ini dengan aman."), + "recoveryKeySuccessBody": MessageLookupByLibrary.simpleMessage( + "Bagus! Kunci pemulihan kamu sah. Terima kasih telah melakukan verifikasi.\n\nHarap simpan selalu kunci pemulihan kamu dengan aman."), + "recoveryKeyVerified": MessageLookupByLibrary.simpleMessage( + "Kunci pemulihan terverifikasi"), + "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( + "Kunci pemulihan kamu adalah satu-satunya cara untuk memulihkan foto-foto kamu jika kamu lupa kata sandi. Kamu bisa lihat kunci pemulihan kamu di Pengaturan > Keamanan.\n\nHarap masukkan kunci pemulihan kamu di sini untuk memastikan bahwa kamu telah menyimpannya dengan baik."), + "recoverySuccessful": + MessageLookupByLibrary.simpleMessage("Pemulihan berhasil!"), + "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( + "Perangkat ini tidak cukup kuat untuk memverifikasi kata sandi kamu, tapi kami dapat membuat ulang kata sandi kamu sehingga dapat digunakan di semua perangkat.\n\nSilahkan masuk menggunakan kunci pemulihan dan buat ulang kata sandi kamu (Kamu dapat menggunakan kata sandi yang sama lagi jika mau)."), + "recreatePasswordTitle": + MessageLookupByLibrary.simpleMessage("Buat kembali kata sandi"), + "reddit": MessageLookupByLibrary.simpleMessage("Reddit"), + "referralStep1": MessageLookupByLibrary.simpleMessage( + "1. Berikan kode ini ke teman kamu"), + "referralStep2": MessageLookupByLibrary.simpleMessage( + "2. Ia perlu daftar ke paket berbayar"), + "referralStep3": m47, + "referralsAreCurrentlyPaused": + MessageLookupByLibrary.simpleMessage("Rujukan sedang dijeda"), + "remove": MessageLookupByLibrary.simpleMessage("Hapus"), + "removeDuplicates": + MessageLookupByLibrary.simpleMessage("Hapus duplikat"), + "removeDuplicatesDesc": MessageLookupByLibrary.simpleMessage( + "Lihat dan hapus file yang sama persis."), + "removeFromAlbum": + MessageLookupByLibrary.simpleMessage("Hapus dari album"), + "removeFromAlbumTitle": + MessageLookupByLibrary.simpleMessage("Hapus dari album?"), + "removeLink": MessageLookupByLibrary.simpleMessage("Hapus link"), + "removeParticipant": + MessageLookupByLibrary.simpleMessage("Hapus peserta"), + "removeParticipantBody": m48, + "removePersonLabel": + MessageLookupByLibrary.simpleMessage("Hapus label orang"), + "removePublicLink": + MessageLookupByLibrary.simpleMessage("Hapus link publik"), + "removeShareItemsWarning": MessageLookupByLibrary.simpleMessage( + "Beberapa item yang kamu hapus ditambahkan oleh orang lain, dan kamu akan kehilangan akses ke item tersebut"), + "removeWithQuestionMark": + MessageLookupByLibrary.simpleMessage("Hapus?"), + "removingFromFavorites": + MessageLookupByLibrary.simpleMessage("Menghapus dari favorit..."), + "rename": MessageLookupByLibrary.simpleMessage("Ubah nama"), + "renameAlbum": MessageLookupByLibrary.simpleMessage("Ubah nama album"), + "renameFile": MessageLookupByLibrary.simpleMessage("Ubah nama file"), + "renewSubscription": + MessageLookupByLibrary.simpleMessage("Perpanjang langganan"), + "renewsOn": m49, + "reportABug": MessageLookupByLibrary.simpleMessage("Laporkan bug"), + "reportBug": MessageLookupByLibrary.simpleMessage("Laporkan bug"), + "resendEmail": + MessageLookupByLibrary.simpleMessage("Kirim ulang email"), + "resetPasswordTitle": + MessageLookupByLibrary.simpleMessage("Atur ulang kata sandi"), + "restore": MessageLookupByLibrary.simpleMessage("Pulihkan"), + "restoringFiles": + MessageLookupByLibrary.simpleMessage("Memulihkan file..."), + "retry": MessageLookupByLibrary.simpleMessage("Coba lagi"), + "reviewDeduplicateItems": MessageLookupByLibrary.simpleMessage( + "Silakan lihat dan hapus item yang merupakan duplikat."), + "right": MessageLookupByLibrary.simpleMessage("Kanan"), + "rotate": MessageLookupByLibrary.simpleMessage("Putar"), + "rotateLeft": MessageLookupByLibrary.simpleMessage("Putar ke kiri"), + "rotateRight": MessageLookupByLibrary.simpleMessage("Putar ke kanan"), + "safelyStored": MessageLookupByLibrary.simpleMessage("Tersimpan aman"), + "save": MessageLookupByLibrary.simpleMessage("Simpan"), + "saveKey": MessageLookupByLibrary.simpleMessage("Simpan kunci"), + "saveYourRecoveryKeyIfYouHaventAlready": + MessageLookupByLibrary.simpleMessage( + "Jika belum, simpan kunci pemulihan kamu"), + "saving": MessageLookupByLibrary.simpleMessage("Menyimpan..."), + "savingEdits": + MessageLookupByLibrary.simpleMessage("Menyimpan edit..."), + "scanCode": MessageLookupByLibrary.simpleMessage("Pindai kode"), + "scanThisBarcodeWithnyourAuthenticatorApp": + MessageLookupByLibrary.simpleMessage( + "Pindai barcode ini dengan\napp autentikator kamu"), + "search": MessageLookupByLibrary.simpleMessage("Telusuri"), + "searchAlbumsEmptySection": + MessageLookupByLibrary.simpleMessage("Album"), + "searchByAlbumNameHint": + MessageLookupByLibrary.simpleMessage("Nama album"), + "searchByExamples": MessageLookupByLibrary.simpleMessage( + "• Nama album (cth. \"Kamera\")\n• Jenis file (cth. \"Video\", \".gif\")\n• Tahun atau bulan (cth. \"2022\", \"Januari\")\n• Musim liburan (cth. \"Natal\")\n• Keterangan foto (cth. “#seru”)"), + "searchCaptionEmptySection": MessageLookupByLibrary.simpleMessage( + "Tambah keterangan seperti \"#trip\" pada info foto agar mudah ditemukan di sini"), + "searchDatesEmptySection": MessageLookupByLibrary.simpleMessage( + "Telusuri dengan tanggal, bulan, atau tahun"), + "searchFaceEmptySection": MessageLookupByLibrary.simpleMessage( + "Orang akan ditampilkan di sini setelah pengindeksan selesai"), + "searchFileTypesAndNamesEmptySection": + MessageLookupByLibrary.simpleMessage("Nama dan jenis file"), + "searchHint2": + MessageLookupByLibrary.simpleMessage("Tanggal, keterangan foto"), + "searchHint3": + MessageLookupByLibrary.simpleMessage("Album, nama dan jenis file"), + "searchHint5": MessageLookupByLibrary.simpleMessage( + "Segera tiba: Penelusuran wajah & ajaib ✨"), + "searchResultCount": m50, + "security": MessageLookupByLibrary.simpleMessage("Keamanan"), + "selectALocation": MessageLookupByLibrary.simpleMessage("Pilih lokasi"), + "selectALocationFirst": MessageLookupByLibrary.simpleMessage( + "Pilih lokasi terlebih dahulu"), + "selectAlbum": MessageLookupByLibrary.simpleMessage("Pilih album"), + "selectAll": MessageLookupByLibrary.simpleMessage("Pilih semua"), + "selectFoldersForBackup": MessageLookupByLibrary.simpleMessage( + "Pilih folder yang perlu dicadangkan"), + "selectItemsToAdd": MessageLookupByLibrary.simpleMessage( + "Pilih item untuk ditambahkan"), + "selectLanguage": MessageLookupByLibrary.simpleMessage("Pilih Bahasa"), + "selectReason": MessageLookupByLibrary.simpleMessage("Pilih alasan"), + "selectYourPlan": + MessageLookupByLibrary.simpleMessage("Pilih paket kamu"), + "selectedFilesAreNotOnEnte": MessageLookupByLibrary.simpleMessage( + "File terpilih tidak tersimpan di Ente"), + "selectedFoldersWillBeEncryptedAndBackedUp": + MessageLookupByLibrary.simpleMessage( + "Folder yang terpilih akan dienkripsi dan dicadangkan"), + "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": + MessageLookupByLibrary.simpleMessage( + "Item terpilih akan dihapus dari semua album dan dipindahkan ke sampah."), + "selectedPhotos": m1, + "selectedPhotosWithYours": m51, + "send": MessageLookupByLibrary.simpleMessage("Kirim"), + "sendEmail": MessageLookupByLibrary.simpleMessage("Kirim email"), + "sendInvite": MessageLookupByLibrary.simpleMessage("Kirim undangan"), + "sendLink": MessageLookupByLibrary.simpleMessage("Kirim link"), + "serverEndpoint": + MessageLookupByLibrary.simpleMessage("Endpoint server"), + "setAPassword": MessageLookupByLibrary.simpleMessage("Atur sandi"), + "setAs": MessageLookupByLibrary.simpleMessage("Pasang sebagai"), + "setCover": MessageLookupByLibrary.simpleMessage("Ubah sampul"), + "setPasswordTitle": + MessageLookupByLibrary.simpleMessage("Buat kata sandi"), + "setupComplete": + MessageLookupByLibrary.simpleMessage("Penyiapan selesai"), + "share": MessageLookupByLibrary.simpleMessage("Bagikan"), + "shareALink": MessageLookupByLibrary.simpleMessage("Bagikan link"), + "shareAlbumHint": MessageLookupByLibrary.simpleMessage( + "Buka album lalu ketuk tombol bagikan di sudut kanan atas untuk berbagi."), + "shareAnAlbumNow": + MessageLookupByLibrary.simpleMessage("Bagikan album sekarang"), + "shareLink": MessageLookupByLibrary.simpleMessage("Bagikan link"), + "shareMyVerificationID": m52, + "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( + "Bagikan hanya dengan orang yang kamu inginkan"), + "shareTextConfirmOthersVerificationID": m2, + "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( + "Unduh Ente agar kita bisa berbagi foto dan video kualitas asli dengan mudah\n\nhttps://ente.io"), + "shareTextReferralCode": m53, + "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( + "Bagikan ke pengguna non-Ente"), + "shareWithPeopleSectionTitle": m54, + "shareYourFirstAlbum": + MessageLookupByLibrary.simpleMessage("Bagikan album pertamamu"), + "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( + "Buat album bersama dan kolaborasi dengan pengguna Ente lain, termasuk pengguna paket gratis."), + "sharedByMe": + MessageLookupByLibrary.simpleMessage("Dibagikan oleh saya"), + "sharedByYou": + MessageLookupByLibrary.simpleMessage("Dibagikan oleh kamu"), + "sharedPhotoNotifications": + MessageLookupByLibrary.simpleMessage("Foto terbagi baru"), + "sharedWith": m55, + "sharedWithMe": + MessageLookupByLibrary.simpleMessage("Dibagikan dengan saya"), + "sharedWithYou": + MessageLookupByLibrary.simpleMessage("Dibagikan dengan kamu"), + "sharing": MessageLookupByLibrary.simpleMessage("Membagikan..."), + "showMemories": MessageLookupByLibrary.simpleMessage("Lihat kenangan"), + "signOutFromOtherDevices": MessageLookupByLibrary.simpleMessage( + "Keluarkan akun dari perangkat lain"), + "signOutOtherBody": MessageLookupByLibrary.simpleMessage( + "Jika kamu merasa ada yang mengetahui sandimu, kamu bisa mengeluarkan akunmu secara paksa dari perangkat lain."), + "signOutOtherDevices": + MessageLookupByLibrary.simpleMessage("Keluar di perangkat lain"), + "signUpTerms": MessageLookupByLibrary.simpleMessage( + "Saya menyetujui ketentuan layanan dan kebijakan privasi Ente"), + "singleFileDeleteFromDevice": m56, + "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( + "Ia akan dihapus dari semua album."), + "singleFileInBothLocalAndRemote": m57, + "singleFileInRemoteOnly": m58, + "skip": MessageLookupByLibrary.simpleMessage("Lewati"), + "social": MessageLookupByLibrary.simpleMessage("Sosial"), + "someItemsAreInBothEnteAndYourDevice": + MessageLookupByLibrary.simpleMessage( + "Sejumlah item tersimpan di Ente serta di perangkat ini."), + "someoneSharingAlbumsWithYouShouldSeeTheSameId": + MessageLookupByLibrary.simpleMessage( + "Orang yang membagikan album denganmu bisa melihat ID yang sama di perangkat mereka."), + "somethingWentWrong": + MessageLookupByLibrary.simpleMessage("Terjadi kesalahan"), + "somethingWentWrongPleaseTryAgain": + MessageLookupByLibrary.simpleMessage( + "Terjadi kesalahan, silakan coba lagi"), + "sorry": MessageLookupByLibrary.simpleMessage("Maaf"), + "sorryCouldNotAddToFavorites": MessageLookupByLibrary.simpleMessage( + "Maaf, tidak dapat menambahkan ke favorit!"), + "sorryCouldNotRemoveFromFavorites": + MessageLookupByLibrary.simpleMessage( + "Maaf, tidak dapat menghapus dari favorit!"), + "sorryTheCodeYouveEnteredIsIncorrect": + MessageLookupByLibrary.simpleMessage( + "Maaf, kode yang kamu masukkan salah"), + "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": + MessageLookupByLibrary.simpleMessage( + "Maaf, kami tidak dapat menghasilkan kunci yang aman di perangkat ini.\n\nHarap mendaftar dengan perangkat lain."), + "sortAlbumsBy": + MessageLookupByLibrary.simpleMessage("Urut berdasarkan"), + "sortNewestFirst": MessageLookupByLibrary.simpleMessage("Terbaru dulu"), + "sortOldestFirst": MessageLookupByLibrary.simpleMessage("Terlama dulu"), + "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ Berhasil"), + "startBackup": + MessageLookupByLibrary.simpleMessage("Mulai pencadangan"), + "status": MessageLookupByLibrary.simpleMessage("Status"), + "stopCastingBody": MessageLookupByLibrary.simpleMessage( + "Apakah kamu ingin menghentikan transmisi?"), + "stopCastingTitle": + MessageLookupByLibrary.simpleMessage("Hentikan transmisi"), + "storage": MessageLookupByLibrary.simpleMessage("Penyimpanan"), + "storageBreakupFamily": + MessageLookupByLibrary.simpleMessage("Keluarga"), + "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Kamu"), + "storageInGB": m59, + "storageUsageInfo": m60, + "strongStrength": MessageLookupByLibrary.simpleMessage("Kuat"), + "subAlreadyLinkedErrMessage": m61, + "subWillBeCancelledOn": m62, + "subscribe": MessageLookupByLibrary.simpleMessage("Berlangganan"), + "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( + "Langgananmu telah berakhir. Silakan langganan kembali untuk berbagi."), + "subscription": MessageLookupByLibrary.simpleMessage("Langganan"), + "success": MessageLookupByLibrary.simpleMessage("Berhasil"), + "successfullyArchived": + MessageLookupByLibrary.simpleMessage("Berhasil diarsipkan"), + "successfullyHid": + MessageLookupByLibrary.simpleMessage("Berhasil disembunyikan"), + "successfullyUnarchived": MessageLookupByLibrary.simpleMessage( + "Berhasil dikeluarkan dari arsip"), + "suggestFeatures": + MessageLookupByLibrary.simpleMessage("Sarankan fitur"), + "support": MessageLookupByLibrary.simpleMessage("Dukungan"), + "syncStopped": + MessageLookupByLibrary.simpleMessage("Sinkronisasi terhenti"), + "syncing": MessageLookupByLibrary.simpleMessage("Menyinkronkan..."), + "systemTheme": MessageLookupByLibrary.simpleMessage("Sistem"), + "tapToCopy": MessageLookupByLibrary.simpleMessage("ketuk untuk salin"), + "tapToEnterCode": + MessageLookupByLibrary.simpleMessage("Ketuk untuk masukkan kode"), + "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( + "Sepertinya terjadi kesalahan. Silakan coba lagi setelah beberapa saat. Jika kesalahan terus terjadi, silakan hubungi tim dukungan kami."), + "terminate": MessageLookupByLibrary.simpleMessage("Akhiri"), + "terminateSession": + MessageLookupByLibrary.simpleMessage("Akhiri sesi?"), + "terms": MessageLookupByLibrary.simpleMessage("Ketentuan"), + "termsOfServicesTitle": + MessageLookupByLibrary.simpleMessage("Ketentuan"), + "thankYou": MessageLookupByLibrary.simpleMessage("Terima kasih"), + "thankYouForSubscribing": MessageLookupByLibrary.simpleMessage( + "Terima kasih telah berlangganan!"), + "theRecoveryKeyYouEnteredIsIncorrect": + MessageLookupByLibrary.simpleMessage( + "Kunci pemulihan yang kamu masukkan salah"), + "theme": MessageLookupByLibrary.simpleMessage("Tema"), + "theseItemsWillBeDeletedFromYourDevice": + MessageLookupByLibrary.simpleMessage( + "Item ini akan dihapus dari perangkat ini."), + "theyAlsoGetXGb": m64, + "thisActionCannotBeUndone": MessageLookupByLibrary.simpleMessage( + "Tindakan ini tidak dapat dibatalkan"), + "thisAlbumAlreadyHDACollaborativeLink": + MessageLookupByLibrary.simpleMessage( + "Link kolaborasi untuk album ini sudah terbuat"), + "thisCanBeUsedToRecoverYourAccountIfYou": + MessageLookupByLibrary.simpleMessage( + "Ini dapat digunakan untuk memulihkan akun kamu jika kehilangan faktor kedua kamu"), + "thisDevice": MessageLookupByLibrary.simpleMessage("Perangkat ini"), + "thisEmailIsAlreadyInUse": + MessageLookupByLibrary.simpleMessage("Email ini telah digunakan"), + "thisImageHasNoExifData": MessageLookupByLibrary.simpleMessage( + "Gambar ini tidak memiliki data exif"), + "thisIsPersonVerificationId": m65, + "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( + "Ini adalah ID Verifikasi kamu"), + "thisWillLogYouOutOfTheFollowingDevice": + MessageLookupByLibrary.simpleMessage( + "Ini akan mengeluarkan akunmu dari perangkat berikut:"), + "thisWillLogYouOutOfThisDevice": MessageLookupByLibrary.simpleMessage( + "Ini akan mengeluarkan akunmu dari perangkat ini!"), + "toHideAPhotoOrVideo": MessageLookupByLibrary.simpleMessage( + "Untuk menyembunyikan foto atau video"), + "toResetVerifyEmail": MessageLookupByLibrary.simpleMessage( + "Untuk mengatur ulang sandimu, harap verifikasi email kamu terlebih dahulu."), + "todaysLogs": MessageLookupByLibrary.simpleMessage("Log hari ini"), + "total": MessageLookupByLibrary.simpleMessage("jumlah total"), + "trash": MessageLookupByLibrary.simpleMessage("Sampah"), + "trashDaysLeft": m66, + "trim": MessageLookupByLibrary.simpleMessage("Pangkas"), + "tryAgain": MessageLookupByLibrary.simpleMessage("Coba lagi"), + "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( + "Aktifkan pencadangan untuk mengunggah file yang ditambahkan ke folder ini ke Ente secara otomatis."), + "twitter": MessageLookupByLibrary.simpleMessage("Twitter"), + "twoMonthsFreeOnYearlyPlans": MessageLookupByLibrary.simpleMessage( + "2 bulan gratis dengan paket tahunan"), + "twofactor": + MessageLookupByLibrary.simpleMessage("Autentikasi dua langkah"), + "twofactorAuthenticationHasBeenDisabled": + MessageLookupByLibrary.simpleMessage( + "Autentikasi dua langkah telah dinonaktifkan"), + "twofactorAuthenticationPageTitle": + MessageLookupByLibrary.simpleMessage("Autentikasi dua langkah"), + "twofactorAuthenticationSuccessfullyReset": + MessageLookupByLibrary.simpleMessage( + "Autentikasi dua langkah berhasil direset"), + "twofactorSetup": MessageLookupByLibrary.simpleMessage( + "Penyiapan autentikasi dua langkah"), + "unarchive": + MessageLookupByLibrary.simpleMessage("Keluarkan dari arsip"), + "unarchiveAlbum": + MessageLookupByLibrary.simpleMessage("Keluarkan album dari arsip"), + "unarchiving": + MessageLookupByLibrary.simpleMessage("Mengeluarkan dari arsip..."), + "unavailableReferralCode": MessageLookupByLibrary.simpleMessage( + "Maaf, kode ini tidak tersedia."), + "uncategorized": + MessageLookupByLibrary.simpleMessage("Tak Berkategori"), + "unlock": MessageLookupByLibrary.simpleMessage("Buka"), + "unselectAll": + MessageLookupByLibrary.simpleMessage("Batalkan semua pilihan"), + "update": MessageLookupByLibrary.simpleMessage("Perbarui"), + "updateAvailable": + MessageLookupByLibrary.simpleMessage("Pembaruan tersedia"), + "updatingFolderSelection": MessageLookupByLibrary.simpleMessage( + "Memperbaharui pilihan folder..."), + "uploadingFilesToAlbum": + MessageLookupByLibrary.simpleMessage("Mengunggah file ke album..."), + "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( + "Potongan hingga 50%, sampai 4 Des."), + "usableReferralStorageInfo": MessageLookupByLibrary.simpleMessage( + "Kuota yang dapat digunakan dibatasi oleh paket kamu saat ini. Kelebihan kuota yang diklaim, akan secara otomatis dapat digunakan saat kamu meningkatkan paket kamu."), + "usePublicLinksForPeopleNotOnEnte": + MessageLookupByLibrary.simpleMessage( + "Bagikan link publik ke orang yang tidak menggunakan Ente"), + "useRecoveryKey": + MessageLookupByLibrary.simpleMessage("Gunakan kunci pemulihan"), + "useSelectedPhoto": + MessageLookupByLibrary.simpleMessage("Gunakan foto terpilih"), + "validTill": m67, + "verificationFailedPleaseTryAgain": + MessageLookupByLibrary.simpleMessage( + "Verifikasi gagal, silakan coba lagi"), + "verificationId": MessageLookupByLibrary.simpleMessage("ID Verifikasi"), + "verify": MessageLookupByLibrary.simpleMessage("Verifikasi"), + "verifyEmail": MessageLookupByLibrary.simpleMessage("Verifikasi email"), + "verifyEmailID": m68, + "verifyPasskey": + MessageLookupByLibrary.simpleMessage("Verifikasi passkey"), + "verifyPassword": + MessageLookupByLibrary.simpleMessage("Verifikasi sandi"), + "verifyingRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Memverifikasi kunci pemulihan..."), + "videoSmallCase": MessageLookupByLibrary.simpleMessage("video"), + "videos": MessageLookupByLibrary.simpleMessage("Video"), + "viewActiveSessions": + MessageLookupByLibrary.simpleMessage("Lihat sesi aktif"), + "viewAll": MessageLookupByLibrary.simpleMessage("Lihat semua"), + "viewAllExifData": + MessageLookupByLibrary.simpleMessage("Lihat seluruh data EXIF"), + "viewLargeFiles": + MessageLookupByLibrary.simpleMessage("File berukuran besar"), + "viewLogs": MessageLookupByLibrary.simpleMessage("Lihat log"), + "viewRecoveryKey": + MessageLookupByLibrary.simpleMessage("Lihat kunci pemulihan"), + "viewer": MessageLookupByLibrary.simpleMessage("Pemirsa"), + "visitWebToManage": MessageLookupByLibrary.simpleMessage( + "Silakan buka web.ente.io untuk mengatur langgananmu"), + "waitingForVerification": + MessageLookupByLibrary.simpleMessage("Menunggu verifikasi..."), + "waitingForWifi": + MessageLookupByLibrary.simpleMessage("Menunggu WiFi..."), + "weHaveSendEmailTo": m69, + "weakStrength": MessageLookupByLibrary.simpleMessage("Lemah"), + "welcomeBack": + MessageLookupByLibrary.simpleMessage("Selamat datang kembali!"), + "whatsNew": MessageLookupByLibrary.simpleMessage("Hal yang baru"), + "yearly": MessageLookupByLibrary.simpleMessage("Tahunan"), + "yearsAgo": m70, + "yes": MessageLookupByLibrary.simpleMessage("Ya"), + "yesCancel": MessageLookupByLibrary.simpleMessage("Ya, batalkan"), + "yesConvertToViewer": + MessageLookupByLibrary.simpleMessage("Ya, ubah ke pemirsa"), + "yesDelete": MessageLookupByLibrary.simpleMessage("Ya, hapus"), + "yesDiscardChanges": + MessageLookupByLibrary.simpleMessage("Ya, buang perubahan"), + "yesLogout": MessageLookupByLibrary.simpleMessage("Ya, keluar"), + "yesRemove": MessageLookupByLibrary.simpleMessage("Ya, hapus"), + "yesRenew": MessageLookupByLibrary.simpleMessage("Ya, Perpanjang"), + "you": MessageLookupByLibrary.simpleMessage("Kamu"), + "youAreOnAFamilyPlan": MessageLookupByLibrary.simpleMessage( + "Kamu menggunakan paket keluarga!"), + "youAreOnTheLatestVersion": MessageLookupByLibrary.simpleMessage( + "Kamu menggunakan versi terbaru"), + "youCanAtMaxDoubleYourStorage": MessageLookupByLibrary.simpleMessage( + "* Maksimal dua kali lipat dari kuota penyimpananmu"), + "youCanManageYourLinksInTheShareTab": + MessageLookupByLibrary.simpleMessage( + "Kamu bisa atur link yang telah kamu buat di tab berbagi."), + "youCannotShareWithYourself": MessageLookupByLibrary.simpleMessage( + "Kamu tidak bisa berbagi dengan dirimu sendiri"), + "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( + "Kamu tidak memiliki item di arsip."), + "youHaveSuccessfullyFreedUp": m71, + "yourAccountHasBeenDeleted": + MessageLookupByLibrary.simpleMessage("Akunmu telah dihapus"), + "yourMap": MessageLookupByLibrary.simpleMessage("Peta kamu"), + "yourPurchaseWasSuccessful": + MessageLookupByLibrary.simpleMessage("Pembelianmu berhasil"), + "yourStorageDetailsCouldNotBeFetched": + MessageLookupByLibrary.simpleMessage( + "Rincian penyimpananmu tidak dapat dimuat"), + "yourSubscriptionHasExpired": + MessageLookupByLibrary.simpleMessage("Langgananmu telah berakhir"), + "yourSubscriptionWasUpdatedSuccessfully": + MessageLookupByLibrary.simpleMessage( + "Langgananmu telah berhasil diperbarui"), + "yourVerificationCodeHasExpired": MessageLookupByLibrary.simpleMessage( + "Kode verifikasi kamu telah kedaluwarsa"), + "zoomOutToSeePhotos": MessageLookupByLibrary.simpleMessage( + "Perkecil peta untuk melihat foto lainnya") + }; +} diff --git a/mobile/lib/generated/intl/messages_it.dart b/mobile/lib/generated/intl/messages_it.dart index e66ac02bc7..782eb147c5 100644 --- a/mobile/lib/generated/intl/messages_it.dart +++ b/mobile/lib/generated/intl/messages_it.dart @@ -20,34 +20,25 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'it'; - static String m0(count) => - "${Intl.plural(count, zero: 'Add collaborator', one: 'Add collaborator', other: 'Add collaborators')}"; - - static String m2(count) => + static String m4(count) => "${Intl.plural(count, one: 'Aggiungi elemento', other: 'Aggiungi elementi')}"; - static String m1(count) => - "${Intl.plural(count, zero: 'Add viewer', one: 'Add viewer', other: 'Add viewers')}"; + static String m7(emailOrName) => "Aggiunto da ${emailOrName}"; - static String m4(emailOrName) => "Aggiunto da ${emailOrName}"; + static String m8(albumName) => "Aggiunto con successo su ${albumName}"; - static String m5(albumName) => "Aggiunto con successo su ${albumName}"; - - static String m6(count) => + static String m9(count) => "${Intl.plural(count, zero: 'Nessun partecipante', one: '1 Partecipante', other: '${count} Partecipanti')}"; - static String m7(versionValue) => "Versione: ${versionValue}"; + static String m10(versionValue) => "Versione: ${versionValue}"; - static String m8(freeAmount, storageUnit) => - "${freeAmount} ${storageUnit} liberi"; - - static String m9(paymentProvider) => + static String m12(paymentProvider) => "Annulla prima il tuo abbonamento esistente da ${paymentProvider}"; - static String m10(user) => + static String m13(user) => "${user} non sarà più in grado di aggiungere altre foto a questo album\n\nSarà ancora in grado di rimuovere le foto esistenti aggiunte da lui o lei"; - static String m11(isFamilyMember, storageAmountInGb) => + static String m14(isFamilyMember, storageAmountInGb) => "${Intl.select(isFamilyMember, { 'true': 'Il tuo piano famiglia ha già richiesto ${storageAmountInGb} GB finora', @@ -55,106 +46,97 @@ class MessageLookup extends MessageLookupByLibrary { 'other': 'Hai già richiesto ${storageAmountInGb} GB finora!', })}"; - static String m12(albumName) => "Link collaborativo creato per ${albumName}"; + static String m15(albumName) => "Link collaborativo creato per ${albumName}"; - static String m13(familyAdminEmail) => + static String m16(familyAdminEmail) => "Contatta ${familyAdminEmail} per gestire il tuo abbonamento"; - static String m14(provider) => + static String m17(provider) => "Scrivi all\'indirizzo support@ente.io per gestire il tuo abbonamento ${provider}."; - static String m16(count) => + static String m19(count) => "${Intl.plural(count, one: 'Elimina ${count} elemento', other: 'Elimina ${count} elementi')}"; - static String m17(currentlyDeleting, totalCount) => + static String m20(currentlyDeleting, totalCount) => "Eliminazione di ${currentlyDeleting} / ${totalCount}"; - static String m18(albumName) => + static String m21(albumName) => "Questo rimuoverà il link pubblico per accedere a \"${albumName}\"."; - static String m19(supportEmail) => + static String m22(supportEmail) => "Per favore invia un\'email a ${supportEmail} dall\'indirizzo email con cui ti sei registrato"; - static String m20(count, storageSaved) => + static String m23(count, storageSaved) => "Hai ripulito ${Intl.plural(count, one: '${count} doppione', other: '${count} doppioni')}, salvando (${storageSaved}!)"; - static String m21(count, formattedSize) => + static String m24(count, formattedSize) => "${count} file, ${formattedSize} l\'uno"; - static String m22(newEmail) => "Email cambiata in ${newEmail}"; + static String m25(newEmail) => "Email cambiata in ${newEmail}"; - static String m23(email) => - "${email} non ha un account su ente.\n\nInvia un invito per condividere foto."; - - static String m24(count, formattedNumber) => + static String m27(count, formattedNumber) => "${Intl.plural(count, one: '1 file', other: '${formattedNumber} file')} di quest\'album sono stati salvati in modo sicuro"; - static String m25(count, formattedNumber) => + static String m28(count, formattedNumber) => "${Intl.plural(count, one: '1 file', other: '${formattedNumber} file')} di quest\'album sono stati salvati in modo sicuro"; - static String m26(storageAmountInGB) => + static String m29(storageAmountInGB) => "${storageAmountInGB} GB ogni volta che qualcuno si iscrive a un piano a pagamento e applica il tuo codice"; - static String m27(endDate) => "La prova gratuita termina il ${endDate}"; + static String m30(endDate) => "La prova gratuita termina il ${endDate}"; - static String m28(count) => + static String m31(count) => "Puoi ancora accedere a ${Intl.plural(count, one: '', other: 'loro')} su ente finché hai un abbonamento attivo"; - static String m29(sizeInMBorGB) => "Libera ${sizeInMBorGB}"; + static String m32(sizeInMBorGB) => "Libera ${sizeInMBorGB}"; - static String m30(count, formattedSize) => + static String m33(count, formattedSize) => "${Intl.plural(count, one: 'Può essere cancellata per liberare ${formattedSize}', other: 'Possono essere cancellati per liberare ${formattedSize}')}"; - static String m32(count) => + static String m35(count) => "${Intl.plural(count, one: '${count} elemento', other: '${count} elementi')}"; - static String m33(expiryTime) => "Il link scadrà il ${expiryTime}"; + static String m36(expiryTime) => "Il link scadrà il ${expiryTime}"; - static String m34(count, formattedCount) => + static String m0(count, formattedCount) => "${Intl.plural(count, one: '${formattedCount} ricordo', other: '${formattedCount} ricordi')}"; - static String m35(count) => + static String m37(count) => "${Intl.plural(count, one: 'Sposta elemento', other: 'Sposta elementi')}"; - static String m36(albumName) => "Spostato con successo su ${albumName}"; + static String m38(albumName) => "Spostato con successo su ${albumName}"; - static String m39(passwordStrengthValue) => + static String m41(passwordStrengthValue) => "Sicurezza password: ${passwordStrengthValue}"; - static String m40(providerName) => + static String m42(providerName) => "Si prega di parlare con il supporto di ${providerName} se ti è stato addebitato qualcosa"; - static String m41(endDate) => - "Prova gratuita valida fino al ${endDate}.\nPuoi scegliere un piano a pagamento in seguito."; + static String m44(toEmail) => "Per favore invia un\'email a ${toEmail}"; - static String m42(toEmail) => "Per favore invia un\'email a ${toEmail}"; + static String m45(toEmail) => "Invia i log a \n${toEmail}"; - static String m43(toEmail) => "Invia i log a \n${toEmail}"; + static String m46(storeName) => "Valutaci su ${storeName}"; - static String m44(storeName) => "Valutaci su ${storeName}"; - - static String m45(storageInGB) => + static String m47(storageInGB) => "3. Ottenete entrambi ${storageInGB} GB* gratis"; - static String m46(userEmail) => + static String m48(userEmail) => "${userEmail} verrà rimosso da questo album condiviso\n\nQualsiasi foto aggiunta dall\'utente verrà rimossa dall\'album"; - static String m47(endDate) => "Si rinnova il ${endDate}"; + static String m49(endDate) => "Si rinnova il ${endDate}"; - static String m49(count) => "${count} selezionati"; + static String m1(count) => "${count} selezionati"; - static String m50(count, yourCount) => + static String m51(count, yourCount) => "${count} selezionato (${yourCount} tuoi)"; - static String m51(verificationID) => + static String m52(verificationID) => "Ecco il mio ID di verifica: ${verificationID} per ente.io."; - static String m52(verificationID) => + static String m2(verificationID) => "Hey, puoi confermare che questo è il tuo ID di verifica: ${verificationID} su ente.io"; - static String m53(referralCode, referralStorageInGB) => - "ente referral code: ${referralCode} \n\nApplicalo in Impostazioni → Generale → Referral per ottenere ${referralStorageInGB} GB gratis dopo la registrazione di un piano a pagamento\n\nhttps://ente.io"; - static String m54(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Condividi con persone specifiche', one: 'Condividi con una persona', other: 'Condividi con ${numberOfPeople} persone')}"; @@ -163,20 +145,12 @@ class MessageLookup extends MessageLookupByLibrary { static String m56(fileType) => "Questo ${fileType} verrà eliminato dal tuo dispositivo."; - static String m57(fileType) => - "Questo ${fileType} è sia su ente che sul tuo dispositivo."; - - static String m58(fileType) => "Questo ${fileType} verrà eliminato su ente."; - static String m59(storageAmountInGB) => "${storageAmountInGB} GB"; static String m60( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} di ${totalAmount} ${totalStorageUnit} utilizzati"; - static String m61(id) => - "Il tuo ${id} è già collegato ad un altro account ente.\nSe desideri utilizzare il tuo ${id} con questo account, contatta il nostro supporto\'\'"; - static String m62(endDate) => "L\'abbonamento verrà cancellato il ${endDate}"; static String m63(completed, total) => @@ -205,8 +179,6 @@ class MessageLookup extends MessageLookupByLibrary { final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { - "aNewVersionOfEnteIsAvailable": MessageLookupByLibrary.simpleMessage( - "Una nuova versione di ente è disponibile."), "about": MessageLookupByLibrary.simpleMessage("Info"), "account": MessageLookupByLibrary.simpleMessage("Account"), "accountWelcomeBack": @@ -219,13 +191,13 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Aggiungi una nuova email"), "addCollaborator": MessageLookupByLibrary.simpleMessage("Aggiungi collaboratore"), - "addCollaborators": m0, "addFromDevice": MessageLookupByLibrary.simpleMessage("Aggiungi dal dispositivo"), - "addItem": m2, + "addItem": m4, "addLocation": MessageLookupByLibrary.simpleMessage("Aggiungi luogo"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Aggiungi"), "addMore": MessageLookupByLibrary.simpleMessage("Aggiungi altri"), + "addNew": MessageLookupByLibrary.simpleMessage("Aggiungi nuovo"), "addOnPageSubtitle": MessageLookupByLibrary.simpleMessage( "Dettagli dei componenti aggiuntivi"), "addOns": MessageLookupByLibrary.simpleMessage("Componenti aggiuntivi"), @@ -234,15 +206,13 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Aggiungi selezionate"), "addToAlbum": MessageLookupByLibrary.simpleMessage("Aggiungi all\'album"), - "addToEnte": MessageLookupByLibrary.simpleMessage("Aggiungi su ente"), "addToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Aggiungi ad album nascosto"), "addViewer": MessageLookupByLibrary.simpleMessage("Aggiungi in sola lettura"), - "addViewers": m1, "addedAs": MessageLookupByLibrary.simpleMessage("Aggiunto come"), - "addedBy": m4, - "addedSuccessfullyTo": m5, + "addedBy": m7, + "addedSuccessfullyTo": m8, "addingToFavorites": MessageLookupByLibrary.simpleMessage("Aggiunto ai preferiti..."), "advanced": MessageLookupByLibrary.simpleMessage("Avanzate"), @@ -254,7 +224,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Dopo una settimana"), "after1Year": MessageLookupByLibrary.simpleMessage("Dopo un anno"), "albumOwner": MessageLookupByLibrary.simpleMessage("Proprietario"), - "albumParticipantsCount": m6, + "albumParticipantsCount": m9, "albumTitle": MessageLookupByLibrary.simpleMessage("Titolo album"), "albumUpdated": MessageLookupByLibrary.simpleMessage("Album aggiornato"), @@ -291,10 +261,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Android, iOS, Web, Desktop"), "androidSignInTitle": MessageLookupByLibrary.simpleMessage("Autenticazione necessaria"), - "appLock": MessageLookupByLibrary.simpleMessage("App lock"), - "appLockDescriptions": MessageLookupByLibrary.simpleMessage( - "Choose between your device\'s default lock screen and a custom lock screen with a PIN or password."), - "appVersion": m7, + "appVersion": m10, "appleId": MessageLookupByLibrary.simpleMessage("Apple ID"), "apply": MessageLookupByLibrary.simpleMessage("Applica"), "applyCodeTitle": @@ -340,8 +307,6 @@ class MessageLookup extends MessageLookupByLibrary { "Autenticati per configurare l\'autenticazione a due fattori"), "authToInitiateAccountDeletion": MessageLookupByLibrary.simpleMessage( "Autenticati per avviare l\'eliminazione dell\'account"), - "authToViewPasskey": MessageLookupByLibrary.simpleMessage( - "Please authenticate to view your passkey"), "authToViewYourActiveSessions": MessageLookupByLibrary.simpleMessage( "Autenticati per visualizzare le sessioni attive"), "authToViewYourHiddenFiles": MessageLookupByLibrary.simpleMessage( @@ -357,11 +322,7 @@ class MessageLookup extends MessageLookupByLibrary { "Autenticazione non riuscita, prova di nuovo"), "authenticationSuccessful": MessageLookupByLibrary.simpleMessage("Autenticazione riuscita!"), - "autoLock": MessageLookupByLibrary.simpleMessage("Auto lock"), - "autoLockFeatureDescription": MessageLookupByLibrary.simpleMessage( - "Time after which the app locks after being put in the background"), "available": MessageLookupByLibrary.simpleMessage("Disponibile"), - "availableStorageSpace": m8, "backedUpFolders": MessageLookupByLibrary.simpleMessage("Cartelle salvate"), "backup": MessageLookupByLibrary.simpleMessage("Backup"), @@ -384,16 +345,16 @@ class MessageLookup extends MessageLookupByLibrary { "canOnlyRemoveFilesOwnedByYou": MessageLookupByLibrary.simpleMessage( "Puoi rimuovere solo i file di tua proprietà"), "cancel": MessageLookupByLibrary.simpleMessage("Annulla"), - "cancelOtherSubscription": m9, + "cancelOtherSubscription": m12, "cancelSubscription": MessageLookupByLibrary.simpleMessage("Annulla abbonamento"), - "cannotAddMorePhotosAfterBecomingViewer": m10, + "cannotAddMorePhotosAfterBecomingViewer": m13, "cannotDeleteSharedFiles": MessageLookupByLibrary.simpleMessage( "Impossibile eliminare i file condivisi"), "centerPoint": MessageLookupByLibrary.simpleMessage("Punto centrale"), "changeEmail": MessageLookupByLibrary.simpleMessage("Modifica email"), "changeLocationOfSelectedItems": MessageLookupByLibrary.simpleMessage( - "Change location of selected items?"), + "Cambiare la posizione degli elementi selezionati?"), "changePassword": MessageLookupByLibrary.simpleMessage("Cambia password"), "changePasswordTitle": @@ -406,26 +367,13 @@ class MessageLookup extends MessageLookupByLibrary { "Per favore, controlla la tua casella di posta (e lo spam) per completare la verifica"), "checking": MessageLookupByLibrary.simpleMessage("Controllo in corso..."), - "cl_guest_view_call_to_action": MessageLookupByLibrary.simpleMessage( - "Seleziona le foto e prova la \"Vista Ospite\"."), - "cl_guest_view_description": MessageLookupByLibrary.simpleMessage( - "Mostri le foto a un amico? Non preoccuparti che scorrano troppo lontano. La vista ospite bloccherà le foto che selezioni."), - "cl_guest_view_title": - MessageLookupByLibrary.simpleMessage("Vista Ospite"), - "cl_panorama_viewer_description": MessageLookupByLibrary.simpleMessage( - "Abbiamo aggiunto il supporto per visualizzare foto panoramiche con viste a 360 gradi. L\'esperienza è immersiva con la navigazione basata sul movimento!"), - "cl_panorama_viewer_title": - MessageLookupByLibrary.simpleMessage("Visualizzatore Panoramico"), - "cl_video_player_description": MessageLookupByLibrary.simpleMessage( - "Presentiamo un nuovo lettore video, con controlli di riproduzione migliorati e supporto per video HDR."), - "cl_video_player_title": - MessageLookupByLibrary.simpleMessage("Lettore Video"), "claimFreeStorage": MessageLookupByLibrary.simpleMessage("Richiedi spazio gratuito"), "claimMore": MessageLookupByLibrary.simpleMessage("Richiedine di più!"), "claimed": MessageLookupByLibrary.simpleMessage("Riscattato"), - "claimedStorageSoFar": m11, + "claimedStorageSoFar": m14, "clearCaches": MessageLookupByLibrary.simpleMessage("Svuota cache"), + "clearIndexes": MessageLookupByLibrary.simpleMessage("Cancella indici"), "click": MessageLookupByLibrary.simpleMessage("• Clic"), "clickOnTheOverflowMenu": MessageLookupByLibrary.simpleMessage("• Fai clic sul menu"), @@ -434,19 +382,15 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Club per tempo di cattura"), "clubByFileName": MessageLookupByLibrary.simpleMessage("Unisci per nome file"), - "clusteringProgress": - MessageLookupByLibrary.simpleMessage("Clustering progress"), "codeAppliedPageTitle": MessageLookupByLibrary.simpleMessage("Codice applicato"), "codeCopiedToClipboard": MessageLookupByLibrary.simpleMessage( "Codice copiato negli appunti"), "codeUsedByYou": MessageLookupByLibrary.simpleMessage("Codice utilizzato da te"), - "collabLinkSectionDescription": MessageLookupByLibrary.simpleMessage( - "Crea un link per consentire alle persone di aggiungere e visualizzare foto nel tuo album condiviso senza bisogno di un\'applicazione o di un account ente. Ottimo per raccogliere foto di un evento."), "collaborativeLink": MessageLookupByLibrary.simpleMessage("Link collaborativo"), - "collaborativeLinkCreatedFor": m12, + "collaborativeLinkCreatedFor": m15, "collaborator": MessageLookupByLibrary.simpleMessage("Collaboratore"), "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": MessageLookupByLibrary.simpleMessage( @@ -474,11 +418,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Conferma chiave di recupero"), "confirmYourRecoveryKey": MessageLookupByLibrary.simpleMessage( "Conferma la tua chiave di recupero"), - "contactFamilyAdmin": m13, + "contactFamilyAdmin": m16, "contactSupport": MessageLookupByLibrary.simpleMessage("Contatta il supporto"), - "contactToManageSubscription": m14, - "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), + "contactToManageSubscription": m17, + "contacts": MessageLookupByLibrary.simpleMessage("Contatti"), "continueLabel": MessageLookupByLibrary.simpleMessage("Continua"), "continueOnFreeTrial": MessageLookupByLibrary.simpleMessage("Continua la prova gratuita"), @@ -503,8 +447,6 @@ class MessageLookup extends MessageLookupByLibrary { "createAccount": MessageLookupByLibrary.simpleMessage("Crea account"), "createAlbumActionHint": MessageLookupByLibrary.simpleMessage( "Premi a lungo per selezionare le foto e fai clic su + per creare un album"), - "createCollaborativeLink": - MessageLookupByLibrary.simpleMessage("Create collaborative link"), "createCollage": MessageLookupByLibrary.simpleMessage("Crea un collage"), "createNewAccount": @@ -541,8 +483,6 @@ class MessageLookup extends MessageLookupByLibrary { "deleteAlbumsDialogBody": MessageLookupByLibrary.simpleMessage( "Questo eliminerà tutti gli album vuoti. È utile quando si desidera ridurre l\'ingombro nella lista degli album."), "deleteAll": MessageLookupByLibrary.simpleMessage("Elimina tutto"), - "deleteConfirmDialogBody": MessageLookupByLibrary.simpleMessage( - "Questo account è collegato ad altre app di ente, se ne utilizzi.\\n\\nI tuoi dati caricati, su tutte le app di ente, saranno pianificati per la cancellazione e il tuo account verrà eliminato definitivamente."), "deleteEmailRequest": MessageLookupByLibrary.simpleMessage( "Invia un\'email a account-deletion@ente.io dal tuo indirizzo email registrato."), "deleteEmptyAlbums": @@ -553,13 +493,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Elimina da entrambi"), "deleteFromDevice": MessageLookupByLibrary.simpleMessage("Elimina dal dispositivo"), - "deleteFromEnte": - MessageLookupByLibrary.simpleMessage("Elimina da ente"), - "deleteItemCount": m16, + "deleteItemCount": m19, "deleteLocation": MessageLookupByLibrary.simpleMessage("Elimina posizione"), "deletePhotos": MessageLookupByLibrary.simpleMessage("Elimina foto"), - "deleteProgress": m17, + "deleteProgress": m20, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Manca una caratteristica chiave di cui ho bisogno"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -574,17 +512,11 @@ class MessageLookup extends MessageLookupByLibrary { "Eliminare l\'album condiviso?"), "deleteSharedAlbumDialogBody": MessageLookupByLibrary.simpleMessage( "L\'album verrà eliminato per tutti\n\nPerderai l\'accesso alle foto condivise in questo album che sono di proprietà di altri"), - "descriptions": MessageLookupByLibrary.simpleMessage("Descriptions"), "deselectAll": MessageLookupByLibrary.simpleMessage("Deseleziona tutti"), "designedToOutlive": MessageLookupByLibrary.simpleMessage("Progettato per sopravvivere"), "details": MessageLookupByLibrary.simpleMessage("Dettagli"), - "deviceFilesAutoUploading": MessageLookupByLibrary.simpleMessage( - "I file aggiunti in questa cartella del dispositivo verranno automaticamente caricati su ente."), - "deviceLock": MessageLookupByLibrary.simpleMessage("Device lock"), - "deviceLockExplanation": MessageLookupByLibrary.simpleMessage( - "Disabilita il blocco schermo del dispositivo quando ente è in primo piano e c\'è un backup in corso. Questo normalmente non è necessario, ma può aiutare durante grossi caricamenti e le importazioni iniziali di grandi librerie si completano più velocemente."), "didYouKnow": MessageLookupByLibrary.simpleMessage("Lo sapevi che?"), "disableAutoLock": MessageLookupByLibrary.simpleMessage( "Disabilita blocco automatico"), @@ -592,7 +524,7 @@ class MessageLookup extends MessageLookupByLibrary { "I visualizzatori possono scattare screenshot o salvare una copia delle foto utilizzando strumenti esterni"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Nota bene"), - "disableLinkMessage": m18, + "disableLinkMessage": m21, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Disabilita autenticazione a due fattori"), "disablingTwofactorAuthentication": @@ -601,6 +533,7 @@ class MessageLookup extends MessageLookupByLibrary { "discord": MessageLookupByLibrary.simpleMessage("Discord"), "dismiss": MessageLookupByLibrary.simpleMessage("Ignora"), "distanceInKMUnit": MessageLookupByLibrary.simpleMessage("km"), + "doNotSignOut": MessageLookupByLibrary.simpleMessage("Non uscire"), "doThisLater": MessageLookupByLibrary.simpleMessage("In seguito"), "doYouWantToDiscardTheEditsYouHaveMade": MessageLookupByLibrary.simpleMessage( @@ -613,21 +546,20 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Scaricamento fallito"), "downloading": MessageLookupByLibrary.simpleMessage("Scaricamento in corso..."), - "dropSupportEmail": m19, - "duplicateFileCountWithStorageSaved": m20, - "duplicateItemsGroup": m21, + "dropSupportEmail": m22, + "duplicateFileCountWithStorageSaved": m23, + "duplicateItemsGroup": m24, "edit": MessageLookupByLibrary.simpleMessage("Modifica"), - "editLocation": MessageLookupByLibrary.simpleMessage("Edit location"), + "editLocation": MessageLookupByLibrary.simpleMessage("Modifica luogo"), "editLocationTagTitle": MessageLookupByLibrary.simpleMessage("Modifica luogo"), "editsSaved": MessageLookupByLibrary.simpleMessage("Modifiche salvate"), "editsToLocationWillOnlyBeSeenWithinEnte": MessageLookupByLibrary.simpleMessage( - "Edits to location will only be seen within Ente"), + "Le modifiche alla posizione saranno visibili solo all\'interno di Ente"), "eligible": MessageLookupByLibrary.simpleMessage("idoneo"), "email": MessageLookupByLibrary.simpleMessage("Email"), - "emailChangedTo": m22, - "emailNoEnteAccount": m23, + "emailChangedTo": m25, "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("Verifica Email"), "emailYourLogs": MessageLookupByLibrary.simpleMessage( @@ -645,13 +577,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Chiavi di crittografia"), "endtoendEncryptedByDefault": MessageLookupByLibrary.simpleMessage("Crittografia end-to-end"), - "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": - MessageLookupByLibrary.simpleMessage( - "ente può criptare e preservare i file solo se concedi l\'accesso alle foto e ai video"), - "entePhotosPerm": MessageLookupByLibrary.simpleMessage( - "ente necessita del permesso per preservare le tue foto"), - "enteSubscriptionPitch": MessageLookupByLibrary.simpleMessage( - "ente conserva i tuoi ricordi, in modo che siano sempre a disposizione, anche se perdi il dispositivo."), "enteSubscriptionShareWithFamily": MessageLookupByLibrary.simpleMessage( "Aggiungi la tua famiglia al tuo piano."), "enterAlbumName": MessageLookupByLibrary.simpleMessage( @@ -668,9 +593,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Inserisci password"), "enterPasswordToEncrypt": MessageLookupByLibrary.simpleMessage( "Inserisci una password per criptare i tuoi dati"), - "enterPersonName": - MessageLookupByLibrary.simpleMessage("Enter person name"), - "enterPin": MessageLookupByLibrary.simpleMessage("Enter PIN"), "enterReferralCode": MessageLookupByLibrary.simpleMessage( "Inserisci il codice di invito"), "enterThe6digitCodeFromnyourAuthenticatorApp": @@ -692,8 +614,6 @@ class MessageLookup extends MessageLookupByLibrary { "Questo link è scaduto. Si prega di selezionare un nuovo orario di scadenza o disabilitare la scadenza del link."), "exportLogs": MessageLookupByLibrary.simpleMessage("Esporta log"), "exportYourData": MessageLookupByLibrary.simpleMessage("Esporta dati"), - "faceRecognition": - MessageLookupByLibrary.simpleMessage("Face recognition"), "failedToApplyCode": MessageLookupByLibrary.simpleMessage( "Impossibile applicare il codice"), "failedToCancel": @@ -710,8 +630,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Rinnovo fallito"), "failedToVerifyPaymentStatus": MessageLookupByLibrary.simpleMessage( "Impossibile verificare lo stato del pagamento"), - "familyPlanOverview": MessageLookupByLibrary.simpleMessage( - "Aggiungi 5 membri della famiglia al tuo piano esistente senza pagare extra.\n\nOgni membro ottiene il proprio spazio privato e non può vedere i file dell\'altro a meno che non siano condivisi.\n\nI piani familiari sono disponibili per i clienti che hanno un abbonamento ente a pagamento.\n\nIscriviti ora per iniziare!"), "familyPlanPortalTitle": MessageLookupByLibrary.simpleMessage("Famiglia"), "familyPlans": MessageLookupByLibrary.simpleMessage("Piano famiglia"), @@ -725,28 +643,27 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Aggiungi descrizione..."), "fileSavedToGallery": MessageLookupByLibrary.simpleMessage("File salvato nella galleria"), - "filesBackedUpFromDevice": m24, - "filesBackedUpInAlbum": m25, + "filesBackedUpFromDevice": m27, + "filesBackedUpInAlbum": m28, "filesDeleted": MessageLookupByLibrary.simpleMessage("File eliminati"), "flip": MessageLookupByLibrary.simpleMessage("Capovolgi"), "forYourMemories": MessageLookupByLibrary.simpleMessage("per i tuoi ricordi"), "forgotPassword": MessageLookupByLibrary.simpleMessage("Password dimenticata"), - "foundFaces": MessageLookupByLibrary.simpleMessage("Found faces"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("Spazio gratuito richiesto"), - "freeStorageOnReferralSuccess": m26, + "freeStorageOnReferralSuccess": m29, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("Spazio libero utilizzabile"), "freeTrial": MessageLookupByLibrary.simpleMessage("Prova gratuita"), - "freeTrialValidTill": m27, - "freeUpAccessPostDelete": m28, - "freeUpAmount": m29, + "freeTrialValidTill": m30, + "freeUpAccessPostDelete": m31, + "freeUpAmount": m32, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("Libera spazio"), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Libera spazio"), - "freeUpSpaceSaving": m30, + "freeUpSpaceSaving": m33, "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Fino a 1000 ricordi mostrati nella galleria"), "general": MessageLookupByLibrary.simpleMessage("Generali"), @@ -761,20 +678,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Concedi il permesso"), "groupNearbyPhotos": MessageLookupByLibrary.simpleMessage( "Raggruppa foto nelle vicinanze"), - "guestView": MessageLookupByLibrary.simpleMessage("Guest view"), - "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( - "To enable guest view, please setup device passcode or screen lock in your system settings."), "hearUsExplanation": MessageLookupByLibrary.simpleMessage( "Non teniamo traccia del numero di installazioni dell\'app. Sarebbe utile se ci dicesse dove ci ha trovato!"), "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( "Come hai sentito parlare di Ente? (opzionale)"), "hidden": MessageLookupByLibrary.simpleMessage("Nascosti"), "hide": MessageLookupByLibrary.simpleMessage("Nascondi"), - "hideContent": MessageLookupByLibrary.simpleMessage("Hide content"), - "hideContentDescriptionAndroid": MessageLookupByLibrary.simpleMessage( - "Hides app content in the app switcher and disables screenshots"), - "hideContentDescriptionIos": MessageLookupByLibrary.simpleMessage( - "Hides app content in the app switcher"), "hiding": MessageLookupByLibrary.simpleMessage("Nascondendo..."), "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("Ospitato presso OSM France"), @@ -787,9 +696,6 @@ class MessageLookup extends MessageLookupByLibrary { "L\'autenticazione biometrica è disabilitata. Blocca e sblocca lo schermo per abilitarla."), "iOSOkButton": MessageLookupByLibrary.simpleMessage("OK"), "ignoreUpdate": MessageLookupByLibrary.simpleMessage("Ignora"), - "ignoredFolderUploadReason": MessageLookupByLibrary.simpleMessage( - "Alcuni file in questo album vengono ignorati dal caricamento perché erano stati precedentemente cancellati da ente."), - "immediately": MessageLookupByLibrary.simpleMessage("Immediately"), "importing": MessageLookupByLibrary.simpleMessage("Importazione in corso...."), "incorrectCode": @@ -802,8 +708,8 @@ class MessageLookup extends MessageLookupByLibrary { "Il codice che hai inserito non è corretto"), "incorrectRecoveryKeyTitle": MessageLookupByLibrary.simpleMessage("Chiave di recupero errata"), - "indexingIsPaused": MessageLookupByLibrary.simpleMessage( - "Indexing is paused, will automatically resume when device is ready"), + "indexedItems": + MessageLookupByLibrary.simpleMessage("Elementi indicizzati"), "insecureDevice": MessageLookupByLibrary.simpleMessage("Dispositivo non sicuro"), "installManually": @@ -814,21 +720,17 @@ class MessageLookup extends MessageLookupByLibrary { "invalidRecoveryKey": MessageLookupByLibrary.simpleMessage( "La chiave di recupero che hai inserito non è valida. Assicurati che contenga 24 parole e controlla l\'ortografia di ciascuna parola.\n\nSe hai inserito un vecchio codice di recupero, assicurati che sia lungo 64 caratteri e controlla ciascuno di essi."), "invite": MessageLookupByLibrary.simpleMessage("Invita"), - "inviteToEnte": MessageLookupByLibrary.simpleMessage("Invita su ente"), "inviteYourFriends": MessageLookupByLibrary.simpleMessage("Invita i tuoi amici"), - "inviteYourFriendsToEnte": - MessageLookupByLibrary.simpleMessage("Invita i tuoi amici a ente"), "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Sembra che qualcosa sia andato storto. Riprova tra un po\'. Se l\'errore persiste, contatta il nostro team di supporto."), - "itemCount": m32, + "itemCount": m35, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Gli elementi mostrano il numero di giorni rimanenti prima della cancellazione permanente"), "itemsWillBeRemovedFromAlbum": MessageLookupByLibrary.simpleMessage( "Gli elementi selezionati saranno rimossi da questo album"), - "joinDiscord": MessageLookupByLibrary.simpleMessage("Join Discord"), "keepPhotos": MessageLookupByLibrary.simpleMessage("Mantieni foto"), "kiloMeterUnit": MessageLookupByLibrary.simpleMessage("km"), "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( @@ -851,7 +753,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Limite dei dispositivi"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Attivato"), "linkExpired": MessageLookupByLibrary.simpleMessage("Scaduto"), - "linkExpiresOn": m33, + "linkExpiresOn": m36, "linkExpiry": MessageLookupByLibrary.simpleMessage("Scadenza del link"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("Il link è scaduto"), @@ -886,7 +788,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Nome della località"), "locationTagFeatureDescription": MessageLookupByLibrary.simpleMessage( "Un tag di localizzazione raggruppa tutte le foto scattate entro il raggio di una foto"), - "locations": MessageLookupByLibrary.simpleMessage("Locations"), "lockButtonLabel": MessageLookupByLibrary.simpleMessage("Blocca"), "lockscreen": MessageLookupByLibrary.simpleMessage("Schermata di blocco"), @@ -897,9 +798,6 @@ class MessageLookup extends MessageLookupByLibrary { "logout": MessageLookupByLibrary.simpleMessage("Disconnetti"), "logsDialogBody": MessageLookupByLibrary.simpleMessage( "Invia i log per aiutarci a risolvere il tuo problema. Si prega di notare che i nomi dei file saranno inclusi per aiutare a tenere traccia di problemi con file specifici."), - "longPressAnEmailToVerifyEndToEndEncryption": - MessageLookupByLibrary.simpleMessage( - "Long press an email to verify end to end encryption."), "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Premi a lungo su un elemento per visualizzarlo a schermo intero"), @@ -918,31 +816,30 @@ class MessageLookup extends MessageLookupByLibrary { "maps": MessageLookupByLibrary.simpleMessage("Mappe"), "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), - "memoryCount": m34, + "memoryCount": m0, "merchandise": MessageLookupByLibrary.simpleMessage("Merchandise"), "mobileWebDesktop": MessageLookupByLibrary.simpleMessage("Mobile, Web, Desktop"), "moderateStrength": MessageLookupByLibrary.simpleMessage("Mediocre"), - "modifyYourQueryOrTrySearchingFor": - MessageLookupByLibrary.simpleMessage( - "Modify your query, or try searching for"), "monthly": MessageLookupByLibrary.simpleMessage("Mensile"), - "moveItem": m35, + "moveItem": m37, "moveToAlbum": MessageLookupByLibrary.simpleMessage("Sposta nell\'album"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Sposta in album nascosto"), - "movedSuccessfullyTo": m36, + "movedSuccessfullyTo": m38, "movedToTrash": MessageLookupByLibrary.simpleMessage("Spostato nel cestino"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( "Spostamento dei file nell\'album..."), "name": MessageLookupByLibrary.simpleMessage("Nome"), + "networkConnectionRefusedErr": MessageLookupByLibrary.simpleMessage( + "Impossibile connettersi a Ente, riprova tra un po\' di tempo. Se l\'errore persiste, contatta l\'assistenza."), + "networkHostLookUpErr": MessageLookupByLibrary.simpleMessage( + "Impossibile connettersi a Ente, controlla le impostazioni di rete e contatta l\'assistenza se l\'errore persiste."), "never": MessageLookupByLibrary.simpleMessage("Mai"), "newAlbum": MessageLookupByLibrary.simpleMessage("Nuovo album"), - "newToEnte": MessageLookupByLibrary.simpleMessage("Nuovo utente"), "newest": MessageLookupByLibrary.simpleMessage("Più recenti"), - "next": MessageLookupByLibrary.simpleMessage("Next"), "no": MessageLookupByLibrary.simpleMessage("No"), "noAlbumsSharedByYouYet": MessageLookupByLibrary.simpleMessage( "Ancora nessun album condiviso da te"), @@ -956,13 +853,13 @@ class MessageLookup extends MessageLookupByLibrary { "Nessuna foto o video nascosti"), "noImagesWithLocation": MessageLookupByLibrary.simpleMessage( "Nessuna immagine con posizione"), + "noInternetConnection": MessageLookupByLibrary.simpleMessage( + "Nessuna connessione internet"), "noPhotosAreBeingBackedUpRightNow": MessageLookupByLibrary.simpleMessage( "Il backup delle foto attualmente non viene eseguito"), "noPhotosFoundHere": MessageLookupByLibrary.simpleMessage("Nessuna foto trovata"), - "noQuickLinksSelected": - MessageLookupByLibrary.simpleMessage("No quick links selected"), "noRecoveryKey": MessageLookupByLibrary.simpleMessage("Nessuna chiave di recupero?"), "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( @@ -970,8 +867,6 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Nessun risultato"), "noResultsFound": MessageLookupByLibrary.simpleMessage("Nessun risultato trovato"), - "noSystemLockFound": - MessageLookupByLibrary.simpleMessage("No system lock found"), "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( "Ancora nulla di condiviso con te"), "nothingToSeeHere": @@ -1001,16 +896,16 @@ class MessageLookup extends MessageLookupByLibrary { "Password modificata con successo"), "passwordLock": MessageLookupByLibrary.simpleMessage("Blocco con password"), - "passwordStrength": m39, - "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( - "Password strength is calculated considering the length of the password, used characters, and whether or not the password appears in the top 10,000 most used passwords"), + "passwordStrength": m41, "passwordWarning": MessageLookupByLibrary.simpleMessage( "Noi non memorizziamo la tua password, quindi se te la dimentichi, non possiamo decriptare i tuoi dati"), "paymentDetails": MessageLookupByLibrary.simpleMessage("Dettagli di Pagamento"), "paymentFailed": MessageLookupByLibrary.simpleMessage("Pagamento non riuscito"), - "paymentFailedTalkToProvider": m40, + "paymentFailedTalkToProvider": m42, + "pendingItems": + MessageLookupByLibrary.simpleMessage("Elementi in sospeso"), "pendingSync": MessageLookupByLibrary.simpleMessage("Sincronizzazione in sospeso"), "peopleUsingYourCode": MessageLookupByLibrary.simpleMessage( @@ -1030,24 +925,23 @@ class MessageLookup extends MessageLookupByLibrary { "pickCenterPoint": MessageLookupByLibrary.simpleMessage( "Selezionare il punto centrale"), "pinAlbum": MessageLookupByLibrary.simpleMessage("Fissa l\'album"), - "pinLock": MessageLookupByLibrary.simpleMessage("PIN lock"), - "playStoreFreeTrialValidTill": m41, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("Abbonamento su PlayStore"), + "pleaseCheckYourInternetConnectionAndTryAgain": + MessageLookupByLibrary.simpleMessage( + "Si prega di verificare la propria connessione Internet e riprovare."), "pleaseContactSupportAndWeWillBeHappyToHelp": MessageLookupByLibrary.simpleMessage( "Contatta support@ente.io e saremo felici di aiutarti!"), "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Riprova. Se il problema persiste, ti invitiamo a contattare l\'assistenza"), - "pleaseEmailUsAt": m42, + "pleaseEmailUsAt": m44, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage("Concedi i permessi"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage( "Effettua nuovamente l\'accesso"), - "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( - "Please select quick links to remove"), - "pleaseSendTheLogsTo": m43, + "pleaseSendTheLogsTo": m45, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Riprova"), "pleaseVerifyTheCodeYouHaveEntered": MessageLookupByLibrary.simpleMessage( @@ -1081,7 +975,7 @@ class MessageLookup extends MessageLookupByLibrary { "raiseTicket": MessageLookupByLibrary.simpleMessage("Invia ticket"), "rateTheApp": MessageLookupByLibrary.simpleMessage("Valuta l\'app"), "rateUs": MessageLookupByLibrary.simpleMessage("Lascia una recensione"), - "rateUsOnStore": m44, + "rateUsOnStore": m46, "recover": MessageLookupByLibrary.simpleMessage("Recupera"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Recupera account"), @@ -1107,16 +1001,13 @@ class MessageLookup extends MessageLookupByLibrary { "recreatePasswordTitle": MessageLookupByLibrary.simpleMessage("Reimposta password"), "reddit": MessageLookupByLibrary.simpleMessage("Reddit"), - "reenterPassword": - MessageLookupByLibrary.simpleMessage("Re-enter password"), - "reenterPin": MessageLookupByLibrary.simpleMessage("Re-enter PIN"), "referFriendsAnd2xYourPlan": MessageLookupByLibrary.simpleMessage( "Invita un amico e raddoppia il tuo spazio"), "referralStep1": MessageLookupByLibrary.simpleMessage( "1. Condividi questo codice con i tuoi amici"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Si iscrivono per un piano a pagamento"), - "referralStep3": m45, + "referralStep3": m47, "referrals": MessageLookupByLibrary.simpleMessage("Invita un Amico"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "I referral code sono attualmente in pausa"), @@ -1135,18 +1026,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Rimuovi dall\'album"), "removeFromAlbumTitle": MessageLookupByLibrary.simpleMessage("Rimuovi dall\'album?"), - "removeFromFavorite": - MessageLookupByLibrary.simpleMessage("Rimuovi dai preferiti"), "removeLink": MessageLookupByLibrary.simpleMessage("Elimina link"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Rimuovi partecipante"), - "removeParticipantBody": m46, - "removePersonLabel": - MessageLookupByLibrary.simpleMessage("Remove person label"), + "removeParticipantBody": m48, "removePublicLink": MessageLookupByLibrary.simpleMessage("Rimuovi link pubblico"), - "removePublicLinks": - MessageLookupByLibrary.simpleMessage("Remove public links"), "removeShareItemsWarning": MessageLookupByLibrary.simpleMessage( "Alcuni degli elementi che stai rimuovendo sono stati aggiunti da altre persone e ne perderai l\'accesso"), "removeWithQuestionMark": @@ -1158,7 +1043,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("Rinomina file"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Rinnova abbonamento"), - "renewsOn": m47, + "renewsOn": m49, "reportABug": MessageLookupByLibrary.simpleMessage("Segnala un bug"), "reportBug": MessageLookupByLibrary.simpleMessage("Segnala un bug"), "resendEmail": MessageLookupByLibrary.simpleMessage("Rinvia email"), @@ -1192,16 +1077,26 @@ class MessageLookup extends MessageLookupByLibrary { "scanThisBarcodeWithnyourAuthenticatorApp": MessageLookupByLibrary.simpleMessage( "Scansione questo codice QR\ncon la tua app di autenticazione"), - "search": MessageLookupByLibrary.simpleMessage("Search"), + "searchAlbumsEmptySection": + MessageLookupByLibrary.simpleMessage("Album"), "searchByAlbumNameHint": MessageLookupByLibrary.simpleMessage("Nome album"), "searchByExamples": MessageLookupByLibrary.simpleMessage( "• Nomi degli album (es. \"Camera\")\n• Tipi di file (es. \"Video\", \".gif\")\n• Anni e mesi (e.. \"2022\", \"gennaio\")\n• Vacanze (ad es. \"Natale\")\n• Descrizioni delle foto (ad es. “#mare”)"), + "searchDatesEmptySection": MessageLookupByLibrary.simpleMessage( + "Ricerca per data, mese o anno"), + "searchHint3": + MessageLookupByLibrary.simpleMessage("Album, nomi di file e tipi"), + "searchHint4": MessageLookupByLibrary.simpleMessage("Luogo"), + "searchLocationEmptySection": MessageLookupByLibrary.simpleMessage( + "Raggruppa foto scattate entro un certo raggio da una foto"), + "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage( + "Invita persone e vedrai qui tutte le foto condivise da loro"), "security": MessageLookupByLibrary.simpleMessage("Sicurezza"), "selectALocation": - MessageLookupByLibrary.simpleMessage("Select a location"), + MessageLookupByLibrary.simpleMessage("Seleziona un luogo"), "selectALocationFirst": - MessageLookupByLibrary.simpleMessage("Select a location first"), + MessageLookupByLibrary.simpleMessage("Scegli prima una posizione"), "selectAlbum": MessageLookupByLibrary.simpleMessage("Seleziona album"), "selectAll": MessageLookupByLibrary.simpleMessage("Seleziona tutto"), "selectFoldersForBackup": MessageLookupByLibrary.simpleMessage( @@ -1216,16 +1111,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Seleziona un motivo"), "selectYourPlan": MessageLookupByLibrary.simpleMessage("Seleziona un piano"), - "selectedFilesAreNotOnEnte": MessageLookupByLibrary.simpleMessage( - "I file selezionati non sono su ente"), "selectedFoldersWillBeEncryptedAndBackedUp": MessageLookupByLibrary.simpleMessage( "Le cartelle selezionate verranno crittografate e salvate su ente"), "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage( "Gli elementi selezionati verranno eliminati da tutti gli album e spostati nel cestino."), - "selectedPhotos": m49, - "selectedPhotosWithYours": m50, + "selectedPhotos": m1, + "selectedPhotosWithYours": m51, "send": MessageLookupByLibrary.simpleMessage("Invia"), "sendEmail": MessageLookupByLibrary.simpleMessage("Invia email"), "sendInvite": MessageLookupByLibrary.simpleMessage("Invita"), @@ -1237,9 +1130,6 @@ class MessageLookup extends MessageLookupByLibrary { "setAs": MessageLookupByLibrary.simpleMessage("Imposta come"), "setCover": MessageLookupByLibrary.simpleMessage("Imposta copertina"), "setLabel": MessageLookupByLibrary.simpleMessage("Imposta"), - "setNewPassword": - MessageLookupByLibrary.simpleMessage("Set new password"), - "setNewPin": MessageLookupByLibrary.simpleMessage("Set new PIN"), "setPasswordTitle": MessageLookupByLibrary.simpleMessage("Imposta password"), "setRadius": MessageLookupByLibrary.simpleMessage("Imposta raggio"), @@ -1252,20 +1142,13 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Condividi un album"), "shareLink": MessageLookupByLibrary.simpleMessage("Condividi link"), - "shareMyVerificationID": m51, + "shareMyVerificationID": m52, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Condividi solo con le persone che vuoi"), - "shareTextConfirmOthersVerificationID": m52, - "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( - "Scarica ente in modo da poter facilmente condividere foto e video senza perdita di qualità\n\nhttps://ente.io"), - "shareTextReferralCode": m53, - "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( - "Condividi con utenti che non hanno un account ente"), + "shareTextConfirmOthersVerificationID": m2, "shareWithPeopleSectionTitle": m54, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage( "Condividi il tuo primo album"), - "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( - "Crea album condivisi e collaborativi con altri utenti ente, inclusi utenti su piani gratuiti."), "sharedByMe": MessageLookupByLibrary.simpleMessage("Condiviso da me"), "sharedByYou": MessageLookupByLibrary.simpleMessage("Condivise da te"), "sharedPhotoNotifications": @@ -1280,18 +1163,19 @@ class MessageLookup extends MessageLookupByLibrary { "sharing": MessageLookupByLibrary.simpleMessage("Condivisione in corso..."), "showMemories": MessageLookupByLibrary.simpleMessage("Mostra ricordi"), + "signOutFromOtherDevices": MessageLookupByLibrary.simpleMessage( + "Esci dagli altri dispositivi"), + "signOutOtherBody": MessageLookupByLibrary.simpleMessage( + "Se pensi che qualcuno possa conoscere la tua password, puoi forzare tutti gli altri dispositivi che usano il tuo account ad uscire."), + "signOutOtherDevices": MessageLookupByLibrary.simpleMessage( + "Esci dagli altri dispositivi"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Accetto i termini di servizio e la politica sulla privacy"), "singleFileDeleteFromDevice": m56, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "Verrà eliminato da tutti gli album."), - "singleFileInBothLocalAndRemote": m57, - "singleFileInRemoteOnly": m58, "skip": MessageLookupByLibrary.simpleMessage("Salta"), "social": MessageLookupByLibrary.simpleMessage("Social"), - "someItemsAreInBothEnteAndYourDevice": - MessageLookupByLibrary.simpleMessage( - "Alcuni elementi sono sia su ente che sul tuo dispositivo."), "someOfTheFilesYouAreTryingToDeleteAre": MessageLookupByLibrary.simpleMessage( "Alcuni dei file che si sta tentando di eliminare sono disponibili solo sul dispositivo e non possono essere recuperati se cancellati"), @@ -1322,6 +1206,7 @@ class MessageLookup extends MessageLookupByLibrary { "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ Operazione riuscita"), "startBackup": MessageLookupByLibrary.simpleMessage("Avvia backup"), + "status": MessageLookupByLibrary.simpleMessage("Stato"), "storage": MessageLookupByLibrary.simpleMessage("Spazio di archiviazione"), "storageBreakupFamily": @@ -1332,7 +1217,6 @@ class MessageLookup extends MessageLookupByLibrary { "Limite d\'archiviazione superato"), "storageUsageInfo": m60, "strongStrength": MessageLookupByLibrary.simpleMessage("Forte"), - "subAlreadyLinkedErrMessage": m61, "subWillBeCancelledOn": m62, "subscribe": MessageLookupByLibrary.simpleMessage("Iscriviti"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( @@ -1359,7 +1243,6 @@ class MessageLookup extends MessageLookupByLibrary { "tapToCopy": MessageLookupByLibrary.simpleMessage("tocca per copiare"), "tapToEnterCode": MessageLookupByLibrary.simpleMessage( "Tocca per inserire il codice"), - "tapToUnlock": MessageLookupByLibrary.simpleMessage("Tap to unlock"), "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Sembra che qualcosa sia andato storto. Riprova tra un po\'. Se l\'errore persiste, contatta il nostro team di supporto."), "terminate": MessageLookupByLibrary.simpleMessage("Terminata"), @@ -1405,26 +1288,16 @@ class MessageLookup extends MessageLookupByLibrary { "Verrai disconnesso dai seguenti dispositivi:"), "thisWillLogYouOutOfThisDevice": MessageLookupByLibrary.simpleMessage( "Verrai disconnesso dal tuo dispositivo!"), - "thisWillRemovePublicLinksOfAllSelectedQuickLinks": - MessageLookupByLibrary.simpleMessage( - "This will remove public links of all selected quick links."), - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": - MessageLookupByLibrary.simpleMessage( - "To enable app lock, please setup device passcode or screen lock in your system settings."), "toHideAPhotoOrVideo": MessageLookupByLibrary.simpleMessage( "Per nascondere una foto o un video"), "toResetVerifyEmail": MessageLookupByLibrary.simpleMessage( "Per reimpostare la tua password, verifica prima la tua email."), "todaysLogs": MessageLookupByLibrary.simpleMessage("Log di oggi"), - "tooManyIncorrectAttempts": - MessageLookupByLibrary.simpleMessage("Too many incorrect attempts"), "total": MessageLookupByLibrary.simpleMessage("totale"), "totalSize": MessageLookupByLibrary.simpleMessage("Dimensioni totali"), "trash": MessageLookupByLibrary.simpleMessage("Cestino"), "trashDaysLeft": m66, "tryAgain": MessageLookupByLibrary.simpleMessage("Riprova"), - "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( - "Attiva il backup per caricare automaticamente i file aggiunti in questa cartella del dispositivo su ente."), "twitter": MessageLookupByLibrary.simpleMessage("Twitter"), "twoMonthsFreeOnYearlyPlans": MessageLookupByLibrary.simpleMessage( "2 mesi gratis sui piani annuali"), @@ -1470,9 +1343,6 @@ class MessageLookup extends MessageLookupByLibrary { "Caricamento dei file nell\'album..."), "usableReferralStorageInfo": MessageLookupByLibrary.simpleMessage( "Lo spazio disponibile è limitato dal tuo piano corrente. L\'archiviazione in eccesso diventerà automaticamente utilizzabile quando aggiornerai il tuo piano."), - "usePublicLinksForPeopleNotOnEnte": - MessageLookupByLibrary.simpleMessage( - "Usa link pubblici per persone non registrate su ente"), "useRecoveryKey": MessageLookupByLibrary.simpleMessage( "Utilizza un codice di recupero"), "useSelectedPhoto": @@ -1508,6 +1378,8 @@ class MessageLookup extends MessageLookupByLibrary { "viewer": MessageLookupByLibrary.simpleMessage("Sola lettura"), "visitWebToManage": MessageLookupByLibrary.simpleMessage( "Visita web.ente.io per gestire il tuo abbonamento"), + "waitingForWifi": + MessageLookupByLibrary.simpleMessage("In attesa del WiFi..."), "weAreOpenSource": MessageLookupByLibrary.simpleMessage("Siamo open source!"), "weDontSupportEditingPhotosAndAlbumsThatYouDont": @@ -1550,7 +1422,6 @@ class MessageLookup extends MessageLookupByLibrary { "youHaveSuccessfullyFreedUp": m71, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage( "Il tuo account è stato eliminato"), - "yourMap": MessageLookupByLibrary.simpleMessage("Your map"), "yourPlanWasSuccessfullyDowngraded": MessageLookupByLibrary.simpleMessage( "Il tuo piano è stato aggiornato con successo"), diff --git a/mobile/lib/generated/intl/messages_ja.dart b/mobile/lib/generated/intl/messages_ja.dart new file mode 100644 index 0000000000..a36e46602c --- /dev/null +++ b/mobile/lib/generated/intl/messages_ja.dart @@ -0,0 +1,25 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a ja locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'ja'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => {}; +} diff --git a/mobile/lib/generated/intl/messages_km.dart b/mobile/lib/generated/intl/messages_km.dart new file mode 100644 index 0000000000..22d4231361 --- /dev/null +++ b/mobile/lib/generated/intl/messages_km.dart @@ -0,0 +1,25 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a km locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'km'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => {}; +} diff --git a/mobile/lib/generated/intl/messages_ko.dart b/mobile/lib/generated/intl/messages_ko.dart index 0ce3e0bd49..e378d62fd9 100644 --- a/mobile/lib/generated/intl/messages_ko.dart +++ b/mobile/lib/generated/intl/messages_ko.dart @@ -20,104 +20,28 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'ko'; - static String m0(count) => - "${Intl.plural(count, zero: 'Add collaborator', one: 'Add collaborator', other: 'Add collaborators')}"; - - static String m1(count) => - "${Intl.plural(count, zero: 'Add viewer', one: 'Add viewer', other: 'Add viewers')}"; - final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { - "addCollaborators": m0, - "addToHiddenAlbum": - MessageLookupByLibrary.simpleMessage("Add to hidden album"), - "addViewers": m1, - "appLock": MessageLookupByLibrary.simpleMessage("App lock"), - "appLockDescriptions": MessageLookupByLibrary.simpleMessage( - "Choose between your device\'s default lock screen and a custom lock screen with a PIN or password."), - "authToViewPasskey": MessageLookupByLibrary.simpleMessage( - "Please authenticate to view your passkey"), - "autoLock": MessageLookupByLibrary.simpleMessage("Auto lock"), - "autoLockFeatureDescription": MessageLookupByLibrary.simpleMessage( - "Time after which the app locks after being put in the background"), - "changeLocationOfSelectedItems": MessageLookupByLibrary.simpleMessage( - "Change location of selected items?"), - "clusteringProgress": - MessageLookupByLibrary.simpleMessage("Clustering progress"), - "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), - "createCollaborativeLink": - MessageLookupByLibrary.simpleMessage("Create collaborative link"), - "deleteConfirmDialogBody": MessageLookupByLibrary.simpleMessage( - "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted."), - "descriptions": MessageLookupByLibrary.simpleMessage("Descriptions"), - "deviceLock": MessageLookupByLibrary.simpleMessage("Device lock"), - "editLocation": MessageLookupByLibrary.simpleMessage("Edit location"), - "editsToLocationWillOnlyBeSeenWithinEnte": - MessageLookupByLibrary.simpleMessage( - "Edits to location will only be seen within Ente"), - "enterPersonName": - MessageLookupByLibrary.simpleMessage("Enter person name"), - "enterPin": MessageLookupByLibrary.simpleMessage("Enter PIN"), - "faceRecognition": - MessageLookupByLibrary.simpleMessage("Face recognition"), - "fileTypes": MessageLookupByLibrary.simpleMessage("File types"), - "foundFaces": MessageLookupByLibrary.simpleMessage("Found faces"), - "guestView": MessageLookupByLibrary.simpleMessage("Guest view"), - "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( - "To enable guest view, please setup device passcode or screen lock in your system settings."), - "hideContent": MessageLookupByLibrary.simpleMessage("Hide content"), - "hideContentDescriptionAndroid": MessageLookupByLibrary.simpleMessage( - "Hides app content in the app switcher and disables screenshots"), - "hideContentDescriptionIos": MessageLookupByLibrary.simpleMessage( - "Hides app content in the app switcher"), - "immediately": MessageLookupByLibrary.simpleMessage("Immediately"), - "indexingIsPaused": MessageLookupByLibrary.simpleMessage( - "Indexing is paused, will automatically resume when device is ready"), - "joinDiscord": MessageLookupByLibrary.simpleMessage("Join Discord"), - "locations": MessageLookupByLibrary.simpleMessage("Locations"), - "longPressAnEmailToVerifyEndToEndEncryption": - MessageLookupByLibrary.simpleMessage( - "Long press an email to verify end to end encryption."), - "modifyYourQueryOrTrySearchingFor": - MessageLookupByLibrary.simpleMessage( - "Modify your query, or try searching for"), - "moveToHiddenAlbum": - MessageLookupByLibrary.simpleMessage("Move to hidden album"), - "next": MessageLookupByLibrary.simpleMessage("Next"), - "noQuickLinksSelected": - MessageLookupByLibrary.simpleMessage("No quick links selected"), - "noSystemLockFound": - MessageLookupByLibrary.simpleMessage("No system lock found"), - "passwordLock": MessageLookupByLibrary.simpleMessage("Password lock"), - "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( - "Password strength is calculated considering the length of the password, used characters, and whether or not the password appears in the top 10,000 most used passwords"), - "pinLock": MessageLookupByLibrary.simpleMessage("PIN lock"), - "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( - "Please select quick links to remove"), - "reenterPassword": - MessageLookupByLibrary.simpleMessage("Re-enter password"), - "reenterPin": MessageLookupByLibrary.simpleMessage("Re-enter PIN"), - "removePersonLabel": - MessageLookupByLibrary.simpleMessage("Remove person label"), - "removePublicLinks": - MessageLookupByLibrary.simpleMessage("Remove public links"), - "search": MessageLookupByLibrary.simpleMessage("Search"), - "selectALocation": - MessageLookupByLibrary.simpleMessage("Select a location"), - "selectALocationFirst": - MessageLookupByLibrary.simpleMessage("Select a location first"), - "setNewPassword": - MessageLookupByLibrary.simpleMessage("Set new password"), - "setNewPin": MessageLookupByLibrary.simpleMessage("Set new PIN"), - "tapToUnlock": MessageLookupByLibrary.simpleMessage("Tap to unlock"), - "thisWillRemovePublicLinksOfAllSelectedQuickLinks": - MessageLookupByLibrary.simpleMessage( - "This will remove public links of all selected quick links."), - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": - MessageLookupByLibrary.simpleMessage( - "To enable app lock, please setup device passcode or screen lock in your system settings."), - "tooManyIncorrectAttempts": - MessageLookupByLibrary.simpleMessage("Too many incorrect attempts"), - "yourMap": MessageLookupByLibrary.simpleMessage("Your map") + "accountWelcomeBack": + MessageLookupByLibrary.simpleMessage("다시 오신 것을 환영합니다!"), + "askDeleteReason": + MessageLookupByLibrary.simpleMessage("계정을 삭제하는 가장 큰 이유가 무엇인가요?"), + "cancel": MessageLookupByLibrary.simpleMessage("닫기"), + "confirmAccountDeletion": + MessageLookupByLibrary.simpleMessage("계정 삭제 확인"), + "deleteAccount": MessageLookupByLibrary.simpleMessage("계정 삭제"), + "deleteAccountPermanentlyButton": + MessageLookupByLibrary.simpleMessage("계정을 영구적으로 삭제"), + "email": MessageLookupByLibrary.simpleMessage("이메일"), + "enterValidEmail": + MessageLookupByLibrary.simpleMessage("올바른 이메일 주소를 입력하세요."), + "enterYourEmailAddress": + MessageLookupByLibrary.simpleMessage("이메일을 입력하세요"), + "feedback": MessageLookupByLibrary.simpleMessage("피드백"), + "invalidEmailAddress": + MessageLookupByLibrary.simpleMessage("잘못된 이메일 주소"), + "verify": MessageLookupByLibrary.simpleMessage("인증"), + "yourAccountHasBeenDeleted": + MessageLookupByLibrary.simpleMessage("계정이 삭제되었습니다.") }; } diff --git a/mobile/lib/generated/intl/messages_nl.dart b/mobile/lib/generated/intl/messages_nl.dart index 58088301a8..a33e630355 100644 --- a/mobile/lib/generated/intl/messages_nl.dart +++ b/mobile/lib/generated/intl/messages_nl.dart @@ -20,37 +20,37 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'nl'; - static String m0(count) => + static String m3(count) => "${Intl.plural(count, zero: 'Voeg samenwerker toe', one: 'Voeg samenwerker toe', other: 'Voeg samenwerkers toe')}"; - static String m2(count) => + static String m4(count) => "${Intl.plural(count, one: 'Bestand toevoegen', other: 'Bestanden toevoegen')}"; - static String m3(storageAmount, endDate) => + static String m5(storageAmount, endDate) => "Jouw ${storageAmount} add-on is geldig tot ${endDate}"; - static String m1(count) => + static String m6(count) => "${Intl.plural(count, one: 'Voeg kijker toe', other: 'Voeg kijkers toe')}"; - static String m4(emailOrName) => "Toegevoegd door ${emailOrName}"; + static String m7(emailOrName) => "Toegevoegd door ${emailOrName}"; - static String m5(albumName) => "Succesvol toegevoegd aan ${albumName}"; + static String m8(albumName) => "Succesvol toegevoegd aan ${albumName}"; - static String m6(count) => + static String m9(count) => "${Intl.plural(count, zero: 'Geen deelnemers', one: '1 deelnemer', other: '${count} deelnemers')}"; - static String m7(versionValue) => "Versie: ${versionValue}"; + static String m10(versionValue) => "Versie: ${versionValue}"; - static String m8(freeAmount, storageUnit) => + static String m11(freeAmount, storageUnit) => "${freeAmount} ${storageUnit} vrij"; - static String m9(paymentProvider) => + static String m12(paymentProvider) => "Annuleer eerst uw bestaande abonnement bij ${paymentProvider}"; - static String m10(user) => + static String m13(user) => "${user} zal geen foto\'s meer kunnen toevoegen aan dit album\n\nDe gebruiker zal nog steeds bestaande foto\'s kunnen verwijderen die door hen zijn toegevoegd"; - static String m11(isFamilyMember, storageAmountInGb) => + static String m14(isFamilyMember, storageAmountInGb) => "${Intl.select(isFamilyMember, { 'true': 'Jouw familie heeft ${storageAmountInGb} GB geclaimd tot nu toe', @@ -58,113 +58,116 @@ class MessageLookup extends MessageLookupByLibrary { 'other': 'Je hebt ${storageAmountInGb} GB geclaimd tot nu toe!', })}"; - static String m12(albumName) => + static String m15(albumName) => "Gezamenlijke link aangemaakt voor ${albumName}"; - static String m13(familyAdminEmail) => + static String m16(familyAdminEmail) => "Neem contact op met ${familyAdminEmail} om uw abonnement te beheren"; - static String m14(provider) => + static String m17(provider) => "Neem contact met ons op via support@ente.io om uw ${provider} abonnement te beheren."; - static String m15(endpoint) => "Verbonden met ${endpoint}"; + static String m18(endpoint) => "Verbonden met ${endpoint}"; - static String m16(count) => + static String m19(count) => "${Intl.plural(count, one: 'Verwijder ${count} bestand', other: 'Verwijder ${count} bestanden')}"; - static String m17(currentlyDeleting, totalCount) => + static String m20(currentlyDeleting, totalCount) => "Verwijderen van ${currentlyDeleting} / ${totalCount}"; - static String m18(albumName) => + static String m21(albumName) => "Dit verwijdert de openbare link voor toegang tot \"${albumName}\"."; - static String m19(supportEmail) => + static String m22(supportEmail) => "Stuur een e-mail naar ${supportEmail} vanaf het door jou geregistreerde e-mailadres"; - static String m20(count, storageSaved) => + static String m23(count, storageSaved) => "Je hebt ${Intl.plural(count, one: '${count} dubbel bestand', other: '${count} dubbele bestanden')} opgeruimd, totaal (${storageSaved}!)"; - static String m21(count, formattedSize) => + static String m24(count, formattedSize) => "${count} bestanden, elk ${formattedSize}"; - static String m22(newEmail) => "E-mailadres gewijzigd naar ${newEmail}"; + static String m25(newEmail) => "E-mailadres gewijzigd naar ${newEmail}"; - static String m23(email) => + static String m26(email) => "${email} heeft geen Ente account.\n\nStuur ze een uitnodiging om foto\'s te delen."; - static String m24(count, formattedNumber) => + static String m27(count, formattedNumber) => "${Intl.plural(count, one: '1 bestand', other: '${formattedNumber} bestanden')} in dit album zijn veilig geback-upt"; - static String m25(count, formattedNumber) => + static String m28(count, formattedNumber) => "${Intl.plural(count, one: '1 bestand', other: '${formattedNumber} bestanden')} in dit album is veilig geback-upt"; - static String m26(storageAmountInGB) => + static String m29(storageAmountInGB) => "${storageAmountInGB} GB telkens als iemand zich aanmeldt voor een betaald abonnement en je code toepast"; - static String m27(endDate) => "Gratis proefversie geldig tot ${endDate}"; + static String m30(endDate) => "Gratis proefversie geldig tot ${endDate}"; - static String m28(count) => + static String m31(count) => "Je hebt nog steeds toegang tot ${Intl.plural(count, one: 'het', other: 'ze')} op Ente zolang je een actief abonnement hebt"; - static String m29(sizeInMBorGB) => "Maak ${sizeInMBorGB} vrij"; + static String m32(sizeInMBorGB) => "Maak ${sizeInMBorGB} vrij"; - static String m30(count, formattedSize) => + static String m33(count, formattedSize) => "${Intl.plural(count, one: 'Het kan verwijderd worden van het apparaat om ${formattedSize} vrij te maken', other: 'Ze kunnen verwijderd worden van het apparaat om ${formattedSize} vrij te maken')}"; - static String m31(currentlyProcessing, totalCount) => + static String m34(currentlyProcessing, totalCount) => "Verwerken van ${currentlyProcessing} / ${totalCount}"; - static String m32(count) => + static String m35(count) => "${Intl.plural(count, one: '${count} item', other: '${count} items')}"; - static String m33(expiryTime) => "Link vervalt op ${expiryTime}"; + static String m36(expiryTime) => "Link vervalt op ${expiryTime}"; - static String m34(count, formattedCount) => + static String m0(count, formattedCount) => "${Intl.plural(count, zero: 'geen herinneringen', one: '${formattedCount} herinnering', other: '${formattedCount} herinneringen')}"; - static String m35(count) => + static String m37(count) => "${Intl.plural(count, one: 'Bestand verplaatsen', other: 'Bestanden verplaatsen')}"; - static String m36(albumName) => "Succesvol verplaatst naar ${albumName}"; + static String m38(albumName) => "Succesvol verplaatst naar ${albumName}"; - static String m37(name) => "Niet ${name}?"; + static String m39(name) => "Niet ${name}?"; - static String m39(passwordStrengthValue) => + static String m40(familyAdminEmail) => + "Neem contact op met ${familyAdminEmail} om uw code te wijzigen."; + + static String m41(passwordStrengthValue) => "Wachtwoord sterkte: ${passwordStrengthValue}"; - static String m40(providerName) => + static String m42(providerName) => "Praat met ${providerName} klantenservice als u in rekening bent gebracht"; - static String m41(endDate) => + static String m43(endDate) => "Gratis proefperiode geldig tot ${endDate}.\nU kunt naderhand een betaald abonnement kiezen."; - static String m42(toEmail) => "Stuur ons een e-mail op ${toEmail}"; + static String m44(toEmail) => "Stuur ons een e-mail op ${toEmail}"; - static String m43(toEmail) => + static String m45(toEmail) => "Verstuur de logboeken alstublieft naar ${toEmail}"; - static String m44(storeName) => "Beoordeel ons op ${storeName}"; + static String m46(storeName) => "Beoordeel ons op ${storeName}"; - static String m45(storageInGB) => + static String m47(storageInGB) => "Jullie krijgen allebei ${storageInGB} GB* gratis"; - static String m46(userEmail) => + static String m48(userEmail) => "${userEmail} zal worden verwijderd uit dit gedeelde album\n\nAlle door hen toegevoegde foto\'s worden ook uit het album verwijderd"; - static String m47(endDate) => "Wordt verlengd op ${endDate}"; + static String m49(endDate) => "Wordt verlengd op ${endDate}"; - static String m48(count) => + static String m50(count) => "${Intl.plural(count, one: '${count} resultaat gevonden', other: '${count} resultaten gevonden')}"; - static String m49(count) => "${count} geselecteerd"; + static String m1(count) => "${count} geselecteerd"; - static String m50(count, yourCount) => + static String m51(count, yourCount) => "${count} geselecteerd (${yourCount} van jou)"; - static String m51(verificationID) => + static String m52(verificationID) => "Hier is mijn verificatie-ID: ${verificationID} voor ente.io."; - static String m52(verificationID) => + static String m2(verificationID) => "Hey, kunt u bevestigen dat dit uw ente.io verificatie-ID is: ${verificationID}"; static String m53(referralCode, referralStorageInGB) => @@ -236,10 +239,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Nieuw e-mailadres toevoegen"), "addCollaborator": MessageLookupByLibrary.simpleMessage("Samenwerker toevoegen"), - "addCollaborators": m0, + "addCollaborators": m3, "addFromDevice": MessageLookupByLibrary.simpleMessage("Toevoegen vanaf apparaat"), - "addItem": m2, + "addItem": m4, "addLocation": MessageLookupByLibrary.simpleMessage("Locatie toevoegen"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Toevoegen"), @@ -247,7 +250,7 @@ class MessageLookup extends MessageLookupByLibrary { "addNew": MessageLookupByLibrary.simpleMessage("Nieuwe toevoegen"), "addOnPageSubtitle": MessageLookupByLibrary.simpleMessage("Details van add-ons"), - "addOnValidTill": m3, + "addOnValidTill": m5, "addOns": MessageLookupByLibrary.simpleMessage("Add-ons"), "addPhotos": MessageLookupByLibrary.simpleMessage("Foto\'s toevoegen"), "addSelected": @@ -258,12 +261,12 @@ class MessageLookup extends MessageLookupByLibrary { "addToHiddenAlbum": MessageLookupByLibrary.simpleMessage( "Toevoegen aan verborgen album"), "addViewer": MessageLookupByLibrary.simpleMessage("Voeg kijker toe"), - "addViewers": m1, + "addViewers": m6, "addYourPhotosNow": MessageLookupByLibrary.simpleMessage("Voeg nu je foto\'s toe"), "addedAs": MessageLookupByLibrary.simpleMessage("Toegevoegd als"), - "addedBy": m4, - "addedSuccessfullyTo": m5, + "addedBy": m7, + "addedSuccessfullyTo": m8, "addingToFavorites": MessageLookupByLibrary.simpleMessage("Toevoegen aan favorieten..."), "advanced": MessageLookupByLibrary.simpleMessage("Geavanceerd"), @@ -274,7 +277,7 @@ class MessageLookup extends MessageLookupByLibrary { "after1Week": MessageLookupByLibrary.simpleMessage("Na 1 week"), "after1Year": MessageLookupByLibrary.simpleMessage("Na 1 jaar"), "albumOwner": MessageLookupByLibrary.simpleMessage("Eigenaar"), - "albumParticipantsCount": m6, + "albumParticipantsCount": m9, "albumTitle": MessageLookupByLibrary.simpleMessage("Albumtitel"), "albumUpdated": MessageLookupByLibrary.simpleMessage("Album bijgewerkt"), @@ -312,8 +315,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Verificatie vereist"), "appLock": MessageLookupByLibrary.simpleMessage("App-vergrendeling"), "appLockDescriptions": MessageLookupByLibrary.simpleMessage( - "Choose between your device\'s default lock screen and a custom lock screen with a PIN or password."), - "appVersion": m7, + "Kies tussen het standaard vergrendelscherm van uw apparaat en een aangepast vergrendelscherm met een pincode of wachtwoord."), + "appVersion": m10, "appleId": MessageLookupByLibrary.simpleMessage("Apple ID"), "apply": MessageLookupByLibrary.simpleMessage("Toepassen"), "applyCodeTitle": @@ -360,8 +363,6 @@ class MessageLookup extends MessageLookupByLibrary { "Graag verifiëren om tweestapsverificatie te configureren"), "authToInitiateAccountDeletion": MessageLookupByLibrary.simpleMessage( "Gelieve te verifiëren om het verwijderen van je account te starten"), - "authToViewPasskey": MessageLookupByLibrary.simpleMessage( - "Please authenticate to view your passkey"), "authToViewYourActiveSessions": MessageLookupByLibrary.simpleMessage( "Graag verifiëren om uw actieve sessies te bekijken"), "authToViewYourHiddenFiles": MessageLookupByLibrary.simpleMessage( @@ -391,7 +392,7 @@ class MessageLookup extends MessageLookupByLibrary { "autoPairDesc": MessageLookupByLibrary.simpleMessage( "Automatisch koppelen werkt alleen met apparaten die Chromecast ondersteunen."), "available": MessageLookupByLibrary.simpleMessage("Beschikbaar"), - "availableStorageSpace": m8, + "availableStorageSpace": m11, "backedUpFolders": MessageLookupByLibrary.simpleMessage("Back-up mappen"), "backup": MessageLookupByLibrary.simpleMessage("Back-up"), @@ -416,10 +417,10 @@ class MessageLookup extends MessageLookupByLibrary { "canOnlyRemoveFilesOwnedByYou": MessageLookupByLibrary.simpleMessage( "Kan alleen bestanden verwijderen die jouw eigendom zijn"), "cancel": MessageLookupByLibrary.simpleMessage("Annuleer"), - "cancelOtherSubscription": m9, + "cancelOtherSubscription": m12, "cancelSubscription": MessageLookupByLibrary.simpleMessage("Abonnement opzeggen"), - "cannotAddMorePhotosAfterBecomingViewer": m10, + "cannotAddMorePhotosAfterBecomingViewer": m13, "cannotDeleteSharedFiles": MessageLookupByLibrary.simpleMessage( "Kan gedeelde bestanden niet verwijderen"), "castIPMismatchBody": MessageLookupByLibrary.simpleMessage( @@ -429,6 +430,7 @@ class MessageLookup extends MessageLookupByLibrary { "castInstruction": MessageLookupByLibrary.simpleMessage( "Bezoek cast.ente.io op het apparaat dat u wilt koppelen.\n\nVoer de code hieronder in om het album op uw TV af te spelen."), "centerPoint": MessageLookupByLibrary.simpleMessage("Middelpunt"), + "change": MessageLookupByLibrary.simpleMessage("Wijzigen"), "changeEmail": MessageLookupByLibrary.simpleMessage("E-mail wijzigen"), "changeLocationOfSelectedItems": MessageLookupByLibrary.simpleMessage( "Locatie van geselecteerde items wijzigen?"), @@ -438,6 +440,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Wachtwoord wijzigen"), "changePermissions": MessageLookupByLibrary.simpleMessage("Rechten aanpassen?"), + "changeYourReferralCode": + MessageLookupByLibrary.simpleMessage("Wijzig uw verwijzingscode"), "checkForUpdates": MessageLookupByLibrary.simpleMessage("Controleer op updates"), "checkInboxAndSpamFolder": MessageLookupByLibrary.simpleMessage( @@ -446,24 +450,24 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Status controleren"), "checking": MessageLookupByLibrary.simpleMessage("Controleren..."), "cl_guest_view_call_to_action": MessageLookupByLibrary.simpleMessage( - "Selecteer foto\'s en bekijk de \"Gastweergave\"."), + "Selecteer foto\'s en bekijk \"Gastweergave\"."), "cl_guest_view_description": MessageLookupByLibrary.simpleMessage( - "Geef je je telefoon aan een vriend om foto\'s te laten zien? Maak je geen zorgen dat ze te ver swipen. Gastweergave vergrendelt ze op de foto\'s die je selecteert."), + "Geeft u een vriend uw telefoon om foto\'s te laten zien? Maakt u zich geen zorgen dat ze te ver swipen. Gastweergave zal diegene beperken tot de foto\'s die u selecteert."), "cl_guest_view_title": MessageLookupByLibrary.simpleMessage("Gastweergave"), "cl_panorama_viewer_description": MessageLookupByLibrary.simpleMessage( - "We hebben ondersteuning toegevoegd voor het bekijken van panoramafoto\'s met 360 graden weergaven. De ervaring is meeslepend met bewegingsgestuurde navigatie!"), + "We hebben ondersteuning toegevoegd voor het bekijken van panoramafoto\'s met 360 graden weergave. De ervaring is immersief met op beweging gebaseerde navigatie!"), "cl_panorama_viewer_title": - MessageLookupByLibrary.simpleMessage("Panorama Viewer"), + MessageLookupByLibrary.simpleMessage("Panoramakijker"), "cl_video_player_description": MessageLookupByLibrary.simpleMessage( - "We introduceren een nieuwe videospeler met betere afspeelbediening en ondersteuning voor HDR-video\'s."), + "Een verfrissende nieuwe videospeler, met betere afspeelknoppen en ondersteuning voor HDR-video\'s."), "cl_video_player_title": MessageLookupByLibrary.simpleMessage("Videospeler"), "claimFreeStorage": MessageLookupByLibrary.simpleMessage("Claim gratis opslag"), "claimMore": MessageLookupByLibrary.simpleMessage("Claim meer!"), "claimed": MessageLookupByLibrary.simpleMessage("Geclaimd"), - "claimedStorageSoFar": m11, + "claimedStorageSoFar": m14, "cleanUncategorized": MessageLookupByLibrary.simpleMessage("Ongecategoriseerd opschonen"), "cleanUncategorizedDescription": MessageLookupByLibrary.simpleMessage( @@ -482,6 +486,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Voortgang clusteren"), "codeAppliedPageTitle": MessageLookupByLibrary.simpleMessage("Code toegepast"), + "codeChangeLimitReached": MessageLookupByLibrary.simpleMessage( + "Sorry, u heeft de limiet van het aantal codewijzigingen bereikt."), "codeCopiedToClipboard": MessageLookupByLibrary.simpleMessage( "Code gekopieerd naar klembord"), "codeUsedByYou": @@ -490,7 +496,7 @@ class MessageLookup extends MessageLookupByLibrary { "Maak een link waarmee mensen foto\'s in jouw gedeelde album kunnen toevoegen en bekijken zonder dat ze daarvoor een Ente app of account nodig hebben. Handig voor het verzamelen van foto\'s van evenementen."), "collaborativeLink": MessageLookupByLibrary.simpleMessage("Gezamenlijke link"), - "collaborativeLinkCreatedFor": m12, + "collaborativeLinkCreatedFor": m15, "collaborator": MessageLookupByLibrary.simpleMessage("Samenwerker"), "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": MessageLookupByLibrary.simpleMessage( @@ -520,10 +526,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Bevestig herstelsleutel"), "connectToDevice": MessageLookupByLibrary.simpleMessage( "Verbinding maken met apparaat"), - "contactFamilyAdmin": m13, + "contactFamilyAdmin": m16, "contactSupport": MessageLookupByLibrary.simpleMessage("Contacteer klantenservice"), - "contactToManageSubscription": m14, + "contactToManageSubscription": m17, "contacts": MessageLookupByLibrary.simpleMessage("Contacten"), "contents": MessageLookupByLibrary.simpleMessage("Inhoud"), "continueLabel": MessageLookupByLibrary.simpleMessage("Doorgaan"), @@ -568,7 +574,7 @@ class MessageLookup extends MessageLookupByLibrary { "currentUsageIs": MessageLookupByLibrary.simpleMessage("Huidig gebruik is "), "custom": MessageLookupByLibrary.simpleMessage("Aangepast"), - "customEndpoint": m15, + "customEndpoint": m18, "darkTheme": MessageLookupByLibrary.simpleMessage("Donker"), "dayToday": MessageLookupByLibrary.simpleMessage("Vandaag"), "dayYesterday": MessageLookupByLibrary.simpleMessage("Gisteren"), @@ -604,12 +610,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Verwijder van apparaat"), "deleteFromEnte": MessageLookupByLibrary.simpleMessage("Verwijder van Ente"), - "deleteItemCount": m16, + "deleteItemCount": m19, "deleteLocation": MessageLookupByLibrary.simpleMessage("Verwijder locatie"), "deletePhotos": MessageLookupByLibrary.simpleMessage("Foto\'s verwijderen"), - "deleteProgress": m17, + "deleteProgress": m20, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Ik mis een belangrijke functie"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -651,7 +657,7 @@ class MessageLookup extends MessageLookupByLibrary { "Kijkers kunnen nog steeds screenshots maken of een kopie van je foto\'s opslaan met behulp van externe tools"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Let op"), - "disableLinkMessage": m18, + "disableLinkMessage": m21, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Tweestapsverificatie uitschakelen"), "disablingTwofactorAuthentication": @@ -672,9 +678,9 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("Download mislukt"), "downloading": MessageLookupByLibrary.simpleMessage("Downloaden..."), - "dropSupportEmail": m19, - "duplicateFileCountWithStorageSaved": m20, - "duplicateItemsGroup": m21, + "dropSupportEmail": m22, + "duplicateFileCountWithStorageSaved": m23, + "duplicateItemsGroup": m24, "edit": MessageLookupByLibrary.simpleMessage("Bewerken"), "editLocation": MessageLookupByLibrary.simpleMessage("Locatie bewerken"), @@ -687,8 +693,8 @@ class MessageLookup extends MessageLookupByLibrary { "Bewerkte locatie wordt alleen gezien binnen Ente"), "eligible": MessageLookupByLibrary.simpleMessage("gerechtigd"), "email": MessageLookupByLibrary.simpleMessage("E-mail"), - "emailChangedTo": m22, - "emailNoEnteAccount": m23, + "emailChangedTo": m25, + "emailNoEnteAccount": m26, "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("E-mailverificatie"), "emailYourLogs": @@ -696,10 +702,14 @@ class MessageLookup extends MessageLookupByLibrary { "empty": MessageLookupByLibrary.simpleMessage("Leeg"), "emptyTrash": MessageLookupByLibrary.simpleMessage("Prullenbak leegmaken?"), + "enable": MessageLookupByLibrary.simpleMessage("Inschakelen"), + "enableMLIndexingDesc": MessageLookupByLibrary.simpleMessage( + "Ente ondersteunt on-device machine learning voor gezichtsherkenning, magisch zoeken en andere geavanceerde zoekfuncties"), "enableMaps": MessageLookupByLibrary.simpleMessage("Kaarten inschakelen"), "enableMapsDesc": MessageLookupByLibrary.simpleMessage( "Dit toont jouw foto\'s op een wereldkaart.\n\nDeze kaart wordt gehost door Open Street Map, en de exacte locaties van jouw foto\'s worden nooit gedeeld.\n\nJe kunt deze functie op elk gewenst moment uitschakelen via de instellingen."), + "enabled": MessageLookupByLibrary.simpleMessage("Ingeschakeld"), "encryptingBackup": MessageLookupByLibrary.simpleMessage("Back-up versleutelen..."), "encryption": MessageLookupByLibrary.simpleMessage("Encryptie"), @@ -799,8 +809,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Bestandstype"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Bestandstypen en namen"), - "filesBackedUpFromDevice": m24, - "filesBackedUpInAlbum": m25, + "filesBackedUpFromDevice": m27, + "filesBackedUpInAlbum": m28, "filesDeleted": MessageLookupByLibrary.simpleMessage("Bestanden verwijderd"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage( @@ -816,25 +826,25 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Gezichten gevonden"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("Gratis opslag geclaimd"), - "freeStorageOnReferralSuccess": m26, + "freeStorageOnReferralSuccess": m29, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("Gratis opslag bruikbaar"), "freeTrial": MessageLookupByLibrary.simpleMessage("Gratis proefversie"), - "freeTrialValidTill": m27, - "freeUpAccessPostDelete": m28, - "freeUpAmount": m29, + "freeTrialValidTill": m30, + "freeUpAccessPostDelete": m31, + "freeUpAmount": m32, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("Apparaatruimte vrijmaken"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Bespaar ruimte op je apparaat door bestanden die al geback-upt zijn te wissen."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Ruimte vrijmaken"), - "freeUpSpaceSaving": m30, + "freeUpSpaceSaving": m33, "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Tot 1000 herinneringen getoond in de galerij"), "general": MessageLookupByLibrary.simpleMessage("Algemeen"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Encryptiesleutels genereren..."), - "genericProgress": m31, + "genericProgress": m34, "goToSettings": MessageLookupByLibrary.simpleMessage("Ga naar instellingen"), "googlePlayId": MessageLookupByLibrary.simpleMessage("Google Play ID"), @@ -844,9 +854,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Toestemming verlenen"), "groupNearbyPhotos": MessageLookupByLibrary.simpleMessage("Groep foto\'s in de buurt"), - "guestView": MessageLookupByLibrary.simpleMessage("Guest view"), + "guestView": MessageLookupByLibrary.simpleMessage("Gasten weergave"), "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( - "To enable guest view, please setup device passcode or screen lock in your system settings."), + "Om gasten weergave in te schakelen, moet u een toegangscode of schermvergrendeling instellen in uw systeeminstellingen."), "hearUsExplanation": MessageLookupByLibrary.simpleMessage( "Wij gebruiken geen tracking. Het zou helpen als je ons vertelt waar je ons gevonden hebt!"), "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( @@ -911,7 +921,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Het lijkt erop dat er iets fout is gegaan. Probeer het later opnieuw. Als de fout zich blijft voordoen, neem dan contact op met ons supportteam."), - "itemCount": m32, + "itemCount": m35, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Bestanden tonen het aantal resterende dagen voordat ze permanent worden verwijderd"), @@ -939,7 +949,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Apparaat limiet"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Ingeschakeld"), "linkExpired": MessageLookupByLibrary.simpleMessage("Verlopen"), - "linkExpiresOn": m33, + "linkExpiresOn": m36, "linkExpiry": MessageLookupByLibrary.simpleMessage("Vervaldatum"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("Link is vervallen"), @@ -1001,6 +1011,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Machine Learning"), "magicSearch": MessageLookupByLibrary.simpleMessage("Magische zoekfunctie"), + "magicSearchHint": MessageLookupByLibrary.simpleMessage( + "Magisch zoeken maakt het mogelijk om foto\'s op hun inhoud worden gezocht, bijvoorbeeld \"bloem\", \"rode auto\", \"identiteitsdocumenten\""), "manage": MessageLookupByLibrary.simpleMessage("Beheren"), "manageDeviceStorage": MessageLookupByLibrary.simpleMessage("Apparaatopslag beheren"), @@ -1016,10 +1028,20 @@ class MessageLookup extends MessageLookupByLibrary { "maps": MessageLookupByLibrary.simpleMessage("Kaarten"), "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), - "memoryCount": m34, + "memoryCount": m0, "merchandise": MessageLookupByLibrary.simpleMessage("Merchandise"), + "mlConsent": + MessageLookupByLibrary.simpleMessage("Schakel machine learning in"), + "mlConsentConfirmation": MessageLookupByLibrary.simpleMessage( + "Ik begrijp het, en wil machine learning inschakelen"), + "mlConsentDescription": MessageLookupByLibrary.simpleMessage( + "Als u machine learning inschakelt, zal Ente informatie zoals gezichtsgeometrie uit bestanden extraheren, inclusief degenen die met u gedeeld worden.\n\nDit gebeurt op uw apparaat, en alle gegenereerde biometrische informatie zal end-to-end versleuteld worden."), + "mlConsentPrivacy": MessageLookupByLibrary.simpleMessage( + "Klik hier voor meer details over deze functie in ons privacybeleid."), + "mlConsentTitle": MessageLookupByLibrary.simpleMessage( + "Machine learning inschakelen?"), "mlIndexingDescription": MessageLookupByLibrary.simpleMessage( - "Houd er rekening mee dat dit zal resulteren in een hoger internet- en batterijverbruik totdat alle items zijn geïndexeerd."), + "Houd er rekening mee dat machine learning zal leiden tot hoger bandbreedte- en batterijgebruik totdat alle items geïndexeerd zijn. Overweeg het gebruik van de desktop app voor snellere indexering. Alle resultaten worden automatisch gesynchroniseerd."), "mobileWebDesktop": MessageLookupByLibrary.simpleMessage("Mobiel, Web, Desktop"), "moderateStrength": MessageLookupByLibrary.simpleMessage("Matig"), @@ -1028,12 +1050,13 @@ class MessageLookup extends MessageLookupByLibrary { "Pas je zoekopdracht aan of zoek naar"), "moments": MessageLookupByLibrary.simpleMessage("Momenten"), "monthly": MessageLookupByLibrary.simpleMessage("Maandelijks"), - "moveItem": m35, + "moreDetails": MessageLookupByLibrary.simpleMessage("Meer details"), + "moveItem": m37, "moveToAlbum": MessageLookupByLibrary.simpleMessage("Verplaats naar album"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage( "Verplaatsen naar verborgen album"), - "movedSuccessfullyTo": m36, + "movedSuccessfullyTo": m38, "movedToTrash": MessageLookupByLibrary.simpleMessage("Naar prullenbak verplaatst"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1071,8 +1094,8 @@ class MessageLookup extends MessageLookupByLibrary { "Er worden momenteel geen foto\'s geback-upt"), "noPhotosFoundHere": MessageLookupByLibrary.simpleMessage("Geen foto\'s gevonden hier"), - "noQuickLinksSelected": - MessageLookupByLibrary.simpleMessage("No quick links selected"), + "noQuickLinksSelected": MessageLookupByLibrary.simpleMessage( + "Geen snelle links geselecteerd"), "noRecoveryKey": MessageLookupByLibrary.simpleMessage("Geen herstelcode?"), "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( @@ -1082,7 +1105,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Geen resultaten gevonden"), "noSystemLockFound": MessageLookupByLibrary.simpleMessage( "Geen systeemvergrendeling gevonden"), - "notPersonLabel": m37, + "notPersonLabel": m39, "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage("Nog niets met je gedeeld"), "nothingToSeeHere": @@ -1092,6 +1115,7 @@ class MessageLookup extends MessageLookupByLibrary { "onDevice": MessageLookupByLibrary.simpleMessage("Op het apparaat"), "onEnte": MessageLookupByLibrary.simpleMessage( "Op ente"), + "onlyFamilyAdminCanChangeCode": m40, "oops": MessageLookupByLibrary.simpleMessage("Oeps"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( "Oeps, kon bewerkingen niet opslaan"), @@ -1120,7 +1144,7 @@ class MessageLookup extends MessageLookupByLibrary { "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage( "Wachtwoord succesvol aangepast"), "passwordLock": MessageLookupByLibrary.simpleMessage("Wachtwoord slot"), - "passwordStrength": m39, + "passwordStrength": m41, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "De wachtwoordsterkte wordt berekend aan de hand van de lengte van het wachtwoord, de gebruikte tekens en of het wachtwoord al dan niet in de top 10.000 van meest gebruikte wachtwoorden staat"), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -1131,7 +1155,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Betaling mislukt"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Helaas is je betaling mislukt. Neem contact op met support zodat we je kunnen helpen!"), - "paymentFailedTalkToProvider": m40, + "paymentFailedTalkToProvider": m42, "pendingItems": MessageLookupByLibrary.simpleMessage("Bestanden in behandeling"), "pendingSync": MessageLookupByLibrary.simpleMessage( @@ -1161,7 +1185,7 @@ class MessageLookup extends MessageLookupByLibrary { "pinLock": MessageLookupByLibrary.simpleMessage("PIN vergrendeling"), "playOnTv": MessageLookupByLibrary.simpleMessage("Album afspelen op TV"), - "playStoreFreeTrialValidTill": m41, + "playStoreFreeTrialValidTill": m43, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("PlayStore abonnement"), "pleaseCheckYourInternetConnectionAndTryAgain": @@ -1173,14 +1197,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Neem contact op met klantenservice als het probleem aanhoudt"), - "pleaseEmailUsAt": m42, + "pleaseEmailUsAt": m44, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage( "Geef alstublieft toestemming"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Log opnieuw in"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( - "Please select quick links to remove"), - "pleaseSendTheLogsTo": m43, + "Selecteer snelle links om te verwijderen"), + "pleaseSendTheLogsTo": m45, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Probeer het nog eens"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1215,7 +1239,7 @@ class MessageLookup extends MessageLookupByLibrary { "raiseTicket": MessageLookupByLibrary.simpleMessage("Meld probleem"), "rateTheApp": MessageLookupByLibrary.simpleMessage("Beoordeel de app"), "rateUs": MessageLookupByLibrary.simpleMessage("Beoordeel ons"), - "rateUsOnStore": m44, + "rateUsOnStore": m46, "recover": MessageLookupByLibrary.simpleMessage("Herstellen"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Account herstellen"), @@ -1250,7 +1274,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Geef deze code aan je vrienden"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Ze registreren voor een betaald plan"), - "referralStep3": m45, + "referralStep3": m47, "referrals": MessageLookupByLibrary.simpleMessage("Referenties"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Verwijzingen zijn momenteel gepauzeerd"), @@ -1274,17 +1298,17 @@ class MessageLookup extends MessageLookupByLibrary { "removeFromAlbumTitle": MessageLookupByLibrary.simpleMessage("Uit album verwijderen?"), "removeFromFavorite": - MessageLookupByLibrary.simpleMessage("Verwijderen uit favorieten"), + MessageLookupByLibrary.simpleMessage("Verwijder van favorieten"), "removeLink": MessageLookupByLibrary.simpleMessage("Verwijder link"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Deelnemer verwijderen"), - "removeParticipantBody": m46, + "removeParticipantBody": m48, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Verwijder persoonslabel"), "removePublicLink": MessageLookupByLibrary.simpleMessage("Verwijder publieke link"), "removePublicLinks": - MessageLookupByLibrary.simpleMessage("Remove public links"), + MessageLookupByLibrary.simpleMessage("Verwijder publieke link"), "removeShareItemsWarning": MessageLookupByLibrary.simpleMessage( "Sommige van de items die je verwijdert zijn door andere mensen toegevoegd, en je verliest de toegang daartoe"), "removeWithQuestionMark": @@ -1298,7 +1322,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Bestandsnaam wijzigen"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Abonnement verlengen"), - "renewsOn": m47, + "renewsOn": m49, "reportABug": MessageLookupByLibrary.simpleMessage("Een fout melden"), "reportBug": MessageLookupByLibrary.simpleMessage("Fout melden"), "resendEmail": @@ -1314,6 +1338,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Terugzetten naar album"), "restoringFiles": MessageLookupByLibrary.simpleMessage("Bestanden herstellen..."), + "resumableUploads": + MessageLookupByLibrary.simpleMessage("Hervatbare uploads"), "retry": MessageLookupByLibrary.simpleMessage("Opnieuw"), "reviewDeduplicateItems": MessageLookupByLibrary.simpleMessage( "Controleer en verwijder de bestanden die u denkt dat dubbel zijn."), @@ -1367,7 +1393,7 @@ class MessageLookup extends MessageLookupByLibrary { "Foto\'s groeperen die in een bepaalde straal van een foto worden genomen"), "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage( "Nodig mensen uit, en je ziet alle foto\'s die door hen worden gedeeld hier"), - "searchResultCount": m48, + "searchResultCount": m50, "security": MessageLookupByLibrary.simpleMessage("Beveiliging"), "selectALocation": MessageLookupByLibrary.simpleMessage("Selecteer een locatie"), @@ -1394,8 +1420,8 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage( "Geselecteerde bestanden worden verwijderd uit alle albums en verplaatst naar de prullenbak."), - "selectedPhotos": m49, - "selectedPhotosWithYours": m50, + "selectedPhotos": m1, + "selectedPhotosWithYours": m51, "send": MessageLookupByLibrary.simpleMessage("Verzenden"), "sendEmail": MessageLookupByLibrary.simpleMessage("E-mail versturen"), "sendInvite": @@ -1425,10 +1451,10 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Deel nu een album"), "shareLink": MessageLookupByLibrary.simpleMessage("Link delen"), - "shareMyVerificationID": m51, + "shareMyVerificationID": m52, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Deel alleen met de mensen die u wilt"), - "shareTextConfirmOthersVerificationID": m52, + "shareTextConfirmOthersVerificationID": m2, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Download Ente zodat we gemakkelijk foto\'s en video\'s in originele kwaliteit kunnen delen\n\nhttps://ente.io"), "shareTextReferralCode": m53, @@ -1585,10 +1611,10 @@ class MessageLookup extends MessageLookupByLibrary { "Dit zal je uitloggen van dit apparaat!"), "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( - "This will remove public links of all selected quick links."), + "Hiermee worden openbare links van alle geselecteerde snelle links verwijderd."), "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": MessageLookupByLibrary.simpleMessage( - "Om vergrendelscherm in te schakelen, moet u een toegangscode of schermvergrendeling instellen in uw systeeminstellingen."), + "Om appvergrendeling in te schakelen, moet u een toegangscode of schermvergrendeling instellen in uw systeeminstellingen."), "toHideAPhotoOrVideo": MessageLookupByLibrary.simpleMessage( "Om een foto of video te verbergen"), "toResetVerifyEmail": MessageLookupByLibrary.simpleMessage( @@ -1625,6 +1651,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Album uit archief halen"), "unarchiving": MessageLookupByLibrary.simpleMessage("Uit het archief halen..."), + "unavailableReferralCode": MessageLookupByLibrary.simpleMessage( + "Deze code is helaas niet beschikbaar."), "uncategorized": MessageLookupByLibrary.simpleMessage("Ongecategoriseerd"), "unhide": MessageLookupByLibrary.simpleMessage("Zichtbaar maken"), @@ -1687,8 +1715,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Bekijk alle EXIF gegevens"), "viewLargeFiles": MessageLookupByLibrary.simpleMessage("Grote bestanden"), - "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( - "Bekijk bestanden die de meeste opslagruimte verbruiken"), "viewLogs": MessageLookupByLibrary.simpleMessage("Logboeken bekijken"), "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("Toon herstelsleutel"), diff --git a/mobile/lib/generated/intl/messages_no.dart b/mobile/lib/generated/intl/messages_no.dart index 9ac7fbaee5..e5badae7f5 100644 --- a/mobile/lib/generated/intl/messages_no.dart +++ b/mobile/lib/generated/intl/messages_no.dart @@ -20,127 +20,444 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'no'; - static String m0(count) => - "${Intl.plural(count, zero: 'Add collaborator', one: 'Add collaborator', other: 'Add collaborators')}"; + static String m9(count) => + "${Intl.plural(count, zero: 'Ingen deltakere', one: '1 Deltaker', other: '${count} Deltakere')}"; - static String m1(count) => - "${Intl.plural(count, zero: 'Add viewer', one: 'Add viewer', other: 'Add viewers')}"; + static String m13(user) => + "${user} vil ikke kunne legge til flere bilder til dette albumet\n\nDe vil fortsatt kunne fjerne eksisterende bilder lagt til av dem"; + + static String m19(count) => + "${Intl.plural(count, one: 'Slett ${count} element', other: 'Slett ${count} elementer')}"; + + static String m21(albumName) => + "Dette fjerner den offentlige lenken for tilgang til \"${albumName}\"."; + + static String m22(supportEmail) => + "Vennligst send en e-post til ${supportEmail} fra din registrerte e-postadresse"; + + static String m24(count, formattedSize) => + "${count} filer, ${formattedSize} hver"; + + static String m35(count) => + "${Intl.plural(count, one: '${count} element', other: '${count} elementer')}"; + + static String m36(expiryTime) => "Lenken utløper på ${expiryTime}"; + + static String m0(count, formattedCount) => + "${Intl.plural(count, zero: 'ingen minner', one: '${formattedCount} minne', other: '${formattedCount} minner')}"; + + static String m41(passwordStrengthValue) => + "Passordstyrke: ${passwordStrengthValue}"; + + static String m1(count) => "${count} valgt"; + + static String m51(count, yourCount) => "${count} valgt (${yourCount} dine)"; + + static String m52(verificationID) => + "Her er min verifiserings-ID: ${verificationID} for ente.io."; + + static String m2(verificationID) => + "Hei, kan du bekrefte at dette er din ente.io verifiserings-ID: ${verificationID}"; + + static String m54(numberOfPeople) => + "${Intl.plural(numberOfPeople, zero: 'Del med bestemte personer', one: 'Delt med 1 person', other: 'Delt med ${numberOfPeople} personer')}"; + + static String m65(email) => "Dette er ${email} sin verifiserings-ID"; + + static String m68(email) => "Verifiser ${email}"; + + static String m69(email) => + "Vi har sendt en e-post til ${email}"; final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { "accountWelcomeBack": MessageLookupByLibrary.simpleMessage("Velkommen tilbake!"), - "addCollaborators": m0, - "addToHiddenAlbum": - MessageLookupByLibrary.simpleMessage("Add to hidden album"), - "addViewers": m1, - "appLock": MessageLookupByLibrary.simpleMessage("App lock"), - "appLockDescriptions": MessageLookupByLibrary.simpleMessage( - "Choose between your device\'s default lock screen and a custom lock screen with a PIN or password."), + "ackPasswordLostWarning": MessageLookupByLibrary.simpleMessage( + "Jeg forstår at dersom jeg mister passordet mitt, kan jeg miste dataen min, siden daten er ende-til-ende-kryptert."), + "activeSessions": MessageLookupByLibrary.simpleMessage("Aktive økter"), + "addANewEmail": + MessageLookupByLibrary.simpleMessage("Legg til ny e-post"), + "addCollaborator": + MessageLookupByLibrary.simpleMessage("Legg til samarbeidspartner"), + "addMore": MessageLookupByLibrary.simpleMessage("Legg til flere"), + "addViewer": MessageLookupByLibrary.simpleMessage("Legg til seer"), + "addedAs": MessageLookupByLibrary.simpleMessage("Lagt til som"), + "advanced": MessageLookupByLibrary.simpleMessage("Avansert"), + "advancedSettings": MessageLookupByLibrary.simpleMessage("Avansert"), + "after1Day": MessageLookupByLibrary.simpleMessage("Etter 1 dag"), + "after1Hour": MessageLookupByLibrary.simpleMessage("Etter 1 time"), + "after1Month": MessageLookupByLibrary.simpleMessage("Etter 1 måned"), + "after1Week": MessageLookupByLibrary.simpleMessage("Etter 1 uke"), + "after1Year": MessageLookupByLibrary.simpleMessage("Etter 1 år"), + "albumOwner": MessageLookupByLibrary.simpleMessage("Eier"), + "albumParticipantsCount": m9, + "albumUpdated": MessageLookupByLibrary.simpleMessage("Album oppdatert"), + "albums": MessageLookupByLibrary.simpleMessage("Album"), + "allowAddPhotosDescription": MessageLookupByLibrary.simpleMessage( + "Tillat folk med lenken å også legge til bilder til det delte albumet."), + "allowAddingPhotos": + MessageLookupByLibrary.simpleMessage("Tillat å legge til bilder"), + "allowDownloads": + MessageLookupByLibrary.simpleMessage("Tillat nedlastinger"), + "apply": MessageLookupByLibrary.simpleMessage("Anvend"), "askDeleteReason": MessageLookupByLibrary.simpleMessage( "Hva er hovedårsaken til at du sletter kontoen din?"), - "authToViewPasskey": MessageLookupByLibrary.simpleMessage( - "Please authenticate to view your passkey"), - "autoLock": MessageLookupByLibrary.simpleMessage("Auto lock"), - "autoLockFeatureDescription": MessageLookupByLibrary.simpleMessage( - "Time after which the app locks after being put in the background"), + "authToViewYourHiddenFiles": MessageLookupByLibrary.simpleMessage( + "Vennligst autentiser deg for å se dine skjulte filer"), + "authToViewYourRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Vennligst autentiser deg for å se gjennopprettingsnøkkelen din"), "cancel": MessageLookupByLibrary.simpleMessage("Avbryt"), - "changeLocationOfSelectedItems": MessageLookupByLibrary.simpleMessage( - "Change location of selected items?"), - "clusteringProgress": - MessageLookupByLibrary.simpleMessage("Clustering progress"), + "cannotAddMorePhotosAfterBecomingViewer": m13, + "changeEmail": + MessageLookupByLibrary.simpleMessage("Endre e-postadresse"), + "changePasswordTitle": + MessageLookupByLibrary.simpleMessage("Bytt passord"), + "changePermissions": + MessageLookupByLibrary.simpleMessage("Endre tillatelser?"), + "checkInboxAndSpamFolder": MessageLookupByLibrary.simpleMessage( + "Sjekk innboksen din (og spam) for å fullføre verifikasjonen"), + "clearIndexes": MessageLookupByLibrary.simpleMessage("Tøm indekser"), + "codeCopiedToClipboard": MessageLookupByLibrary.simpleMessage( + "Kode kopiert til utklippstavlen"), + "collaborativeLink": + MessageLookupByLibrary.simpleMessage("Samarbeidslenke"), + "collaborator": + MessageLookupByLibrary.simpleMessage("Samarbeidspartner"), + "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": + MessageLookupByLibrary.simpleMessage( + "Samarbeidspartnere kan legge til bilder og videoer i det delte albumet."), + "collectPhotos": MessageLookupByLibrary.simpleMessage("Samle bilder"), + "confirm": MessageLookupByLibrary.simpleMessage("Bekreft"), "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage("Bekreft sletting av konto"), "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( "Ja, jeg ønsker å slette denne kontoen og all dataen dens permanent."), - "contacts": MessageLookupByLibrary.simpleMessage("Contacts"), - "createCollaborativeLink": - MessageLookupByLibrary.simpleMessage("Create collaborative link"), + "confirmPassword": + MessageLookupByLibrary.simpleMessage("Bekreft passordet"), + "confirmRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Bekreft gjenopprettingsnøkkel"), + "confirmYourRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Bekreft din gjenopprettingsnøkkel"), + "contactSupport": + MessageLookupByLibrary.simpleMessage("Kontakt kundestøtte"), + "continueLabel": MessageLookupByLibrary.simpleMessage("Fortsett"), + "copyLink": MessageLookupByLibrary.simpleMessage("Kopier lenke"), + "copypasteThisCodentoYourAuthenticatorApp": + MessageLookupByLibrary.simpleMessage( + "Kopier og lim inn denne koden\ntil autentiseringsappen din"), + "createAccount": MessageLookupByLibrary.simpleMessage("Opprett konto"), + "createAlbumActionHint": MessageLookupByLibrary.simpleMessage( + "Trykk og holde inne for å velge bilder, og trykk på + for å lage et album"), + "createNewAccount": + MessageLookupByLibrary.simpleMessage("Opprett ny konto"), + "createPublicLink": + MessageLookupByLibrary.simpleMessage("Opprett offentlig lenke"), + "custom": MessageLookupByLibrary.simpleMessage("Egendefinert"), + "decrypting": MessageLookupByLibrary.simpleMessage("Dekrypterer..."), "deleteAccount": MessageLookupByLibrary.simpleMessage("Slett konto"), "deleteAccountFeedbackPrompt": MessageLookupByLibrary.simpleMessage( "Vi er lei oss for at du forlater oss. Gi oss gjerne en tilbakemelding så vi kan forbedre oss."), - "deleteConfirmDialogBody": MessageLookupByLibrary.simpleMessage( - "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted."), - "descriptions": MessageLookupByLibrary.simpleMessage("Descriptions"), - "deviceLock": MessageLookupByLibrary.simpleMessage("Device lock"), - "editLocation": MessageLookupByLibrary.simpleMessage("Edit location"), - "editsToLocationWillOnlyBeSeenWithinEnte": - MessageLookupByLibrary.simpleMessage( - "Edits to location will only be seen within Ente"), + "deleteAccountPermanentlyButton": + MessageLookupByLibrary.simpleMessage("Slett bruker for altid"), + "deleteEmailRequest": MessageLookupByLibrary.simpleMessage( + "Vennligst send en e-post til account-deletion@ente.io fra din registrerte e-postadresse."), + "deleteFromBoth": + MessageLookupByLibrary.simpleMessage("Slett fra begge"), + "deleteFromDevice": + MessageLookupByLibrary.simpleMessage("Slett fra enhet"), + "deleteItemCount": m19, + "deletePhotos": MessageLookupByLibrary.simpleMessage("Slett bilder"), + "deleteReason1": MessageLookupByLibrary.simpleMessage( + "Det mangler en hovedfunksjon jeg trenger"), + "deleteReason2": MessageLookupByLibrary.simpleMessage( + "Appen, eller en bestemt funksjon, fungerer ikke slik jeg tror den skal"), + "deleteReason3": MessageLookupByLibrary.simpleMessage( + "Jeg fant en annen tjeneste jeg liker bedre"), + "deleteReason4": + MessageLookupByLibrary.simpleMessage("Grunnen min er ikke listet"), + "deleteRequestSLAText": MessageLookupByLibrary.simpleMessage( + "Forespørselen din vil bli behandlet innen 72 timer."), + "disableDownloadWarningBody": MessageLookupByLibrary.simpleMessage( + "Seere kan fremdeles ta skjermbilder eller lagre en kopi av bildene dine ved bruk av eksterne verktøy"), + "disableDownloadWarningTitle": + MessageLookupByLibrary.simpleMessage("Vær oppmerksom på"), + "disableLinkMessage": m21, + "doThisLater": + MessageLookupByLibrary.simpleMessage("Gjør dette senere"), + "done": MessageLookupByLibrary.simpleMessage("Ferdig"), + "dropSupportEmail": m22, + "duplicateItemsGroup": m24, "email": MessageLookupByLibrary.simpleMessage("E-post"), - "enterPersonName": - MessageLookupByLibrary.simpleMessage("Enter person name"), - "enterPin": MessageLookupByLibrary.simpleMessage("Enter PIN"), + "encryption": MessageLookupByLibrary.simpleMessage("Kryptering"), + "encryptionKeys": + MessageLookupByLibrary.simpleMessage("Krypteringsnøkkel"), + "entePhotosPerm": MessageLookupByLibrary.simpleMessage( + "Ente trenger tillatelse for å bevare bildene dine"), + "enterCode": MessageLookupByLibrary.simpleMessage("Angi kode"), + "enterCodeDescription": MessageLookupByLibrary.simpleMessage( + "Angi koden fra vennen din for å få gratis lagringsplass for dere begge"), + "enterEmail": MessageLookupByLibrary.simpleMessage("Skriv inn e-post"), + "enterNewPasswordToEncrypt": MessageLookupByLibrary.simpleMessage( + "Angi et nytt passord vi kan bruke til å kryptere dataene dine"), + "enterPassword": MessageLookupByLibrary.simpleMessage("Angi passord"), + "enterPasswordToEncrypt": MessageLookupByLibrary.simpleMessage( + "Angi et passord vi kan bruke til å kryptere dataene dine"), + "enterReferralCode": + MessageLookupByLibrary.simpleMessage("Angi vervekode"), + "enterThe6digitCodeFromnyourAuthenticatorApp": + MessageLookupByLibrary.simpleMessage( + "Skriv inn den 6-sifrede koden fra\ndin autentiseringsapp"), "enterValidEmail": MessageLookupByLibrary.simpleMessage( "Vennligst skriv inn en gyldig e-postadresse."), "enterYourEmailAddress": MessageLookupByLibrary.simpleMessage( "Skriv inn e-postadressen din"), - "faceRecognition": - MessageLookupByLibrary.simpleMessage("Face recognition"), + "enterYourPassword": + MessageLookupByLibrary.simpleMessage("Angi passordet ditt"), + "enterYourRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Skriv inn din gjenopprettingsnøkkel"), + "expiredLinkInfo": MessageLookupByLibrary.simpleMessage( + "Denne lenken er utløpt. Vennligst velg en ny utløpstid eller deaktiver lenkeutløp."), + "failedToLoadAlbums": + MessageLookupByLibrary.simpleMessage("Kunne ikke laste inn album"), + "familyPlans": + MessageLookupByLibrary.simpleMessage("Familieabonnementer"), "feedback": MessageLookupByLibrary.simpleMessage("Tilbakemelding"), - "fileTypes": MessageLookupByLibrary.simpleMessage("File types"), - "foundFaces": MessageLookupByLibrary.simpleMessage("Found faces"), - "guestView": MessageLookupByLibrary.simpleMessage("Guest view"), - "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( - "To enable guest view, please setup device passcode or screen lock in your system settings."), - "hideContent": MessageLookupByLibrary.simpleMessage("Hide content"), - "hideContentDescriptionAndroid": MessageLookupByLibrary.simpleMessage( - "Hides app content in the app switcher and disables screenshots"), - "hideContentDescriptionIos": MessageLookupByLibrary.simpleMessage( - "Hides app content in the app switcher"), - "immediately": MessageLookupByLibrary.simpleMessage("Immediately"), - "indexingIsPaused": MessageLookupByLibrary.simpleMessage( - "Indexing is paused, will automatically resume when device is ready"), + "forgotPassword": MessageLookupByLibrary.simpleMessage("Glemt passord"), + "general": MessageLookupByLibrary.simpleMessage("Generelt"), + "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( + "Genererer krypteringsnøkler..."), + "hidden": MessageLookupByLibrary.simpleMessage("Skjult"), + "howItWorks": + MessageLookupByLibrary.simpleMessage("Hvordan det fungerer"), + "howToViewShareeVerificationID": MessageLookupByLibrary.simpleMessage( + "Vennligst be dem om å trykke og holde inne på e-postadressen sin på innstillingsskjermen, og bekreft at ID-ene på begge enhetene er like."), + "importing": MessageLookupByLibrary.simpleMessage("Importerer...."), + "incorrectPasswordTitle": + MessageLookupByLibrary.simpleMessage("Feil passord"), + "incorrectRecoveryKeyBody": MessageLookupByLibrary.simpleMessage( + "Gjennopprettingsnøkkelen du skrev inn er feil"), + "incorrectRecoveryKeyTitle": + MessageLookupByLibrary.simpleMessage("Feil gjenopprettingsnøkkel"), + "indexedItems": + MessageLookupByLibrary.simpleMessage("Indekserte elementer"), + "insecureDevice": MessageLookupByLibrary.simpleMessage("Usikker enhet"), "invalidEmailAddress": MessageLookupByLibrary.simpleMessage("Ugyldig e-postadresse"), - "joinDiscord": MessageLookupByLibrary.simpleMessage("Join Discord"), + "invalidKey": MessageLookupByLibrary.simpleMessage("Ugyldig nøkkel"), + "invalidRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Gjenopprettingsnøkkelen du har skrevet inn er ikke gyldig. Kontroller at den inneholder 24 ord og kontroller stavemåten av hvert ord.\n\nHvis du har angitt en eldre gjenopprettingskode, må du kontrollere at den er 64 tegn lang, og kontrollere hvert av dem."), + "itemCount": m35, + "keepPhotos": MessageLookupByLibrary.simpleMessage("Behold Bilder"), "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( "Vær vennlig og hjelp oss med denne informasjonen"), - "locations": MessageLookupByLibrary.simpleMessage("Locations"), - "longPressAnEmailToVerifyEndToEndEncryption": + "linkDeviceLimit": MessageLookupByLibrary.simpleMessage("Enhetsgrense"), + "linkEnabled": MessageLookupByLibrary.simpleMessage("Aktivert"), + "linkExpired": MessageLookupByLibrary.simpleMessage("Utløpt"), + "linkExpiresOn": m36, + "linkExpiry": MessageLookupByLibrary.simpleMessage("Lenkeutløp"), + "linkHasExpired": + MessageLookupByLibrary.simpleMessage("Lenken har utløpt"), + "linkNeverExpires": MessageLookupByLibrary.simpleMessage("Aldri"), + "lockButtonLabel": MessageLookupByLibrary.simpleMessage("Lås"), + "logInLabel": MessageLookupByLibrary.simpleMessage("Logg inn"), + "loginTerms": MessageLookupByLibrary.simpleMessage( + "Ved å klikke Logg inn, godtar jeg brukervilkårene og personvernreglene"), + "lostDevice": MessageLookupByLibrary.simpleMessage("Mistet enhet?"), + "machineLearning": MessageLookupByLibrary.simpleMessage("Maskinlæring"), + "magicSearch": MessageLookupByLibrary.simpleMessage("Magisk søk"), + "manage": MessageLookupByLibrary.simpleMessage("Administrer"), + "manageDeviceStorage": + MessageLookupByLibrary.simpleMessage("Behandle enhetslagring"), + "manageLink": MessageLookupByLibrary.simpleMessage("Administrer lenke"), + "manageParticipants": + MessageLookupByLibrary.simpleMessage("Administrer"), + "memoryCount": m0, + "moderateStrength": MessageLookupByLibrary.simpleMessage("Moderat"), + "movedToTrash": + MessageLookupByLibrary.simpleMessage("Flyttet til papirkurven"), + "never": MessageLookupByLibrary.simpleMessage("Aldri"), + "newAlbum": MessageLookupByLibrary.simpleMessage("Nytt album"), + "noDeviceLimit": MessageLookupByLibrary.simpleMessage("Ingen"), + "noRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Ingen gjenopprettingsnøkkel?"), + "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( + "Grunnet vår type ente-til-ende-krypteringsprotokoll kan ikke dine data dekrypteres uten passordet ditt eller gjenopprettingsnøkkelen din"), + "notifications": MessageLookupByLibrary.simpleMessage("Varslinger"), + "ok": MessageLookupByLibrary.simpleMessage("Ok"), + "oops": MessageLookupByLibrary.simpleMessage("Oisann"), + "orPickAnExistingOne": + MessageLookupByLibrary.simpleMessage("Eller velg en eksisterende"), + "password": MessageLookupByLibrary.simpleMessage("Passord"), + "passwordChangedSuccessfully": + MessageLookupByLibrary.simpleMessage("Passordet ble endret"), + "passwordLock": MessageLookupByLibrary.simpleMessage("Passordlås"), + "passwordStrength": m41, + "passwordWarning": MessageLookupByLibrary.simpleMessage( + "Vi lagrer ikke dette passordet, så hvis du glemmer det, kan vi ikke dekryptere dataene dine"), + "pendingItems": + MessageLookupByLibrary.simpleMessage("Ventende elementer"), + "photoGridSize": + MessageLookupByLibrary.simpleMessage("Bilderutenettstørrelse"), + "photoSmallCase": MessageLookupByLibrary.simpleMessage("bilde"), + "pleaseTryAgain": + MessageLookupByLibrary.simpleMessage("Vennligst prøv igjen"), + "pleaseWait": MessageLookupByLibrary.simpleMessage("Vennligst vent..."), + "privacyPolicyTitle": + MessageLookupByLibrary.simpleMessage("Personvernserklæring"), + "publicLinkEnabled": + MessageLookupByLibrary.simpleMessage("Offentlig lenke aktivert"), + "recover": MessageLookupByLibrary.simpleMessage("Gjenopprett"), + "recoverAccount": + MessageLookupByLibrary.simpleMessage("Gjenopprett konto"), + "recoverButton": MessageLookupByLibrary.simpleMessage("Gjenopprett"), + "recoveryKey": + MessageLookupByLibrary.simpleMessage("Gjenopprettingsnøkkel"), + "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( + "Gjenopprettingsnøkkel kopiert til utklippstavlen"), + "recoveryKeyOnForgotPassword": MessageLookupByLibrary.simpleMessage( + "Hvis du glemmer passordet ditt er den eneste måten du kan gjenopprette dataene dine på med denne nøkkelen."), + "recoveryKeySaveDescription": MessageLookupByLibrary.simpleMessage( + "Vi lagrer ikke denne nøkkelen, vennligst lagre denne 24-ords nøkkelen på et trygt sted."), + "recoveryKeySuccessBody": MessageLookupByLibrary.simpleMessage( + "Flott! Din gjenopprettingsnøkkel er gyldig. Takk for bekreftelsen.\n\nVennligst husk å holde gjenopprettingsnøkkelen din trygt sikkerhetskopiert."), + "recoveryKeyVerified": MessageLookupByLibrary.simpleMessage( + "Gjenopprettingsnøkkel bekreftet"), + "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( + "Gjenopprettings nøkkelen er den eneste måten å gjenopprette bildene dine hvis du glemmer passordet ditt. Du kan finne gjenopprettingsnøkkelen din i Innstillinger > Sikkerhet.\n\nVennligst skriv inn gjenopprettingsnøkkelen din her for å bekrefte at du har lagret den riktig."), + "recoverySuccessful": MessageLookupByLibrary.simpleMessage( + "Gjenopprettingen var vellykket!"), + "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( + "Den gjeldende enheten er ikke kraftig nok til å verifisere passordet ditt, men vi kan regenerere på en måte som fungerer på alle enheter.\n\nVennligst logg inn med gjenopprettingsnøkkelen og regenerer passordet (du kan bruke den samme igjen om du vil)."), + "recreatePasswordTitle": + MessageLookupByLibrary.simpleMessage("Gjenopprett passord"), + "referrals": MessageLookupByLibrary.simpleMessage("Vervinger"), + "remindToEmptyEnteTrash": MessageLookupByLibrary.simpleMessage( + "Du kan også tømme \"Papirkurven\" for å få den frigjorte lagringsplassen"), + "remove": MessageLookupByLibrary.simpleMessage("Fjern"), + "removeLink": MessageLookupByLibrary.simpleMessage("Fjern lenke"), + "removeParticipant": + MessageLookupByLibrary.simpleMessage("Fjern deltaker"), + "removePublicLink": + MessageLookupByLibrary.simpleMessage("Fjern offentlig lenke"), + "resendEmail": + MessageLookupByLibrary.simpleMessage("Send e-posten på nytt"), + "resetPasswordTitle": + MessageLookupByLibrary.simpleMessage("Tilbakestill passord"), + "saveKey": MessageLookupByLibrary.simpleMessage("Lagre nøkkel"), + "saveYourRecoveryKeyIfYouHaventAlready": MessageLookupByLibrary.simpleMessage( - "Long press an email to verify end to end encryption."), - "modifyYourQueryOrTrySearchingFor": + "Lagre gjenopprettingsnøkkelen hvis du ikke allerede har gjort det"), + "scanCode": MessageLookupByLibrary.simpleMessage("Skann kode"), + "scanThisBarcodeWithnyourAuthenticatorApp": MessageLookupByLibrary.simpleMessage( - "Modify your query, or try searching for"), - "moveToHiddenAlbum": - MessageLookupByLibrary.simpleMessage("Move to hidden album"), - "next": MessageLookupByLibrary.simpleMessage("Next"), - "noQuickLinksSelected": - MessageLookupByLibrary.simpleMessage("No quick links selected"), - "noSystemLockFound": - MessageLookupByLibrary.simpleMessage("No system lock found"), - "passwordLock": MessageLookupByLibrary.simpleMessage("Password lock"), - "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( - "Password strength is calculated considering the length of the password, used characters, and whether or not the password appears in the top 10,000 most used passwords"), - "pinLock": MessageLookupByLibrary.simpleMessage("PIN lock"), - "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( - "Please select quick links to remove"), - "reenterPassword": - MessageLookupByLibrary.simpleMessage("Re-enter password"), - "reenterPin": MessageLookupByLibrary.simpleMessage("Re-enter PIN"), - "removePersonLabel": - MessageLookupByLibrary.simpleMessage("Remove person label"), - "removePublicLinks": - MessageLookupByLibrary.simpleMessage("Remove public links"), - "search": MessageLookupByLibrary.simpleMessage("Search"), - "selectALocation": - MessageLookupByLibrary.simpleMessage("Select a location"), - "selectALocationFirst": - MessageLookupByLibrary.simpleMessage("Select a location first"), - "setNewPassword": - MessageLookupByLibrary.simpleMessage("Set new password"), - "setNewPin": MessageLookupByLibrary.simpleMessage("Set new PIN"), - "tapToUnlock": MessageLookupByLibrary.simpleMessage("Tap to unlock"), - "thisWillRemovePublicLinksOfAllSelectedQuickLinks": + "Skann denne strekkoden med\nautentiseringsappen din"), + "security": MessageLookupByLibrary.simpleMessage("Sikkerhet"), + "selectAll": MessageLookupByLibrary.simpleMessage("Velg alle"), + "selectFoldersForBackup": MessageLookupByLibrary.simpleMessage( + "Velg mapper for sikkerhetskopiering"), + "selectReason": MessageLookupByLibrary.simpleMessage("Velg grunn"), + "selectedFoldersWillBeEncryptedAndBackedUp": MessageLookupByLibrary.simpleMessage( - "This will remove public links of all selected quick links."), - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": + "Valgte mapper vil bli kryptert og sikkerhetskopiert"), + "selectedPhotos": m1, + "selectedPhotosWithYours": m51, + "sendEmail": MessageLookupByLibrary.simpleMessage("Send e-post"), + "sendInvite": MessageLookupByLibrary.simpleMessage("Send invitasjon"), + "sendLink": MessageLookupByLibrary.simpleMessage("Send lenke"), + "setAPassword": MessageLookupByLibrary.simpleMessage("Lag et passord"), + "setPasswordTitle": + MessageLookupByLibrary.simpleMessage("Lag et passord"), + "setupComplete": + MessageLookupByLibrary.simpleMessage("Oppsett fullført"), + "shareALink": MessageLookupByLibrary.simpleMessage("Del en lenke"), + "shareMyVerificationID": m52, + "shareTextConfirmOthersVerificationID": m2, + "shareWithPeopleSectionTitle": m54, + "sharedPhotoNotifications": + MessageLookupByLibrary.simpleMessage("Nye delte bilder"), + "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( + "Motta varsler når noen legger til et bilde i et delt album som du er en del av"), + "sharing": MessageLookupByLibrary.simpleMessage("Deler..."), + "signUpTerms": MessageLookupByLibrary.simpleMessage( + "Jeg godtar bruksvilkårene og personvernreglene"), + "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( + "Den vil bli slettet fra alle album."), + "skip": MessageLookupByLibrary.simpleMessage("Hopp over"), + "someoneSharingAlbumsWithYouShouldSeeTheSameId": MessageLookupByLibrary.simpleMessage( - "To enable app lock, please setup device passcode or screen lock in your system settings."), - "tooManyIncorrectAttempts": - MessageLookupByLibrary.simpleMessage("Too many incorrect attempts"), + "Folk som deler album med deg bør se den samme ID-en på deres enhet."), + "somethingWentWrong": + MessageLookupByLibrary.simpleMessage("Noe gikk galt"), + "somethingWentWrongPleaseTryAgain": + MessageLookupByLibrary.simpleMessage( + "Noe gikk galt. Vennligst prøv igjen"), + "sorry": MessageLookupByLibrary.simpleMessage("Beklager"), + "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": + MessageLookupByLibrary.simpleMessage( + "Beklager, vi kunne ikke generere sikre nøkler på denne enheten.\n\nvennligst registrer deg fra en annen enhet."), + "sparkleSuccess": MessageLookupByLibrary.simpleMessage("✨ Suksess"), + "status": MessageLookupByLibrary.simpleMessage("Status"), + "strongStrength": MessageLookupByLibrary.simpleMessage("Sterkt"), + "tapToCopy": + MessageLookupByLibrary.simpleMessage("trykk for å kopiere"), + "tapToEnterCode": + MessageLookupByLibrary.simpleMessage("Trykk for å angi kode"), + "terminate": MessageLookupByLibrary.simpleMessage("Avslutte"), + "terminateSession": + MessageLookupByLibrary.simpleMessage("Avslutte økten?"), + "termsOfServicesTitle": MessageLookupByLibrary.simpleMessage("Vilkår"), + "thisCanBeUsedToRecoverYourAccountIfYou": + MessageLookupByLibrary.simpleMessage( + "Dette kan brukes til å gjenopprette kontoen din hvis du mister din andre faktor"), + "thisDevice": MessageLookupByLibrary.simpleMessage("Denne enheten"), + "thisIsPersonVerificationId": m65, + "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( + "Dette er din bekreftelses-ID"), + "thisWillLogYouOutOfTheFollowingDevice": + MessageLookupByLibrary.simpleMessage( + "Dette vil logge deg ut av følgende enhet:"), + "thisWillLogYouOutOfThisDevice": MessageLookupByLibrary.simpleMessage( + "Dette vil logge deg ut av denne enheten!"), + "toResetVerifyEmail": MessageLookupByLibrary.simpleMessage( + "For å tilbakestille passordet ditt, vennligt bekreft e-posten din først."), + "trash": MessageLookupByLibrary.simpleMessage("Papirkurv"), + "tryAgain": MessageLookupByLibrary.simpleMessage("Prøv igjen"), + "twofactorAuthenticationPageTitle": + MessageLookupByLibrary.simpleMessage("Tofaktorautentisering"), + "twofactorSetup": + MessageLookupByLibrary.simpleMessage("Oppsett av to-faktor"), + "uncategorized": MessageLookupByLibrary.simpleMessage("Ukategorisert"), + "unselectAll": MessageLookupByLibrary.simpleMessage("Velg bort alle"), + "updatingFolderSelection": + MessageLookupByLibrary.simpleMessage("Oppdaterer mappevalg..."), + "useRecoveryKey": + MessageLookupByLibrary.simpleMessage("Bruk gjenopprettingsnøkkel"), + "verificationId": + MessageLookupByLibrary.simpleMessage("Verifiserings-ID"), "verify": MessageLookupByLibrary.simpleMessage("Bekreft"), - "yourMap": MessageLookupByLibrary.simpleMessage("Your map") + "verifyEmail": + MessageLookupByLibrary.simpleMessage("Bekreft e-postadresse"), + "verifyEmailID": m68, + "verifyPassword": + MessageLookupByLibrary.simpleMessage("Bekreft passord"), + "verifyingRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Verifiserer gjenopprettingsnøkkel..."), + "videoSmallCase": MessageLookupByLibrary.simpleMessage("video"), + "viewRecoveryKey": + MessageLookupByLibrary.simpleMessage("Vis gjenopprettingsnøkkel"), + "viewer": MessageLookupByLibrary.simpleMessage("Seer"), + "weHaveSendEmailTo": m69, + "weakStrength": MessageLookupByLibrary.simpleMessage("Svakt"), + "welcomeBack": + MessageLookupByLibrary.simpleMessage("Velkommen tilbake!"), + "yesConvertToViewer": + MessageLookupByLibrary.simpleMessage("Ja, konverter til seer"), + "yesDelete": MessageLookupByLibrary.simpleMessage("Ja, slett"), + "you": MessageLookupByLibrary.simpleMessage("Deg"), + "youCannotShareWithYourself": MessageLookupByLibrary.simpleMessage( + "Du kan ikke dele med deg selv"), + "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage( + "Brukeren din har blitt slettet") }; } diff --git a/mobile/lib/generated/intl/messages_pl.dart b/mobile/lib/generated/intl/messages_pl.dart index 5d80b3aaa2..8cb6018be4 100644 --- a/mobile/lib/generated/intl/messages_pl.dart +++ b/mobile/lib/generated/intl/messages_pl.dart @@ -20,37 +20,37 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'pl'; - static String m0(count) => + static String m3(count) => "${Intl.plural(count, one: 'Dodaj współuczestnika', few: 'Dodaj współuczestników', many: 'Dodaj współuczestników', other: 'Dodaj współuczestników')}"; - static String m2(count) => + static String m4(count) => "${Intl.plural(count, one: 'Dodaj element', few: 'Dodaj elementy', other: 'Dodaj elementów')}"; - static String m3(storageAmount, endDate) => + static String m5(storageAmount, endDate) => "Twój dodatek ${storageAmount} jest ważny do ${endDate}"; - static String m1(count) => + static String m6(count) => "${Intl.plural(count, one: 'Dodaj widza', few: 'Dodaj widzów', many: 'Dodaj widzów', other: 'Dodaj widzów')}"; - static String m4(emailOrName) => "Dodane przez ${emailOrName}"; + static String m7(emailOrName) => "Dodane przez ${emailOrName}"; - static String m5(albumName) => "Pomyślnie dodano do ${albumName}"; + static String m8(albumName) => "Pomyślnie dodano do ${albumName}"; - static String m6(count) => + static String m9(count) => "${Intl.plural(count, zero: 'Brak Uczestników', one: '1 Uczestnik', other: '${count} Uczestników')}"; - static String m7(versionValue) => "Wersja: ${versionValue}"; + static String m10(versionValue) => "Wersja: ${versionValue}"; - static String m8(freeAmount, storageUnit) => + static String m11(freeAmount, storageUnit) => "${freeAmount} ${storageUnit} za darmo"; - static String m9(paymentProvider) => + static String m12(paymentProvider) => "Prosimy najpierw anulować istniejącą subskrypcję z ${paymentProvider}"; - static String m10(user) => + static String m13(user) => "${user} nie będzie mógł dodać więcej zdjęć do tego albumu\n\nJednak nadal będą mogli usunąć istniejące zdjęcia, które dodali"; - static String m11(isFamilyMember, storageAmountInGb) => + static String m14(isFamilyMember, storageAmountInGb) => "${Intl.select(isFamilyMember, { 'true': 'Twoja rodzina odebrała ${storageAmountInGb} GB do tej pory', @@ -58,115 +58,115 @@ class MessageLookup extends MessageLookupByLibrary { 'other': 'Odebrałeś ${storageAmountInGb} GB do tej pory!', })}"; - static String m12(albumName) => "Utworzono link współpracy dla ${albumName}"; + static String m15(albumName) => "Utworzono link współpracy dla ${albumName}"; - static String m13(familyAdminEmail) => + static String m16(familyAdminEmail) => "Prosimy skontaktować się z ${familyAdminEmail}, by zarzadząć swoją subskrypcją"; - static String m14(provider) => + static String m17(provider) => "Skontaktuj się z nami pod adresem support@ente.io, aby zarządzać subskrypcją ${provider}."; - static String m15(endpoint) => "Połączono z ${endpoint}"; + static String m18(endpoint) => "Połączono z ${endpoint}"; - static String m16(count) => + static String m19(count) => "${Intl.plural(count, one: 'Usuń ${count} element', few: 'Usuń ${count} elementy', many: 'Usuń ${count} elementów', other: 'Usuń ${count} elementu')}"; - static String m17(currentlyDeleting, totalCount) => + static String m20(currentlyDeleting, totalCount) => "Usuwanie ${currentlyDeleting} / ${totalCount}"; - static String m18(albumName) => + static String m21(albumName) => "Spowoduje to usunięcie publicznego linku dostępu do \"${albumName}\"."; - static String m19(supportEmail) => + static String m22(supportEmail) => "Wyślij wiadomość e-mail na ${supportEmail} z zarejestrowanego adresu e-mail"; - static String m20(count, storageSaved) => + static String m23(count, storageSaved) => "Wyczyszczono ${Intl.plural(count, one: '${count} zdduplikowany plik', other: '${count} zdduplikowane pliki')}, oszczędzając (${storageSaved}!)"; - static String m21(count, formattedSize) => + static String m24(count, formattedSize) => "${count} plików, każdy po ${formattedSize}"; - static String m22(newEmail) => "Adres e-mail został zmieniony na ${newEmail}"; + static String m25(newEmail) => "Adres e-mail został zmieniony na ${newEmail}"; - static String m23(email) => + static String m26(email) => "${email} nie posiada konta Ente.\n\nWyślij im zaproszenie do udostępniania zdjęć."; - static String m24(count, formattedNumber) => + static String m27(count, formattedNumber) => "${Intl.plural(count, one: '1 plikowi', other: '${formattedNumber} plikom')} na tym urządzeniu została bezpiecznie utworzona kopia zapasowa"; - static String m25(count, formattedNumber) => + static String m28(count, formattedNumber) => "${Intl.plural(count, one: '1 plikowi', other: '${formattedNumber} plikom')} w tym albumie została bezpiecznie utworzona kopia zapasowa"; - static String m26(storageAmountInGB) => + static String m29(storageAmountInGB) => "${storageAmountInGB} GB za każdym razem, gdy ktoś zarejestruje się w płatnym planie i użyje twojego kodu"; - static String m27(endDate) => "Okres próbny ważny do ${endDate}"; + static String m30(endDate) => "Okres próbny ważny do ${endDate}"; - static String m28(count) => + static String m31(count) => "Nadal możesz mieć dostęp ${Intl.plural(count, one: 'do tego', other: 'do tych')} na Ente tak długo, jak masz aktywną subskrypcję"; - static String m29(sizeInMBorGB) => "Zwolnij ${sizeInMBorGB}"; + static String m32(sizeInMBorGB) => "Zwolnij ${sizeInMBorGB}"; - static String m30(count, formattedSize) => + static String m33(count, formattedSize) => "${Intl.plural(count, one: 'Można to usunąć z urządzenia, aby zwolnić ${formattedSize}', other: 'Można je usunąć z urządzenia, aby zwolnić ${formattedSize}')}"; - static String m31(currentlyProcessing, totalCount) => + static String m34(currentlyProcessing, totalCount) => "Przetwarzanie ${currentlyProcessing} / ${totalCount}"; - static String m32(count) => + static String m35(count) => "${Intl.plural(count, one: '${count} element', few: '${count} elementy', many: '${count} elementów', other: '${count} elementu')}"; - static String m33(expiryTime) => "Link wygaśnie ${expiryTime}"; + static String m36(expiryTime) => "Link wygaśnie ${expiryTime}"; - static String m34(count, formattedCount) => + static String m0(count, formattedCount) => "${Intl.plural(count, zero: 'brak wspomnień', one: '${formattedCount} wspomnienie', few: '${formattedCount} wspomnienia', other: '${formattedCount} wspomnień')}"; - static String m35(count) => + static String m37(count) => "${Intl.plural(count, one: 'Przenieś element', few: 'Przenieś elementy', other: 'Przenieś elementów')}"; - static String m36(albumName) => "Pomyślnie przeniesiono do ${albumName}"; + static String m38(albumName) => "Pomyślnie przeniesiono do ${albumName}"; - static String m37(name) => "Nie ${name}?"; + static String m39(name) => "Nie ${name}?"; - static String m38(familyAdminEmail) => + static String m40(familyAdminEmail) => "Skontaktuj się z ${familyAdminEmail}, aby zmienić swój kod."; - static String m39(passwordStrengthValue) => + static String m41(passwordStrengthValue) => "Siła hasła: ${passwordStrengthValue}"; - static String m40(providerName) => + static String m42(providerName) => "Porozmawiaj ze wsparciem ${providerName} jeśli zostałeś obciążony"; - static String m41(endDate) => + static String m43(endDate) => "Bezpłatny okres próbny ważny do ${endDate}.\nNastępnie możesz wybrać płatny plan."; - static String m42(toEmail) => + static String m44(toEmail) => "Prosimy o kontakt mailowy pod adresem ${toEmail}"; - static String m43(toEmail) => "Prosimy wysłać logi do ${toEmail}"; + static String m45(toEmail) => "Prosimy wysłać logi do ${toEmail}"; - static String m44(storeName) => "Oceń nas na ${storeName}"; + static String m46(storeName) => "Oceń nas na ${storeName}"; - static String m45(storageInGB) => + static String m47(storageInGB) => "3. Oboje otrzymujecie ${storageInGB} GB* za darmo"; - static String m46(userEmail) => + static String m48(userEmail) => "${userEmail} zostanie usunięty z tego udostępnionego albumu\n\nWszelkie dodane przez nich zdjęcia zostaną usunięte z albumu"; - static String m47(endDate) => "Subskrypcja odnowi się ${endDate}"; + static String m49(endDate) => "Subskrypcja odnowi się ${endDate}"; - static String m48(count) => + static String m50(count) => "${Intl.plural(count, one: 'Znaleziono ${count} wynik', few: 'Znaleziono ${count} wyniki', other: 'Znaleziono ${count} wyników')}"; - static String m49(count) => "Wybrano ${count}"; + static String m1(count) => "Wybrano ${count}"; - static String m50(count, yourCount) => + static String m51(count, yourCount) => "Wybrano ${count} (twoich ${yourCount})"; - static String m51(verificationID) => + static String m52(verificationID) => "Oto mój identyfikator weryfikacyjny: ${verificationID} dla ente.io."; - static String m52(verificationID) => + static String m2(verificationID) => "Hej, czy możesz potwierdzić, że to jest Twój identyfikator weryfikacyjny ente.io: ${verificationID}"; static String m53(referralCode, referralStorageInGB) => @@ -236,10 +236,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Dodaj nowy adres e-mail"), "addCollaborator": MessageLookupByLibrary.simpleMessage("Dodaj współuczestnika"), - "addCollaborators": m0, + "addCollaborators": m3, "addFromDevice": MessageLookupByLibrary.simpleMessage("Dodaj z urządzenia"), - "addItem": m2, + "addItem": m4, "addLocation": MessageLookupByLibrary.simpleMessage("Dodaj lokalizację"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Dodaj"), @@ -247,7 +247,7 @@ class MessageLookup extends MessageLookupByLibrary { "addNew": MessageLookupByLibrary.simpleMessage("Dodaj nowe"), "addOnPageSubtitle": MessageLookupByLibrary.simpleMessage("Szczegóły dodatków"), - "addOnValidTill": m3, + "addOnValidTill": m5, "addOns": MessageLookupByLibrary.simpleMessage("Dodatki"), "addPhotos": MessageLookupByLibrary.simpleMessage("Dodaj zdjęcia"), "addSelected": MessageLookupByLibrary.simpleMessage("Dodaj zaznaczone"), @@ -256,12 +256,12 @@ class MessageLookup extends MessageLookupByLibrary { "addToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Dodaj do ukrytego albumu"), "addViewer": MessageLookupByLibrary.simpleMessage("Dodaj widza"), - "addViewers": m1, + "addViewers": m6, "addYourPhotosNow": MessageLookupByLibrary.simpleMessage("Dodaj swoje zdjęcia teraz"), "addedAs": MessageLookupByLibrary.simpleMessage("Dodano jako"), - "addedBy": m4, - "addedSuccessfullyTo": m5, + "addedBy": m7, + "addedSuccessfullyTo": m8, "addingToFavorites": MessageLookupByLibrary.simpleMessage("Dodawanie do ulubionych..."), "advanced": MessageLookupByLibrary.simpleMessage("Zaawansowane"), @@ -273,7 +273,7 @@ class MessageLookup extends MessageLookupByLibrary { "after1Week": MessageLookupByLibrary.simpleMessage("Po 1 tygodniu"), "after1Year": MessageLookupByLibrary.simpleMessage("Po 1 roku"), "albumOwner": MessageLookupByLibrary.simpleMessage("Właściciel"), - "albumParticipantsCount": m6, + "albumParticipantsCount": m9, "albumTitle": MessageLookupByLibrary.simpleMessage("Tytuł albumu"), "albumUpdated": MessageLookupByLibrary.simpleMessage("Album został zaktualizowany"), @@ -315,7 +315,7 @@ class MessageLookup extends MessageLookupByLibrary { "Blokada dostępu do aplikacji"), "appLockDescriptions": MessageLookupByLibrary.simpleMessage( "Wybierz między domyślnym ekranem blokady urządzenia a niestandardowym ekranem blokady z kodem PIN lub hasłem."), - "appVersion": m7, + "appVersion": m10, "appleId": MessageLookupByLibrary.simpleMessage("Apple ID"), "apply": MessageLookupByLibrary.simpleMessage("Zastosuj"), "applyCodeTitle": MessageLookupByLibrary.simpleMessage("Użyj kodu"), @@ -392,7 +392,7 @@ class MessageLookup extends MessageLookupByLibrary { "autoPairDesc": MessageLookupByLibrary.simpleMessage( "Automatyczne parowanie działa tylko z urządzeniami obsługującymi Chromecast."), "available": MessageLookupByLibrary.simpleMessage("Dostępne"), - "availableStorageSpace": m8, + "availableStorageSpace": m11, "backedUpFolders": MessageLookupByLibrary.simpleMessage("Foldery kopii zapasowej"), "backup": MessageLookupByLibrary.simpleMessage("Kopia zapasowa"), @@ -419,10 +419,10 @@ class MessageLookup extends MessageLookupByLibrary { "canOnlyRemoveFilesOwnedByYou": MessageLookupByLibrary.simpleMessage( "Można usuwać tylko pliki należące do Ciebie"), "cancel": MessageLookupByLibrary.simpleMessage("Anuluj"), - "cancelOtherSubscription": m9, + "cancelOtherSubscription": m12, "cancelSubscription": MessageLookupByLibrary.simpleMessage("Anuluj subskrypcję"), - "cannotAddMorePhotosAfterBecomingViewer": m10, + "cannotAddMorePhotosAfterBecomingViewer": m13, "cannotDeleteSharedFiles": MessageLookupByLibrary.simpleMessage( "Nie można usunąć udostępnionych plików"), "castIPMismatchBody": MessageLookupByLibrary.simpleMessage( @@ -468,7 +468,7 @@ class MessageLookup extends MessageLookupByLibrary { "Odbierz bezpłatną przestrzeń dyskową"), "claimMore": MessageLookupByLibrary.simpleMessage("Zdobądź więcej!"), "claimed": MessageLookupByLibrary.simpleMessage("Odebrano"), - "claimedStorageSoFar": m11, + "claimedStorageSoFar": m14, "cleanUncategorized": MessageLookupByLibrary.simpleMessage("Wyczyść Nieskategoryzowane"), "cleanUncategorizedDescription": MessageLookupByLibrary.simpleMessage( @@ -498,7 +498,7 @@ class MessageLookup extends MessageLookupByLibrary { "Utwórz link, aby umożliwić innym dodawanie i przeglądanie zdjęć w udostępnionym albumie bez konieczności korzystania z aplikacji lub konta Ente. Świetne rozwiązanie do gromadzenia zdjęć ze wspólnych wydarzeń."), "collaborativeLink": MessageLookupByLibrary.simpleMessage("Link do współpracy"), - "collaborativeLinkCreatedFor": m12, + "collaborativeLinkCreatedFor": m15, "collaborator": MessageLookupByLibrary.simpleMessage("Współuczestnik"), "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": MessageLookupByLibrary.simpleMessage( @@ -527,10 +527,10 @@ class MessageLookup extends MessageLookupByLibrary { "Potwierdź klucz odzyskiwania"), "connectToDevice": MessageLookupByLibrary.simpleMessage("Połącz z urządzeniem"), - "contactFamilyAdmin": m13, + "contactFamilyAdmin": m16, "contactSupport": MessageLookupByLibrary.simpleMessage( "Skontaktuj się z pomocą techniczną"), - "contactToManageSubscription": m14, + "contactToManageSubscription": m17, "contacts": MessageLookupByLibrary.simpleMessage("Kontakty"), "contents": MessageLookupByLibrary.simpleMessage("Zawartość"), "continueLabel": MessageLookupByLibrary.simpleMessage("Kontynuuj"), @@ -574,7 +574,7 @@ class MessageLookup extends MessageLookupByLibrary { "currentUsageIs": MessageLookupByLibrary.simpleMessage("Aktualne użycie to "), "custom": MessageLookupByLibrary.simpleMessage("Niestandardowy"), - "customEndpoint": m15, + "customEndpoint": m18, "darkTheme": MessageLookupByLibrary.simpleMessage("Ciemny"), "dayToday": MessageLookupByLibrary.simpleMessage("Dzisiaj"), "dayYesterday": MessageLookupByLibrary.simpleMessage("Wczoraj"), @@ -607,11 +607,11 @@ class MessageLookup extends MessageLookupByLibrary { "deleteFromDevice": MessageLookupByLibrary.simpleMessage("Usuń z urządzenia"), "deleteFromEnte": MessageLookupByLibrary.simpleMessage("Usuń z Ente"), - "deleteItemCount": m16, + "deleteItemCount": m19, "deleteLocation": MessageLookupByLibrary.simpleMessage("Usuń lokalizację"), "deletePhotos": MessageLookupByLibrary.simpleMessage("Usuń zdjęcia"), - "deleteProgress": m17, + "deleteProgress": m20, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Brakuje kluczowej funkcji, której potrzebuję"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -652,7 +652,7 @@ class MessageLookup extends MessageLookupByLibrary { "Widzowie mogą nadal robić zrzuty ekranu lub zapisywać kopie zdjęć za pomocą programów trzecich"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Uwaga"), - "disableLinkMessage": m18, + "disableLinkMessage": m21, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Wyłącz uwierzytelnianie dwustopniowe"), "disablingTwofactorAuthentication": @@ -674,9 +674,9 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("Pobieranie nie powiodło się"), "downloading": MessageLookupByLibrary.simpleMessage("Pobieranie..."), - "dropSupportEmail": m19, - "duplicateFileCountWithStorageSaved": m20, - "duplicateItemsGroup": m21, + "dropSupportEmail": m22, + "duplicateFileCountWithStorageSaved": m23, + "duplicateItemsGroup": m24, "edit": MessageLookupByLibrary.simpleMessage("Edytuj"), "editLocation": MessageLookupByLibrary.simpleMessage("Edytuj lokalizację"), @@ -688,8 +688,8 @@ class MessageLookup extends MessageLookupByLibrary { "Edycje lokalizacji będą widoczne tylko w Ente"), "eligible": MessageLookupByLibrary.simpleMessage("kwalifikujący się"), "email": MessageLookupByLibrary.simpleMessage("Adres e-mail"), - "emailChangedTo": m22, - "emailNoEnteAccount": m23, + "emailChangedTo": m25, + "emailNoEnteAccount": m26, "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("Weryfikacja e-mail"), "emailYourLogs": @@ -800,8 +800,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Rodzaje plików"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Typy plików i nazwy"), - "filesBackedUpFromDevice": m24, - "filesBackedUpInAlbum": m25, + "filesBackedUpFromDevice": m27, + "filesBackedUpInAlbum": m28, "filesDeleted": MessageLookupByLibrary.simpleMessage("Pliki usunięto"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage("Pliki zapisane do galerii"), @@ -815,26 +815,26 @@ class MessageLookup extends MessageLookupByLibrary { "foundFaces": MessageLookupByLibrary.simpleMessage("Znaleziono twarze"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage( "Bezpłatna pamięć, którą odebrano"), - "freeStorageOnReferralSuccess": m26, + "freeStorageOnReferralSuccess": m29, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("Darmowa pamięć użyteczna"), "freeTrial": MessageLookupByLibrary.simpleMessage("Darmowy okres próbny"), - "freeTrialValidTill": m27, - "freeUpAccessPostDelete": m28, - "freeUpAmount": m29, + "freeTrialValidTill": m30, + "freeUpAccessPostDelete": m31, + "freeUpAmount": m32, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage( "Zwolnij miejsce na urządzeniu"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Oszczędzaj miejsce na urządzeniu poprzez wyczyszczenie plików, które zostały już przesłane."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Zwolnij miejsce"), - "freeUpSpaceSaving": m30, + "freeUpSpaceSaving": m33, "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "W galerii wyświetlane jest do 1000 pamięci"), "general": MessageLookupByLibrary.simpleMessage("Ogólne"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Generowanie kluczy szyfrujących..."), - "genericProgress": m31, + "genericProgress": m34, "goToSettings": MessageLookupByLibrary.simpleMessage("Przejdź do ustawień"), "googlePlayId": @@ -913,7 +913,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Wygląda na to, że coś poszło nie tak. Spróbuj ponownie po pewnym czasie. Jeśli błąd będzie się powtarzał, skontaktuj się z naszym zespołem pomocy technicznej."), - "itemCount": m32, + "itemCount": m35, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Elementy pokazują liczbę dni pozostałych przed trwałym usunięciem"), @@ -942,7 +942,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Limit urządzeń"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Aktywny"), "linkExpired": MessageLookupByLibrary.simpleMessage("Wygasł"), - "linkExpiresOn": m33, + "linkExpiresOn": m36, "linkExpiry": MessageLookupByLibrary.simpleMessage("Wygaśnięcie linku"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("Link wygasł"), "linkNeverExpires": MessageLookupByLibrary.simpleMessage("Nigdy"), @@ -1023,7 +1023,7 @@ class MessageLookup extends MessageLookupByLibrary { "maps": MessageLookupByLibrary.simpleMessage("Mapy"), "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), - "memoryCount": m34, + "memoryCount": m0, "merchandise": MessageLookupByLibrary.simpleMessage("Sklep"), "mlConsent": MessageLookupByLibrary.simpleMessage("Włącz uczenie maszynowe"), @@ -1047,12 +1047,12 @@ class MessageLookup extends MessageLookupByLibrary { "monthly": MessageLookupByLibrary.simpleMessage("Miesięcznie"), "moreDetails": MessageLookupByLibrary.simpleMessage("Więcej szczegółów"), - "moveItem": m35, + "moveItem": m37, "moveToAlbum": MessageLookupByLibrary.simpleMessage("Przenieś do albumu"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Przenieś do ukrytego albumu"), - "movedSuccessfullyTo": m36, + "movedSuccessfullyTo": m38, "movedToTrash": MessageLookupByLibrary.simpleMessage("Przeniesiono do kosza"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1100,7 +1100,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Nie znaleziono wyników"), "noSystemLockFound": MessageLookupByLibrary.simpleMessage( "Nie znaleziono blokady systemowej"), - "notPersonLabel": m37, + "notPersonLabel": m39, "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( "Nic Ci jeszcze nie udostępniono"), "nothingToSeeHere": MessageLookupByLibrary.simpleMessage( @@ -1110,7 +1110,7 @@ class MessageLookup extends MessageLookupByLibrary { "onDevice": MessageLookupByLibrary.simpleMessage("Na urządzeniu"), "onEnte": MessageLookupByLibrary.simpleMessage("W ente"), - "onlyFamilyAdminCanChangeCode": m38, + "onlyFamilyAdminCanChangeCode": m40, "oops": MessageLookupByLibrary.simpleMessage("Ups"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( "Ups, nie udało się zapisać zmian"), @@ -1139,7 +1139,7 @@ class MessageLookup extends MessageLookupByLibrary { "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage( "Hasło zostało pomyślnie zmienione"), "passwordLock": MessageLookupByLibrary.simpleMessage("Blokada hasłem"), - "passwordStrength": m39, + "passwordStrength": m41, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "Siła hasła jest obliczana, biorąc pod uwagę długość hasła, użyte znaki, i czy hasło pojawi się w 10 000 najczęściej używanych haseł"), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -1150,7 +1150,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Płatność się nie powiodła"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Niestety Twoja płatność nie powiodła się. Skontaktuj się z pomocą techniczną, a my Ci pomożemy!"), - "paymentFailedTalkToProvider": m40, + "paymentFailedTalkToProvider": m42, "pendingItems": MessageLookupByLibrary.simpleMessage("Oczekujące elementy"), "pendingSync": @@ -1179,7 +1179,7 @@ class MessageLookup extends MessageLookupByLibrary { "pinLock": MessageLookupByLibrary.simpleMessage("Blokada PIN"), "playOnTv": MessageLookupByLibrary.simpleMessage( "Odtwórz album na telewizorze"), - "playStoreFreeTrialValidTill": m41, + "playStoreFreeTrialValidTill": m43, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("Subskrypcja PlayStore"), "pleaseCheckYourInternetConnectionAndTryAgain": @@ -1191,14 +1191,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Skontaktuj się z pomocą techniczną, jeśli problem będzie się powtarzał"), - "pleaseEmailUsAt": m42, + "pleaseEmailUsAt": m44, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage( "Prosimy przyznać uprawnienia"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Zaloguj się ponownie"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Prosimy wybrać szybkie linki do usunięcia"), - "pleaseSendTheLogsTo": m43, + "pleaseSendTheLogsTo": m45, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Spróbuj ponownie"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1233,7 +1233,7 @@ class MessageLookup extends MessageLookupByLibrary { "raiseTicket": MessageLookupByLibrary.simpleMessage("Zgłoś"), "rateTheApp": MessageLookupByLibrary.simpleMessage("Oceń aplikację"), "rateUs": MessageLookupByLibrary.simpleMessage("Oceń nas"), - "rateUsOnStore": m44, + "rateUsOnStore": m46, "recover": MessageLookupByLibrary.simpleMessage("Odzyskaj"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Odzyskaj konto"), @@ -1269,7 +1269,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Przekaż ten kod swoim znajomym"), "referralStep2": MessageLookupByLibrary.simpleMessage("2. Wykupują płatny plan"), - "referralStep3": m45, + "referralStep3": m47, "referrals": MessageLookupByLibrary.simpleMessage("Polecenia"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Wysyłanie poleceń jest obecnie wstrzymane"), @@ -1295,7 +1295,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Usuń link"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Usuń użytkownika"), - "removeParticipantBody": m46, + "removeParticipantBody": m48, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Usuń etykietę osoby"), "removePublicLink": @@ -1314,7 +1314,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("Zmień nazwę pliku"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Odnów subskrypcję"), - "renewsOn": m47, + "renewsOn": m49, "reportABug": MessageLookupByLibrary.simpleMessage("Zgłoś błąd"), "reportBug": MessageLookupByLibrary.simpleMessage("Zgłoś błąd"), "resendEmail": @@ -1385,7 +1385,7 @@ class MessageLookup extends MessageLookupByLibrary { "Grupuj zdjęcia zrobione w promieniu zdjęcia"), "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage( "Zaproś ludzi, a zobaczysz tutaj wszystkie udostępnione przez nich zdjęcia"), - "searchResultCount": m48, + "searchResultCount": m50, "security": MessageLookupByLibrary.simpleMessage("Bezpieczeństwo"), "selectALocation": MessageLookupByLibrary.simpleMessage("Wybierz lokalizację"), @@ -1411,8 +1411,8 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage( "Wybrane elementy zostaną usunięte ze wszystkich albumów i przeniesione do kosza."), - "selectedPhotos": m49, - "selectedPhotosWithYours": m50, + "selectedPhotos": m1, + "selectedPhotosWithYours": m51, "send": MessageLookupByLibrary.simpleMessage("Wyślij"), "sendEmail": MessageLookupByLibrary.simpleMessage("Wyślij e-mail"), "sendInvite": @@ -1439,10 +1439,10 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Udostępnij teraz album"), "shareLink": MessageLookupByLibrary.simpleMessage("Udostępnij link"), - "shareMyVerificationID": m51, + "shareMyVerificationID": m52, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Udostępnij tylko ludziom, którym chcesz"), - "shareTextConfirmOthersVerificationID": m52, + "shareTextConfirmOthersVerificationID": m2, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Pobierz Ente, abyśmy mogli łatwo udostępniać zdjęcia i wideo w oryginalnej jakości\n\nhttps://ente.io"), "shareTextReferralCode": m53, @@ -1710,7 +1710,7 @@ class MessageLookup extends MessageLookupByLibrary { "Wyświetl wszystkie dane EXIF"), "viewLargeFiles": MessageLookupByLibrary.simpleMessage("Duże pliki"), "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( - "Wyświetl pliki zużywające największą ilość pamięci"), + "Wyświetl pliki zużywające największą ilość pamięci."), "viewLogs": MessageLookupByLibrary.simpleMessage("Wyświetl logi"), "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("Zobacz klucz odzyskiwania"), diff --git a/mobile/lib/generated/intl/messages_pt.dart b/mobile/lib/generated/intl/messages_pt.dart index af88659609..0472cbcbe0 100644 --- a/mobile/lib/generated/intl/messages_pt.dart +++ b/mobile/lib/generated/intl/messages_pt.dart @@ -20,37 +20,37 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'pt'; - static String m0(count) => + static String m3(count) => "${Intl.plural(count, zero: 'Adicionar colaborador', one: 'Adicionar colaborador', other: 'Adicionar colaboradores')}"; - static String m2(count) => + static String m4(count) => "${Intl.plural(count, one: 'Adicionar item', other: 'Adicionar itens')}"; - static String m3(storageAmount, endDate) => + static String m5(storageAmount, endDate) => "Seu complemento ${storageAmount} é válido até o dia ${endDate}"; - static String m1(count) => + static String m6(count) => "${Intl.plural(count, zero: 'Adicionar visualizador', one: 'Adicionar visualizador', other: 'Adicionar Visualizadores')}"; - static String m4(emailOrName) => "Adicionado por ${emailOrName}"; + static String m7(emailOrName) => "Adicionado por ${emailOrName}"; - static String m5(albumName) => "Adicionado com sucesso a ${albumName}"; + static String m8(albumName) => "Adicionado com sucesso a ${albumName}"; - static String m6(count) => + static String m9(count) => "${Intl.plural(count, zero: 'Nenhum Participante', one: '1 Participante', other: '${count} Participantes')}"; - static String m7(versionValue) => "Versão: ${versionValue}"; + static String m10(versionValue) => "Versão: ${versionValue}"; - static String m8(freeAmount, storageUnit) => + static String m11(freeAmount, storageUnit) => "${freeAmount} ${storageUnit} livre"; - static String m9(paymentProvider) => + static String m12(paymentProvider) => "Por favor, cancele sua assinatura existente do ${paymentProvider} primeiro"; - static String m10(user) => + static String m13(user) => "${user} Não poderá adicionar mais fotos a este álbum\n\nEles ainda poderão remover as fotos existentes adicionadas por eles"; - static String m11(isFamilyMember, storageAmountInGb) => + static String m14(isFamilyMember, storageAmountInGb) => "${Intl.select(isFamilyMember, { 'true': 'Sua família reeinvindicou ${storageAmountInGb} GB até agora', @@ -58,114 +58,114 @@ class MessageLookup extends MessageLookupByLibrary { 'other': 'Você reeinvindicou ${storageAmountInGb} GB até agora', })}"; - static String m12(albumName) => "Link colaborativo criado para ${albumName}"; + static String m15(albumName) => "Link colaborativo criado para ${albumName}"; - static String m13(familyAdminEmail) => + static String m16(familyAdminEmail) => "Entre em contato com ${familyAdminEmail} para gerenciar sua assinatura"; - static String m14(provider) => + static String m17(provider) => "Entre em contato conosco pelo e-mail support@ente.io para gerenciar sua assinatura ${provider}."; - static String m15(endpoint) => "Conectado a ${endpoint}"; + static String m18(endpoint) => "Conectado a ${endpoint}"; - static String m16(count) => + static String m19(count) => "${Intl.plural(count, one: 'Excluir ${count} item', other: 'Excluir ${count} itens')}"; - static String m17(currentlyDeleting, totalCount) => + static String m20(currentlyDeleting, totalCount) => "Excluindo ${currentlyDeleting} / ${totalCount}"; - static String m18(albumName) => + static String m21(albumName) => "Isso removerá o link público para acessar \"${albumName}\"."; - static String m19(supportEmail) => + static String m22(supportEmail) => "Por favor, envie um e-mail para ${supportEmail} a partir do seu endereço de e-mail registrado"; - static String m20(count, storageSaved) => + static String m23(count, storageSaved) => "Você limpou ${Intl.plural(count, one: '${count} arquivo duplicado', other: '${count} arquivos duplicados')}, salvando (${storageSaved}!)"; - static String m21(count, formattedSize) => + static String m24(count, formattedSize) => "${count} Arquivos, ${formattedSize} cada"; - static String m22(newEmail) => "E-mail alterado para ${newEmail}"; + static String m25(newEmail) => "E-mail alterado para ${newEmail}"; - static String m23(email) => + static String m26(email) => "${email} não possui uma conta Ente.\n\nEnvie um convite para compartilhar fotos."; - static String m24(count, formattedNumber) => + static String m27(count, formattedNumber) => "${Intl.plural(count, one: '1 arquivo', other: '${formattedNumber} arquivos')} neste dispositivo teve um backup seguro"; - static String m25(count, formattedNumber) => + static String m28(count, formattedNumber) => "${Intl.plural(count, one: '1 arquivo', other: '${formattedNumber} arquivos')} neste álbum teve um backup seguro"; - static String m26(storageAmountInGB) => + static String m29(storageAmountInGB) => "${storageAmountInGB} GB cada vez que alguém se inscrever para um plano pago e aplica o seu código"; - static String m27(endDate) => "Teste gratuito acaba em ${endDate}"; + static String m30(endDate) => "Teste gratuito acaba em ${endDate}"; - static String m28(count) => + static String m31(count) => "Você ainda pode acessar ${Intl.plural(count, one: 'ele', other: 'eles')} no Ente contanto que você tenha uma assinatura ativa"; - static String m29(sizeInMBorGB) => "Liberar ${sizeInMBorGB}"; + static String m32(sizeInMBorGB) => "Liberar ${sizeInMBorGB}"; - static String m30(count, formattedSize) => + static String m33(count, formattedSize) => "${Intl.plural(count, one: 'Pode ser excluído do dispositivo para liberar ${formattedSize}', other: 'Eles podem ser excluídos do dispositivo para liberar ${formattedSize}')}"; - static String m31(currentlyProcessing, totalCount) => + static String m34(currentlyProcessing, totalCount) => "Processando ${currentlyProcessing} / ${totalCount}"; - static String m32(count) => + static String m35(count) => "${Intl.plural(count, one: '${count} item', other: '${count} items')}"; - static String m33(expiryTime) => "O link irá expirar em ${expiryTime}"; + static String m36(expiryTime) => "O link irá expirar em ${expiryTime}"; - static String m34(count, formattedCount) => + static String m0(count, formattedCount) => "${Intl.plural(count, zero: 'sem memórias', one: '${formattedCount} memória', other: '${formattedCount} memórias')}"; - static String m35(count) => + static String m37(count) => "${Intl.plural(count, one: 'Mover item', other: 'Mover itens')}"; - static String m36(albumName) => "Movido com sucesso para ${albumName}"; + static String m38(albumName) => "Movido com sucesso para ${albumName}"; - static String m37(name) => "Não é ${name}?"; + static String m39(name) => "Não é ${name}?"; - static String m38(familyAdminEmail) => + static String m40(familyAdminEmail) => "Entre em contato com ${familyAdminEmail} para alterar o seu código."; - static String m39(passwordStrengthValue) => + static String m41(passwordStrengthValue) => "Segurança da senha: ${passwordStrengthValue}"; - static String m40(providerName) => + static String m42(providerName) => "Por favor, fale com o suporte ${providerName} se você foi cobrado"; - static String m41(endDate) => + static String m43(endDate) => "Teste gratuito válido até ${endDate}.\nVocê pode escolher um plano pago depois."; - static String m42(toEmail) => + static String m44(toEmail) => "Por favor, envie-nos um e-mail para ${toEmail}"; - static String m43(toEmail) => "Por favor, envie os logs para \n${toEmail}"; + static String m45(toEmail) => "Por favor, envie os logs para \n${toEmail}"; - static String m44(storeName) => "Avalie-nos em ${storeName}"; + static String m46(storeName) => "Avalie-nos em ${storeName}"; - static String m45(storageInGB) => "3. Ambos ganham ${storageInGB} GB* grátis"; + static String m47(storageInGB) => "3. Ambos ganham ${storageInGB} GB* grátis"; - static String m46(userEmail) => + static String m48(userEmail) => "${userEmail} será removido deste álbum compartilhado\n\nQuaisquer fotos adicionadas por eles também serão removidas do álbum"; - static String m47(endDate) => "Renovação de assinatura em ${endDate}"; + static String m49(endDate) => "Renovação de assinatura em ${endDate}"; - static String m48(count) => + static String m50(count) => "${Intl.plural(count, one: '${count} resultado encontrado', other: '${count} resultado encontrado')}"; - static String m49(count) => "${count} Selecionados"; + static String m1(count) => "${count} Selecionados"; - static String m50(count, yourCount) => + static String m51(count, yourCount) => "${count} Selecionado (${yourCount} seus)"; - static String m51(verificationID) => + static String m52(verificationID) => "Aqui está meu ID de verificação para o Ente.io: ${verificationID}"; - static String m52(verificationID) => + static String m2(verificationID) => "Ei, você pode confirmar que este é seu ID de verificação do Ente.io? ${verificationID}"; static String m53(referralCode, referralStorageInGB) => @@ -236,17 +236,17 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Adicionar um novo e-mail"), "addCollaborator": MessageLookupByLibrary.simpleMessage("Adicionar colaborador"), - "addCollaborators": m0, + "addCollaborators": m3, "addFromDevice": MessageLookupByLibrary.simpleMessage( "Adicionar a partir do dispositivo"), - "addItem": m2, + "addItem": m4, "addLocation": MessageLookupByLibrary.simpleMessage("Adicionar local"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Adicionar"), "addMore": MessageLookupByLibrary.simpleMessage("Adicione mais"), "addNew": MessageLookupByLibrary.simpleMessage("Adicionar novo"), "addOnPageSubtitle": MessageLookupByLibrary.simpleMessage("Detalhes dos complementos"), - "addOnValidTill": m3, + "addOnValidTill": m5, "addOns": MessageLookupByLibrary.simpleMessage("Complementos"), "addPhotos": MessageLookupByLibrary.simpleMessage("Adicionar fotos"), "addSelected": @@ -258,12 +258,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Adicionar a álbum oculto"), "addViewer": MessageLookupByLibrary.simpleMessage("Adicionar visualizador"), - "addViewers": m1, + "addViewers": m6, "addYourPhotosNow": MessageLookupByLibrary.simpleMessage("Adicione suas fotos agora"), "addedAs": MessageLookupByLibrary.simpleMessage("Adicionado como"), - "addedBy": m4, - "addedSuccessfullyTo": m5, + "addedBy": m7, + "addedSuccessfullyTo": m8, "addingToFavorites": MessageLookupByLibrary.simpleMessage( "Adicionando aos favoritos..."), "advanced": MessageLookupByLibrary.simpleMessage("Avançado"), @@ -274,7 +274,7 @@ class MessageLookup extends MessageLookupByLibrary { "after1Week": MessageLookupByLibrary.simpleMessage("Após 1 semana"), "after1Year": MessageLookupByLibrary.simpleMessage("Após 1 ano"), "albumOwner": MessageLookupByLibrary.simpleMessage("Proprietário"), - "albumParticipantsCount": m6, + "albumParticipantsCount": m9, "albumTitle": MessageLookupByLibrary.simpleMessage("Título do álbum"), "albumUpdated": MessageLookupByLibrary.simpleMessage("Álbum atualizado"), @@ -314,7 +314,7 @@ class MessageLookup extends MessageLookupByLibrary { "appLock": MessageLookupByLibrary.simpleMessage("Bloqueio de app"), "appLockDescriptions": MessageLookupByLibrary.simpleMessage( "Escolha entre a tela de bloqueio padrão do seu dispositivo e uma tela de bloqueio personalizada com PIN ou senha."), - "appVersion": m7, + "appVersion": m10, "appleId": MessageLookupByLibrary.simpleMessage("ID da Apple"), "apply": MessageLookupByLibrary.simpleMessage("Aplicar"), "applyCodeTitle": @@ -391,7 +391,7 @@ class MessageLookup extends MessageLookupByLibrary { "autoPairDesc": MessageLookupByLibrary.simpleMessage( "O pareamento automático funciona apenas com dispositivos que suportam o Chromecast."), "available": MessageLookupByLibrary.simpleMessage("Disponível"), - "availableStorageSpace": m8, + "availableStorageSpace": m11, "backedUpFolders": MessageLookupByLibrary.simpleMessage("Pastas com backup"), "backup": MessageLookupByLibrary.simpleMessage("Backup"), @@ -417,10 +417,10 @@ class MessageLookup extends MessageLookupByLibrary { "canOnlyRemoveFilesOwnedByYou": MessageLookupByLibrary.simpleMessage( "Só é possível remover arquivos de sua propriedade"), "cancel": MessageLookupByLibrary.simpleMessage("Cancelar"), - "cancelOtherSubscription": m9, + "cancelOtherSubscription": m12, "cancelSubscription": MessageLookupByLibrary.simpleMessage("Cancelar assinatura"), - "cannotAddMorePhotosAfterBecomingViewer": m10, + "cannotAddMorePhotosAfterBecomingViewer": m13, "cannotDeleteSharedFiles": MessageLookupByLibrary.simpleMessage( "Não é possível excluir arquivos compartilhados"), "castIPMismatchBody": MessageLookupByLibrary.simpleMessage( @@ -466,7 +466,7 @@ class MessageLookup extends MessageLookupByLibrary { "Reivindicar armazenamento gratuito"), "claimMore": MessageLookupByLibrary.simpleMessage("Reivindique mais!"), "claimed": MessageLookupByLibrary.simpleMessage("Reivindicado"), - "claimedStorageSoFar": m11, + "claimedStorageSoFar": m14, "cleanUncategorized": MessageLookupByLibrary.simpleMessage("Limpar Sem Categoria"), "cleanUncategorizedDescription": MessageLookupByLibrary.simpleMessage( @@ -495,7 +495,7 @@ class MessageLookup extends MessageLookupByLibrary { "Crie um link para permitir que as pessoas adicionem e vejam fotos no seu álbum compartilhado sem a necessidade do aplicativo ou uma conta Ente. Ótimo para colecionar fotos de eventos."), "collaborativeLink": MessageLookupByLibrary.simpleMessage("Link Colaborativo"), - "collaborativeLinkCreatedFor": m12, + "collaborativeLinkCreatedFor": m15, "collaborator": MessageLookupByLibrary.simpleMessage("Colaborador"), "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": MessageLookupByLibrary.simpleMessage( @@ -524,10 +524,10 @@ class MessageLookup extends MessageLookupByLibrary { "Confirme sua chave de recuperação"), "connectToDevice": MessageLookupByLibrary.simpleMessage("Conectar ao dispositivo"), - "contactFamilyAdmin": m13, + "contactFamilyAdmin": m16, "contactSupport": MessageLookupByLibrary.simpleMessage("Contate o suporte"), - "contactToManageSubscription": m14, + "contactToManageSubscription": m17, "contacts": MessageLookupByLibrary.simpleMessage("Contatos"), "contents": MessageLookupByLibrary.simpleMessage("Conteúdos"), "continueLabel": MessageLookupByLibrary.simpleMessage("Continuar"), @@ -571,7 +571,7 @@ class MessageLookup extends MessageLookupByLibrary { "currentUsageIs": MessageLookupByLibrary.simpleMessage("O uso atual é "), "custom": MessageLookupByLibrary.simpleMessage("Personalizado"), - "customEndpoint": m15, + "customEndpoint": m18, "darkTheme": MessageLookupByLibrary.simpleMessage("Escuro"), "dayToday": MessageLookupByLibrary.simpleMessage("Hoje"), "dayYesterday": MessageLookupByLibrary.simpleMessage("Ontem"), @@ -607,10 +607,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Excluir do dispositivo"), "deleteFromEnte": MessageLookupByLibrary.simpleMessage("Excluir do Ente"), - "deleteItemCount": m16, + "deleteItemCount": m19, "deleteLocation": MessageLookupByLibrary.simpleMessage("Excluir Local"), "deletePhotos": MessageLookupByLibrary.simpleMessage("Excluir fotos"), - "deleteProgress": m17, + "deleteProgress": m20, "deleteReason1": MessageLookupByLibrary.simpleMessage( "Está faltando um recurso-chave que eu preciso"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -651,7 +651,7 @@ class MessageLookup extends MessageLookupByLibrary { "Os espectadores ainda podem tirar screenshots ou salvar uma cópia de suas fotos usando ferramentas externas"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Observe"), - "disableLinkMessage": m18, + "disableLinkMessage": m21, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Desativar autenticação de dois fatores"), "disablingTwofactorAuthentication": @@ -675,9 +675,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Falha no download"), "downloading": MessageLookupByLibrary.simpleMessage("Fazendo download..."), - "dropSupportEmail": m19, - "duplicateFileCountWithStorageSaved": m20, - "duplicateItemsGroup": m21, + "dropSupportEmail": m22, + "duplicateFileCountWithStorageSaved": m23, + "duplicateItemsGroup": m24, "edit": MessageLookupByLibrary.simpleMessage("Editar"), "editLocation": MessageLookupByLibrary.simpleMessage("Editar local"), "editLocationTagTitle": @@ -688,8 +688,8 @@ class MessageLookup extends MessageLookupByLibrary { "Edições para local só serão vistas dentro do Ente"), "eligible": MessageLookupByLibrary.simpleMessage("elegível"), "email": MessageLookupByLibrary.simpleMessage("E-mail"), - "emailChangedTo": m22, - "emailNoEnteAccount": m23, + "emailChangedTo": m25, + "emailNoEnteAccount": m26, "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("Verificação por e-mail"), "emailYourLogs": @@ -799,8 +799,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Tipos de arquivo"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Tipos de arquivo e nomes"), - "filesBackedUpFromDevice": m24, - "filesBackedUpInAlbum": m25, + "filesBackedUpFromDevice": m27, + "filesBackedUpInAlbum": m28, "filesDeleted": MessageLookupByLibrary.simpleMessage("Arquivos excluídos"), "filesSavedToGallery": @@ -816,25 +816,25 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Rostos encontrados"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage( "Armazenamento gratuito reivindicado"), - "freeStorageOnReferralSuccess": m26, + "freeStorageOnReferralSuccess": m29, "freeStorageUsable": MessageLookupByLibrary.simpleMessage( "Armazenamento livre utilizável"), "freeTrial": MessageLookupByLibrary.simpleMessage("Teste gratuito"), - "freeTrialValidTill": m27, - "freeUpAccessPostDelete": m28, - "freeUpAmount": m29, + "freeTrialValidTill": m30, + "freeUpAccessPostDelete": m31, + "freeUpAmount": m32, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage( "Liberar espaço no dispositivo"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Economize espaço no seu dispositivo limpando arquivos que já foram salvos em backup."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Liberar espaço"), - "freeUpSpaceSaving": m30, + "freeUpSpaceSaving": m33, "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Até 1000 memórias mostradas na galeria"), "general": MessageLookupByLibrary.simpleMessage("Geral"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Gerando chaves de criptografia..."), - "genericProgress": m31, + "genericProgress": m34, "goToSettings": MessageLookupByLibrary.simpleMessage("Ir para Configurações"), "googlePlayId": @@ -912,7 +912,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Parece que algo deu errado. Por favor, tente novamente mais tarde. Se o erro persistir, entre em contato com nossa equipe de suporte."), - "itemCount": m32, + "itemCount": m35, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Os itens mostram o número de dias restantes antes da exclusão permanente"), @@ -941,7 +941,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Limite do dispositivo"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Habilitado"), "linkExpired": MessageLookupByLibrary.simpleMessage("Expirado"), - "linkExpiresOn": m33, + "linkExpiresOn": m36, "linkExpiry": MessageLookupByLibrary.simpleMessage("Expiração do link"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("O link expirou"), @@ -1021,7 +1021,7 @@ class MessageLookup extends MessageLookupByLibrary { "maps": MessageLookupByLibrary.simpleMessage("Mapas"), "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), - "memoryCount": m34, + "memoryCount": m0, "merchandise": MessageLookupByLibrary.simpleMessage("Produtos"), "mlConsent": MessageLookupByLibrary.simpleMessage( "Habilitar aprendizado de máquina"), @@ -1044,11 +1044,11 @@ class MessageLookup extends MessageLookupByLibrary { "moments": MessageLookupByLibrary.simpleMessage("Momentos"), "monthly": MessageLookupByLibrary.simpleMessage("Mensal"), "moreDetails": MessageLookupByLibrary.simpleMessage("Mais detalhes"), - "moveItem": m35, + "moveItem": m37, "moveToAlbum": MessageLookupByLibrary.simpleMessage("Mover para álbum"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Mover para álbum oculto"), - "movedSuccessfullyTo": m36, + "movedSuccessfullyTo": m38, "movedToTrash": MessageLookupByLibrary.simpleMessage("Movido para a lixeira"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1096,7 +1096,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Nenhum resultado encontrado"), "noSystemLockFound": MessageLookupByLibrary.simpleMessage( "Nenhum bloqueio de sistema encontrado"), - "notPersonLabel": m37, + "notPersonLabel": m39, "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( "Nada compartilhado com você ainda"), "nothingToSeeHere": @@ -1106,7 +1106,7 @@ class MessageLookup extends MessageLookupByLibrary { "onDevice": MessageLookupByLibrary.simpleMessage("No dispositivo"), "onEnte": MessageLookupByLibrary.simpleMessage( "Em ente"), - "onlyFamilyAdminCanChangeCode": m38, + "onlyFamilyAdminCanChangeCode": m40, "oops": MessageLookupByLibrary.simpleMessage("Opa"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( "Ops, não foi possível salvar edições"), @@ -1136,7 +1136,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Senha alterada com sucesso"), "passwordLock": MessageLookupByLibrary.simpleMessage("Bloqueio por senha"), - "passwordStrength": m39, + "passwordStrength": m41, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "Força da senha é calculada considerando o comprimento da senha, caracteres usados, e se a senha aparece ou não nas 10.000 senhas mais usadas"), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -1147,7 +1147,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Falha no pagamento"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Infelizmente o seu pagamento falhou. Entre em contato com o suporte e nós ajudaremos você!"), - "paymentFailedTalkToProvider": m40, + "paymentFailedTalkToProvider": m42, "pendingItems": MessageLookupByLibrary.simpleMessage("Itens pendentes"), "pendingSync": MessageLookupByLibrary.simpleMessage("Sincronização pendente"), @@ -1175,7 +1175,7 @@ class MessageLookup extends MessageLookupByLibrary { "pinLock": MessageLookupByLibrary.simpleMessage("Bloqueio PIN"), "playOnTv": MessageLookupByLibrary.simpleMessage("Reproduzir álbum na TV"), - "playStoreFreeTrialValidTill": m41, + "playStoreFreeTrialValidTill": m43, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("Assinatura da PlayStore"), "pleaseCheckYourInternetConnectionAndTryAgain": @@ -1187,14 +1187,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Por favor, contate o suporte se o problema persistir"), - "pleaseEmailUsAt": m42, + "pleaseEmailUsAt": m44, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage( "Por favor, conceda as permissões"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage( "Por favor, inicie sessão novamente"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( "Selecione links rápidos para remover"), - "pleaseSendTheLogsTo": m43, + "pleaseSendTheLogsTo": m45, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Por favor, tente novamente"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1231,7 +1231,7 @@ class MessageLookup extends MessageLookupByLibrary { "rateTheApp": MessageLookupByLibrary.simpleMessage("Avalie o aplicativo"), "rateUs": MessageLookupByLibrary.simpleMessage("Avalie-nos"), - "rateUsOnStore": m44, + "rateUsOnStore": m46, "recover": MessageLookupByLibrary.simpleMessage("Recuperar"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Recuperar conta"), @@ -1266,7 +1266,7 @@ class MessageLookup extends MessageLookupByLibrary { "1. Dê este código aos seus amigos"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Eles se inscrevem em um plano pago"), - "referralStep3": m45, + "referralStep3": m47, "referrals": MessageLookupByLibrary.simpleMessage("Indicações"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Indicações estão atualmente pausadas"), @@ -1292,7 +1292,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Remover link"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Remover participante"), - "removeParticipantBody": m46, + "removeParticipantBody": m48, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Remover etiqueta da pessoa"), "removePublicLink": @@ -1310,7 +1310,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameFile": MessageLookupByLibrary.simpleMessage("Renomear arquivo"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Renovar assinatura"), - "renewsOn": m47, + "renewsOn": m49, "reportABug": MessageLookupByLibrary.simpleMessage("Reportar um problema"), "reportBug": @@ -1384,7 +1384,7 @@ class MessageLookup extends MessageLookupByLibrary { "Fotos de grupo que estão sendo tiradas em algum raio da foto"), "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage( "Convide pessoas e você verá todas as fotos compartilhadas por elas aqui"), - "searchResultCount": m48, + "searchResultCount": m50, "security": MessageLookupByLibrary.simpleMessage("Segurança"), "selectALocation": MessageLookupByLibrary.simpleMessage("Selecionar um local"), @@ -1412,8 +1412,8 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage( "Os itens selecionados serão excluídos de todos os álbuns e movidos para a lixeira."), - "selectedPhotos": m49, - "selectedPhotosWithYours": m50, + "selectedPhotos": m1, + "selectedPhotosWithYours": m51, "send": MessageLookupByLibrary.simpleMessage("Enviar"), "sendEmail": MessageLookupByLibrary.simpleMessage("Enviar e-mail"), "sendInvite": MessageLookupByLibrary.simpleMessage("Enviar convite"), @@ -1442,10 +1442,10 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Compartilhar um álbum agora"), "shareLink": MessageLookupByLibrary.simpleMessage("Compartilhar link"), - "shareMyVerificationID": m51, + "shareMyVerificationID": m52, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Compartilhar apenas com as pessoas que você quiser"), - "shareTextConfirmOthersVerificationID": m52, + "shareTextConfirmOthersVerificationID": m2, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Baixe o Ente para que possamos compartilhar facilmente fotos e vídeos de qualidade original\n\nhttps://ente.io"), "shareTextReferralCode": m53, @@ -1548,7 +1548,7 @@ class MessageLookup extends MessageLookupByLibrary { "successfullyUnarchived": MessageLookupByLibrary.simpleMessage("Desarquivado com sucesso"), "successfullyUnhid": - MessageLookupByLibrary.simpleMessage("Desocultado com sucesso"), + MessageLookupByLibrary.simpleMessage("Reexibido com sucesso"), "suggestFeatures": MessageLookupByLibrary.simpleMessage("Sugerir recurso"), "support": MessageLookupByLibrary.simpleMessage("Suporte"), @@ -1709,7 +1709,7 @@ class MessageLookup extends MessageLookupByLibrary { "viewLargeFiles": MessageLookupByLibrary.simpleMessage("Arquivos grandes"), "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( - "Ver arquivos que estão consumindo mais espaço de armazenamento"), + "Ver arquivos que estão consumindo mais espaço de armazenamento."), "viewLogs": MessageLookupByLibrary.simpleMessage("Ver logs"), "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("Ver chave de recuperação"), diff --git a/mobile/lib/generated/intl/messages_ru.dart b/mobile/lib/generated/intl/messages_ru.dart index b62f043922..e40aaf8ce5 100644 --- a/mobile/lib/generated/intl/messages_ru.dart +++ b/mobile/lib/generated/intl/messages_ru.dart @@ -20,147 +20,149 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'ru'; - static String m0(count) => + static String m3(count) => "${Intl.plural(count, one: 'Добавьте соавтора', few: 'Добавьте соавторов', many: 'Добавьте соавторов', other: 'Добавьте соавторов')}"; - static String m2(count) => + static String m4(count) => "${Intl.plural(count, one: 'Добавить элемент', other: 'Добавить элементы')}"; - static String m3(storageAmount, endDate) => + static String m5(storageAmount, endDate) => "Ваше дополнение ${storageAmount} действительно по ${endDate}"; - static String m1(count) => + static String m6(count) => "${Intl.plural(count, one: 'Добавьте зрителя', few: 'Добавьте зрителей', many: 'Добавьте зрителей', other: 'Добавьте зрителей')}"; - static String m4(emailOrName) => "Добавлено ${emailOrName}"; + static String m7(emailOrName) => "Добавлено ${emailOrName}"; - static String m5(albumName) => "Успешно добавлено в ${albumName}"; + static String m8(albumName) => "Успешно добавлено в ${albumName}"; - static String m6(count) => + static String m9(count) => "${Intl.plural(count, zero: 'Нет Участников', one: '1 Участник', other: '${count} Участника')}"; - static String m7(versionValue) => "Версия: ${versionValue}"; + static String m10(versionValue) => "Версия: ${versionValue}"; - static String m8(freeAmount, storageUnit) => + static String m11(freeAmount, storageUnit) => "${freeAmount} ${storageUnit} свободно"; - static String m9(paymentProvider) => + static String m12(paymentProvider) => "Пожалуйста, сначала отмените вашу существующую подписку от ${paymentProvider}"; - static String m10(user) => + static String m13(user) => "${user} больше не сможет добавлять фотографии в этот альбом\n\nОни все еще смогут удалять существующие фотографии, добавленные ими"; - static String m11(isFamilyMember, storageAmountInGb) => + static String m14(isFamilyMember, storageAmountInGb) => "${Intl.select(isFamilyMember, { 'true': 'Ваша семья получила ${storageAmountInGb} ГБ', 'false': 'Вы уже получили ${storageAmountInGb} ГБ', 'other': 'Вы уже получили ${storageAmountInGb} ГБ!', })}"; - static String m12(albumName) => "Совместная ссылка создана для ${albumName}"; + static String m15(albumName) => "Совместная ссылка создана для ${albumName}"; - static String m13(familyAdminEmail) => + static String m16(familyAdminEmail) => "Пожалуйста, свяжитесь с ${familyAdminEmail} для управления подпиской"; - static String m14(provider) => + static String m17(provider) => "Пожалуйста, свяжитесь с нами по адресу support@ente.io для управления подпиской ${provider}."; - static String m15(endpoint) => "Подключено к ${endpoint}"; + static String m18(endpoint) => "Подключено к ${endpoint}"; - static String m16(count) => + static String m19(count) => "${Intl.plural(count, one: 'Удалена ${count} штука', other: 'Удалено ${count} штук')}"; - static String m17(currentlyDeleting, totalCount) => + static String m20(currentlyDeleting, totalCount) => "Удаление ${currentlyDeleting} / ${totalCount}"; - static String m18(albumName) => + static String m21(albumName) => "Это удалит публичную ссылку для доступа к \"${albumName}\"."; - static String m19(supportEmail) => + static String m22(supportEmail) => "Пожалуйста, отправьте электронное письмо на адрес ${supportEmail} с вашего зарегистрированного адреса электронной почты"; - static String m20(count, storageSaved) => + static String m23(count, storageSaved) => "Вы привели себя в порядок ${Intl.plural(count, one: '${count} duplicate file', other: '${count} duplicate files')}, экономия (${storageSaved}!)\n"; - static String m21(count, formattedSize) => + static String m24(count, formattedSize) => "${count} файлов, ${formattedSize}"; - static String m22(newEmail) => + static String m25(newEmail) => "Адрес электронной почты изменен на ${newEmail}"; - static String m23(email) => + static String m26(email) => "У ${email} нет учетной записи Ente.\n\nОтправьте им приглашение для обмена фотографиями."; - static String m24(count, formattedNumber) => + static String m27(count, formattedNumber) => "${Intl.plural(count, one: 'для 1 файла было создан бекап', other: 'для ${formattedNumber} файлов были созданы бекапы')}"; - static String m25(count, formattedNumber) => + static String m28(count, formattedNumber) => "${Intl.plural(count, one: 'для 1 файла было создан бекап', other: 'для ${formattedNumber} файлов были созданы бекапы')}"; - static String m26(storageAmountInGB) => + static String m29(storageAmountInGB) => "${storageAmountInGB} Гигабайт каждый раз когда кто-то подписывается на платный план и применяет ваш код"; - static String m27(endDate) => + static String m30(endDate) => "Бесплатная пробная версия действительна до ${endDate}"; - static String m28(count) => + static String m31(count) => "Вы все еще можете получить доступ к ${Intl.plural(count, one: 'ниму', other: 'ним')} на Ente, пока у вас есть активная подписка"; - static String m29(sizeInMBorGB) => "Освободите ${sizeInMBorGB}"; + static String m32(sizeInMBorGB) => "Освободите ${sizeInMBorGB}"; - static String m30(count, formattedSize) => + static String m33(count, formattedSize) => "${Intl.plural(count, one: 'Это можно удалить с устройства, чтобы освободить ${formattedSize}', other: 'Их можно удалить с устройства, чтобы освободить ${formattedSize}')}"; - static String m31(currentlyProcessing, totalCount) => + static String m34(currentlyProcessing, totalCount) => "Обработка ${currentlyProcessing} / ${totalCount}"; - static String m32(count) => + static String m35(count) => "${Intl.plural(count, one: '${count} штука', other: '${count} штук')}"; - static String m33(expiryTime) => "Ссылка истечёт через ${expiryTime}"; + static String m36(expiryTime) => "Ссылка истечёт через ${expiryTime}"; - static String m34(count, formattedCount) => + static String m0(count, formattedCount) => "${Intl.plural(count, zero: 'нет воспоминаний', one: '${formattedCount} воспоминание', other: '${formattedCount} воспоминаний')}"; - static String m35(count) => + static String m37(count) => "${Intl.plural(count, one: 'Переместить элемент', other: 'Переместить элементы')}"; - static String m36(albumName) => "Успешно перемещено в ${albumName}"; + static String m38(albumName) => "Успешно перемещено в ${albumName}"; - static String m39(passwordStrengthValue) => + static String m39(name) => "Не ${name}?"; + + static String m41(passwordStrengthValue) => "Мощность пароля: ${passwordStrengthValue}"; - static String m40(providerName) => + static String m42(providerName) => "Если с вас сняли оплату, обратитесь в службу поддержки ${providerName}"; - static String m41(endDate) => + static String m43(endDate) => "Бесплатный пробный период до ${endDate}.\nПосле, вы сможете выбрать платный план."; - static String m42(toEmail) => "Пожалуйста, напишите нам на ${toEmail}"; + static String m44(toEmail) => "Пожалуйста, напишите нам на ${toEmail}"; - static String m43(toEmail) => "Пожалуйста, отправьте логи на \n${toEmail}"; + static String m45(toEmail) => "Пожалуйста, отправьте логи на \n${toEmail}"; - static String m44(storeName) => "Оцените нас в ${storeName}"; + static String m46(storeName) => "Оцените нас в ${storeName}"; - static String m45(storageInGB) => + static String m47(storageInGB) => "3. Вы оба получаете ${storageInGB} Гигабайт* бесплатно"; - static String m46(userEmail) => + static String m48(userEmail) => "${userEmail} будет удален из этого общего альбома\n\nВсе добавленные им фотографии также будут удалены из альбома"; - static String m47(endDate) => "Обновление подписки на ${endDate}"; + static String m49(endDate) => "Обновление подписки на ${endDate}"; - static String m48(count) => + static String m50(count) => "${Intl.plural(count, one: '${count} результат найден', other: '${count} результатов найдено')}"; - static String m49(count) => "${count} выбрано"; + static String m1(count) => "${count} выбрано"; - static String m50(count, yourCount) => "${count} выбрано (${yourCount} ваши)"; - - static String m51(verificationID) => - "Вот мой проверочный ID: ${verificationID} для ente.io."; + static String m51(count, yourCount) => "${count} выбрано (${yourCount} ваши)"; static String m52(verificationID) => + "Вот мой проверочный ID: ${verificationID} для ente.io."; + + static String m2(verificationID) => "Эй, вы можете подтвердить, что это ваш идентификатор подтверждения ente.io: ${verificationID}"; static String m53(referralCode, referralStorageInGB) => @@ -229,17 +231,17 @@ class MessageLookup extends MessageLookupByLibrary { "Добавить новый адрес эл. почты"), "addCollaborator": MessageLookupByLibrary.simpleMessage("Добавить соавтора"), - "addCollaborators": m0, + "addCollaborators": m3, "addFromDevice": MessageLookupByLibrary.simpleMessage("Добавить с устройства"), - "addItem": m2, + "addItem": m4, "addLocation": MessageLookupByLibrary.simpleMessage("Добавить место"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Добавить"), "addMore": MessageLookupByLibrary.simpleMessage("Добавить еще"), "addNew": MessageLookupByLibrary.simpleMessage("Добавить новое"), "addOnPageSubtitle": MessageLookupByLibrary.simpleMessage("Подробнее о расширениях"), - "addOnValidTill": m3, + "addOnValidTill": m5, "addOns": MessageLookupByLibrary.simpleMessage("Расширения"), "addPhotos": MessageLookupByLibrary.simpleMessage("Добавить фотографии"), @@ -251,12 +253,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Добавить в скрытый альбом"), "addViewer": MessageLookupByLibrary.simpleMessage("Добавить наблюдателя"), - "addViewers": m1, + "addViewers": m6, "addYourPhotosNow": MessageLookupByLibrary.simpleMessage("Добавьте ваши фотографии"), "addedAs": MessageLookupByLibrary.simpleMessage("Добавлено как"), - "addedBy": m4, - "addedSuccessfullyTo": m5, + "addedBy": m7, + "addedSuccessfullyTo": m8, "addingToFavorites": MessageLookupByLibrary.simpleMessage("Добавление в избранное..."), "advanced": MessageLookupByLibrary.simpleMessage("Дополнительно"), @@ -268,7 +270,7 @@ class MessageLookup extends MessageLookupByLibrary { "after1Week": MessageLookupByLibrary.simpleMessage("Через неделю"), "after1Year": MessageLookupByLibrary.simpleMessage("Через 1 год"), "albumOwner": MessageLookupByLibrary.simpleMessage("Владелец"), - "albumParticipantsCount": m6, + "albumParticipantsCount": m9, "albumTitle": MessageLookupByLibrary.simpleMessage("Название альбома"), "albumUpdated": MessageLookupByLibrary.simpleMessage("Альбом обновлен"), "albums": MessageLookupByLibrary.simpleMessage("Альбомы"), @@ -304,10 +306,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Android, iOS, Web, ПК"), "androidSignInTitle": MessageLookupByLibrary.simpleMessage("Требуется аутентификация"), - "appLock": MessageLookupByLibrary.simpleMessage("App lock"), - "appLockDescriptions": MessageLookupByLibrary.simpleMessage( - "Choose between your device\'s default lock screen and a custom lock screen with a PIN or password."), - "appVersion": m7, + "appLock": + MessageLookupByLibrary.simpleMessage("Блокировка приложения"), + "appVersion": m10, "appleId": MessageLookupByLibrary.simpleMessage("Apple ID"), "apply": MessageLookupByLibrary.simpleMessage("Применить"), "applyCodeTitle": MessageLookupByLibrary.simpleMessage("Применить код"), @@ -352,8 +353,6 @@ class MessageLookup extends MessageLookupByLibrary { "Пожалуйста, авторизуйтесь для настройки двухфакторной аутентификации"), "authToInitiateAccountDeletion": MessageLookupByLibrary.simpleMessage( "Пожалуйста, авторизуйтесь, чтобы начать удаление аккаунта"), - "authToViewPasskey": MessageLookupByLibrary.simpleMessage( - "Please authenticate to view your passkey"), "authToViewYourActiveSessions": MessageLookupByLibrary.simpleMessage( "Пожалуйста, авторизуйтесь для просмотра активных сессий"), "authToViewYourHiddenFiles": MessageLookupByLibrary.simpleMessage( @@ -373,9 +372,9 @@ class MessageLookup extends MessageLookupByLibrary { "Здесь вы увидите доступные устройства."), "autoCastiOSPermission": MessageLookupByLibrary.simpleMessage( "Убедитесь, что для приложения Ente Photos включены права доступа к локальной сети в настройках."), - "autoLock": MessageLookupByLibrary.simpleMessage("Auto lock"), + "autoLock": MessageLookupByLibrary.simpleMessage("Автоблокировка"), "autoLockFeatureDescription": MessageLookupByLibrary.simpleMessage( - "Time after which the app locks after being put in the background"), + "Время в фоне, после которого приложение блокируется"), "autoLogoutMessage": MessageLookupByLibrary.simpleMessage( "В связи с технической ошибкой вы вышли из системы. Приносим свои извинения."), "autoPair": @@ -383,7 +382,7 @@ class MessageLookup extends MessageLookupByLibrary { "autoPairDesc": MessageLookupByLibrary.simpleMessage( "Автоматическое подключение работает только с устройствами, поддерживающими Chromecast."), "available": MessageLookupByLibrary.simpleMessage("Доступно"), - "availableStorageSpace": m8, + "availableStorageSpace": m11, "backedUpFolders": MessageLookupByLibrary.simpleMessage("Резервное копирование папок"), "backup": MessageLookupByLibrary.simpleMessage("Резервное копирование"), @@ -410,10 +409,10 @@ class MessageLookup extends MessageLookupByLibrary { "canOnlyRemoveFilesOwnedByYou": MessageLookupByLibrary.simpleMessage( "Можно удалять только файлы, принадлежащие вам"), "cancel": MessageLookupByLibrary.simpleMessage("Отменить"), - "cancelOtherSubscription": m9, + "cancelOtherSubscription": m12, "cancelSubscription": MessageLookupByLibrary.simpleMessage("Отменить подписку"), - "cannotAddMorePhotosAfterBecomingViewer": m10, + "cannotAddMorePhotosAfterBecomingViewer": m13, "cannotDeleteSharedFiles": MessageLookupByLibrary.simpleMessage( "Невозможно удалить общие файлы"), "castIPMismatchBody": MessageLookupByLibrary.simpleMessage( @@ -424,6 +423,7 @@ class MessageLookup extends MessageLookupByLibrary { "Посетите cast.ente.io на устройстве, которое вы хотите подключить.\n\nВведите код ниже, чтобы воспроизвести альбом на телевизоре."), "centerPoint": MessageLookupByLibrary.simpleMessage("Центральная точка"), + "change": MessageLookupByLibrary.simpleMessage("Изменить"), "changeEmail": MessageLookupByLibrary.simpleMessage( "Изменить адрес электронной почты"), "changeLocationOfSelectedItems": MessageLookupByLibrary.simpleMessage( @@ -434,31 +434,25 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Изменить пароль"), "changePermissions": MessageLookupByLibrary.simpleMessage("Изменить разрешения?"), + "changeYourReferralCode": MessageLookupByLibrary.simpleMessage( + "Изменить ваш реферальный код"), "checkForUpdates": MessageLookupByLibrary.simpleMessage("Проверить обновления"), "checkInboxAndSpamFolder": MessageLookupByLibrary.simpleMessage( "Пожалуйста, проверьте свой почтовый ящик (и спам) для завершения верификации"), "checkStatus": MessageLookupByLibrary.simpleMessage("Проверить статус"), "checking": MessageLookupByLibrary.simpleMessage("Проверка..."), - "cl_guest_view_call_to_action": MessageLookupByLibrary.simpleMessage( - "Выберите фото и попробуйте \"Режим гостя\"."), - "cl_guest_view_description": MessageLookupByLibrary.simpleMessage( - "Показываете фото другу? Не переживайте, что он листнет слишком далеко. Режим гостя заблокирует те фото, которые вы выбрали."), "cl_guest_view_title": - MessageLookupByLibrary.simpleMessage("Режим гостя"), - "cl_panorama_viewer_description": MessageLookupByLibrary.simpleMessage( - "Мы добавили поддержку просмотра панорамных фотографий с углом обзора 360 градусов. Погружение обеспечивается навигацией на основе движения!"), + MessageLookupByLibrary.simpleMessage("Гостевой вид"), "cl_panorama_viewer_title": MessageLookupByLibrary.simpleMessage("Просмотр Панорамы"), - "cl_video_player_description": MessageLookupByLibrary.simpleMessage( - "Представляем новый видеоплеер с улучшенными элементами управления воспроизведением и поддержкой HDR видео."), "cl_video_player_title": MessageLookupByLibrary.simpleMessage("Видеоплеер"), "claimFreeStorage": MessageLookupByLibrary.simpleMessage( "Получить бесплатное хранилище"), "claimMore": MessageLookupByLibrary.simpleMessage("Получите больше!"), "claimed": MessageLookupByLibrary.simpleMessage("Получено"), - "claimedStorageSoFar": m11, + "claimedStorageSoFar": m14, "cleanUncategorized": MessageLookupByLibrary.simpleMessage("Очистить \"Без Категории\""), "cleanUncategorizedDescription": MessageLookupByLibrary.simpleMessage( @@ -486,7 +480,7 @@ class MessageLookup extends MessageLookupByLibrary { "Создайте ссылку, чтобы позволить людям добавлять и просматривать фотографии в вашем общем альбоме без приложения или учетной записи Ente. Отлично подходит для сбора фотографий событий."), "collaborativeLink": MessageLookupByLibrary.simpleMessage("Совместная ссылка"), - "collaborativeLinkCreatedFor": m12, + "collaborativeLinkCreatedFor": m15, "collaborator": MessageLookupByLibrary.simpleMessage("Соавтор"), "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": MessageLookupByLibrary.simpleMessage( @@ -516,10 +510,10 @@ class MessageLookup extends MessageLookupByLibrary { "Подтвердите ваш ключ восстановления"), "connectToDevice": MessageLookupByLibrary.simpleMessage("Подключиться к устройству"), - "contactFamilyAdmin": m13, + "contactFamilyAdmin": m16, "contactSupport": MessageLookupByLibrary.simpleMessage("Связаться с поддержкой"), - "contactToManageSubscription": m14, + "contactToManageSubscription": m17, "contacts": MessageLookupByLibrary.simpleMessage("Контакты"), "contents": MessageLookupByLibrary.simpleMessage("Содержимое"), "continueLabel": MessageLookupByLibrary.simpleMessage("Далее"), @@ -564,7 +558,7 @@ class MessageLookup extends MessageLookupByLibrary { "currentUsageIs": MessageLookupByLibrary.simpleMessage("Текущее использование "), "custom": MessageLookupByLibrary.simpleMessage("Свой"), - "customEndpoint": m15, + "customEndpoint": m18, "darkTheme": MessageLookupByLibrary.simpleMessage("Темная тема"), "dayToday": MessageLookupByLibrary.simpleMessage("Сегодня"), "dayYesterday": MessageLookupByLibrary.simpleMessage("Вчера"), @@ -600,11 +594,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Удалить с устройства"), "deleteFromEnte": MessageLookupByLibrary.simpleMessage("Удалить из Ente"), - "deleteItemCount": m16, + "deleteItemCount": m19, "deleteLocation": MessageLookupByLibrary.simpleMessage("Удалить местоположение"), "deletePhotos": MessageLookupByLibrary.simpleMessage("Удалить фото"), - "deleteProgress": m17, + "deleteProgress": m20, "deleteReason1": MessageLookupByLibrary.simpleMessage( "У вас отсутствует важная функция, которая мне нужна"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -631,7 +625,8 @@ class MessageLookup extends MessageLookupByLibrary { "deviceCodeHint": MessageLookupByLibrary.simpleMessage("Введите код"), "deviceFilesAutoUploading": MessageLookupByLibrary.simpleMessage( "Файлы, добавленные в этот альбом на устройстве, будут автоматически загружены в Ente."), - "deviceLock": MessageLookupByLibrary.simpleMessage("Device lock"), + "deviceLock": + MessageLookupByLibrary.simpleMessage("Блокировка устройства"), "deviceLockExplanation": MessageLookupByLibrary.simpleMessage( "Отключить блокировку экрана, когда Ente находится на переднем плане и выполняется резервное копирование. Обычно это не нужно, но это может ускорить загрузку и первоначальный импорт больших библиотек."), "deviceNotFound": @@ -643,7 +638,7 @@ class MessageLookup extends MessageLookupByLibrary { "Наблюдатели все еще могут делать скриншоты или копировать ваши фотографии с помощью других инструментов"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Обратите внимание"), - "disableLinkMessage": m18, + "disableLinkMessage": m21, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "Отключить двухфакторную аутентификацию"), "disablingTwofactorAuthentication": @@ -664,9 +659,9 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("Загрузка не удалась"), "downloading": MessageLookupByLibrary.simpleMessage("Скачивание..."), - "dropSupportEmail": m19, - "duplicateFileCountWithStorageSaved": m20, - "duplicateItemsGroup": m21, + "dropSupportEmail": m22, + "duplicateFileCountWithStorageSaved": m23, + "duplicateItemsGroup": m24, "edit": MessageLookupByLibrary.simpleMessage("Редактировать"), "editLocation": MessageLookupByLibrary.simpleMessage("Изменить местоположение"), @@ -679,17 +674,19 @@ class MessageLookup extends MessageLookupByLibrary { "Редактирования в местоположении будут видны только внутри Ente"), "eligible": MessageLookupByLibrary.simpleMessage("подходящий"), "email": MessageLookupByLibrary.simpleMessage("Электронная почта"), - "emailChangedTo": m22, - "emailNoEnteAccount": m23, + "emailChangedTo": m25, + "emailNoEnteAccount": m26, "emailVerificationToggle": MessageLookupByLibrary.simpleMessage( "Подтверждение электронной почты"), "emailYourLogs": MessageLookupByLibrary.simpleMessage( "Отправить логи по электронной почте"), "empty": MessageLookupByLibrary.simpleMessage("Очистить"), "emptyTrash": MessageLookupByLibrary.simpleMessage("Очистить корзину?"), + "enable": MessageLookupByLibrary.simpleMessage("Включить"), "enableMaps": MessageLookupByLibrary.simpleMessage("Включить карты"), "enableMapsDesc": MessageLookupByLibrary.simpleMessage( "Ваши фотографии будут показаны на карте мира.\n\nЭта карта размещена на Open Street Map, и точное местоположение ваших фотографий никогда не разглашается.\n\nВы можете отключить эту функцию в любое время в настройках."), + "enabled": MessageLookupByLibrary.simpleMessage("Включено"), "encryptingBackup": MessageLookupByLibrary.simpleMessage( "Шифрование резервной копии..."), "encryption": MessageLookupByLibrary.simpleMessage("Шифрование"), @@ -723,7 +720,7 @@ class MessageLookup extends MessageLookupByLibrary { "enterPasswordToEncrypt": MessageLookupByLibrary.simpleMessage( "Введите пароль, который мы можем использовать для шифрования ваших данных"), "enterPersonName": MessageLookupByLibrary.simpleMessage("Введите имя"), - "enterPin": MessageLookupByLibrary.simpleMessage("Enter PIN"), + "enterPin": MessageLookupByLibrary.simpleMessage("Введите PIN"), "enterReferralCode": MessageLookupByLibrary.simpleMessage("Введите реферальный код"), "enterThe6digitCodeFromnyourAuthenticatorApp": @@ -784,8 +781,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Типы файлов"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Типы файлов и имена"), - "filesBackedUpFromDevice": m24, - "filesBackedUpInAlbum": m25, + "filesBackedUpFromDevice": m27, + "filesBackedUpInAlbum": m28, "filesDeleted": MessageLookupByLibrary.simpleMessage("Файлы удалены"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage("Файлы сохранены в галерею"), @@ -798,26 +795,26 @@ class MessageLookup extends MessageLookupByLibrary { "foundFaces": MessageLookupByLibrary.simpleMessage("Найденные лица"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage( "Бесплатного хранилища получено"), - "freeStorageOnReferralSuccess": m26, + "freeStorageOnReferralSuccess": m29, "freeStorageUsable": MessageLookupByLibrary.simpleMessage( "Бесплатного хранилища можно использовать"), "freeTrial": MessageLookupByLibrary.simpleMessage("Бесплатный пробный период"), - "freeTrialValidTill": m27, - "freeUpAccessPostDelete": m28, - "freeUpAmount": m29, + "freeTrialValidTill": m30, + "freeUpAccessPostDelete": m31, + "freeUpAmount": m32, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage( "Освободите место на устройстве"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( "Сохраните место на вашем устройстве, очистив уже сохраненные файлы."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Освободить место"), - "freeUpSpaceSaving": m30, + "freeUpSpaceSaving": m33, "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "До 1000 воспоминаний, отображаемых в галерее"), "general": MessageLookupByLibrary.simpleMessage("Общее"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Генерируем ключи шифрования..."), - "genericProgress": m31, + "genericProgress": m34, "goToSettings": MessageLookupByLibrary.simpleMessage("Перейти в настройки"), "googlePlayId": MessageLookupByLibrary.simpleMessage("Google Play ID"), @@ -827,9 +824,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Предоставить разрешение"), "groupNearbyPhotos": MessageLookupByLibrary.simpleMessage( "Группировать фотографии рядом"), - "guestView": MessageLookupByLibrary.simpleMessage("Guest view"), + "guestView": MessageLookupByLibrary.simpleMessage("Гостевой вид"), "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( - "To enable guest view, please setup device passcode or screen lock in your system settings."), + "Чтобы включить гостевой вид, настройте пароль устройства или блокировку экрана в настройках системы."), "hearUsExplanation": MessageLookupByLibrary.simpleMessage( "Будет полезно, если вы укажете, где нашли нас, так как мы не отслеживаем установки приложения!"), "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( @@ -837,11 +834,12 @@ class MessageLookup extends MessageLookupByLibrary { "help": MessageLookupByLibrary.simpleMessage("помощь"), "hidden": MessageLookupByLibrary.simpleMessage("Скрыто"), "hide": MessageLookupByLibrary.simpleMessage("Скрыть"), - "hideContent": MessageLookupByLibrary.simpleMessage("Hide content"), + "hideContent": + MessageLookupByLibrary.simpleMessage("Скрыть содержимое"), "hideContentDescriptionAndroid": MessageLookupByLibrary.simpleMessage( - "Hides app content in the app switcher and disables screenshots"), + "Скрывает содержимое приложения в переключателе приложений и отключает скриншоты"), "hideContentDescriptionIos": MessageLookupByLibrary.simpleMessage( - "Hides app content in the app switcher"), + "Скрывает содержимое приложения в переключателе приложений"), "hiding": MessageLookupByLibrary.simpleMessage("Скрытие..."), "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("Размещено на OSM France"), @@ -857,7 +855,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ничего не делать"), "ignoredFolderUploadReason": MessageLookupByLibrary.simpleMessage( "Некоторые файлы в этом альбоме пропущены, потому что они ранее были удалены из Ente."), - "immediately": MessageLookupByLibrary.simpleMessage("Immediately"), + "immediately": MessageLookupByLibrary.simpleMessage("Немедленно"), "importing": MessageLookupByLibrary.simpleMessage("Импорт...."), "incorrectCode": MessageLookupByLibrary.simpleMessage("Неверный код"), "incorrectPasswordTitle": @@ -895,7 +893,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Похоже, что-то пошло не так. Пожалуйста, повторите попытку через некоторое время. Если ошибка повторится, обратитесь в нашу службу поддержки."), - "itemCount": m32, + "itemCount": m35, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Элементы показывают количество дней, оставшихся до окончательного удаления"), @@ -924,7 +922,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Лимит устройств"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Разрешён"), "linkExpired": MessageLookupByLibrary.simpleMessage("Истекшая"), - "linkExpiresOn": m33, + "linkExpiresOn": m36, "linkExpiry": MessageLookupByLibrary.simpleMessage("Срок действия ссылки истек"), "linkHasExpired": @@ -1005,10 +1003,8 @@ class MessageLookup extends MessageLookupByLibrary { "maps": MessageLookupByLibrary.simpleMessage("Карты"), "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), - "memoryCount": m34, + "memoryCount": m0, "merchandise": MessageLookupByLibrary.simpleMessage("Товары"), - "mlIndexingDescription": MessageLookupByLibrary.simpleMessage( - "Пожалуйста, обратите внимание, что машинное обучение приведет к увеличению затрат интернета и энергопотребления до тех пор, пока не будут индексированы все элементы."), "mobileWebDesktop": MessageLookupByLibrary.simpleMessage("Телефон, Web, ПК"), "moderateStrength": MessageLookupByLibrary.simpleMessage("Средний"), @@ -1017,12 +1013,13 @@ class MessageLookup extends MessageLookupByLibrary { "Измените свой запрос или попробуйте поискать"), "moments": MessageLookupByLibrary.simpleMessage("Мгновения"), "monthly": MessageLookupByLibrary.simpleMessage("Ежемесячно"), - "moveItem": m35, + "moreDetails": MessageLookupByLibrary.simpleMessage("Подробнее"), + "moveItem": m37, "moveToAlbum": MessageLookupByLibrary.simpleMessage("Переместить в альбом"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage( "Переместить в скрытый альбом"), - "movedSuccessfullyTo": m36, + "movedSuccessfullyTo": m38, "movedToTrash": MessageLookupByLibrary.simpleMessage("Перемещено в корзину"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1036,7 +1033,7 @@ class MessageLookup extends MessageLookupByLibrary { "newAlbum": MessageLookupByLibrary.simpleMessage("Новый альбом"), "newToEnte": MessageLookupByLibrary.simpleMessage("Впервые в Ente"), "newest": MessageLookupByLibrary.simpleMessage("Самые новые"), - "next": MessageLookupByLibrary.simpleMessage("Next"), + "next": MessageLookupByLibrary.simpleMessage("Далее"), "no": MessageLookupByLibrary.simpleMessage("Нет"), "noAlbumsSharedByYouYet": MessageLookupByLibrary.simpleMessage("У вас пока нет альбомов"), @@ -1061,7 +1058,7 @@ class MessageLookup extends MessageLookupByLibrary { "noPhotosFoundHere": MessageLookupByLibrary.simpleMessage("Здесь нет фотографий"), "noQuickLinksSelected": - MessageLookupByLibrary.simpleMessage("No quick links selected"), + MessageLookupByLibrary.simpleMessage("Не выбрано быстрых ссылок"), "noRecoveryKey": MessageLookupByLibrary.simpleMessage("Нет ключа восстановления?"), "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( @@ -1069,8 +1066,9 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Ничего не найденo"), "noResultsFound": MessageLookupByLibrary.simpleMessage("Ничего не найдено"), - "noSystemLockFound": - MessageLookupByLibrary.simpleMessage("No system lock found"), + "noSystemLockFound": MessageLookupByLibrary.simpleMessage( + "Системная блокировка не найдена"), + "notPersonLabel": m39, "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( "Пока никто не поделился с вами"), "nothingToSeeHere": @@ -1099,6 +1097,7 @@ class MessageLookup extends MessageLookupByLibrary { "pairWithPin": MessageLookupByLibrary.simpleMessage("Соединить с PIN"), "pairingComplete": MessageLookupByLibrary.simpleMessage("Сопряжение завершено"), + "panorama": MessageLookupByLibrary.simpleMessage("Панорама"), "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage( "Верификация еще не завершена"), "passkey": MessageLookupByLibrary.simpleMessage("Ключ"), @@ -1109,9 +1108,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Пароль успешно изменён"), "passwordLock": MessageLookupByLibrary.simpleMessage("Блокировка паролем"), - "passwordStrength": m39, + "passwordStrength": m41, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( - "Password strength is calculated considering the length of the password, used characters, and whether or not the password appears in the top 10,000 most used passwords"), + "Надежность пароля рассчитывается с учетом длины пароля, используемых символов, и появлением пароля в 10 000 наиболее используемых"), "passwordWarning": MessageLookupByLibrary.simpleMessage( "Мы не храним этот пароль, поэтому если вы забудете его, мы не сможем расшифровать ваши данные"), "paymentDetails": @@ -1119,7 +1118,7 @@ class MessageLookup extends MessageLookupByLibrary { "paymentFailed": MessageLookupByLibrary.simpleMessage("Сбой платежа"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "К сожалению, ваш платеж не был выполнен. Пожалуйста, свяжитесь со службой поддержки, и мы вам поможем!"), - "paymentFailedTalkToProvider": m40, + "paymentFailedTalkToProvider": m42, "pendingItems": MessageLookupByLibrary.simpleMessage("Отложенные элементы"), "pendingSync": @@ -1145,10 +1144,10 @@ class MessageLookup extends MessageLookupByLibrary { "pickCenterPoint": MessageLookupByLibrary.simpleMessage("Указать центральную точку"), "pinAlbum": MessageLookupByLibrary.simpleMessage("Закрепить альбом"), - "pinLock": MessageLookupByLibrary.simpleMessage("PIN lock"), + "pinLock": MessageLookupByLibrary.simpleMessage("Блокировка PIN-кодом"), "playOnTv": MessageLookupByLibrary.simpleMessage("Воспроизвести альбом на ТВ"), - "playStoreFreeTrialValidTill": m41, + "playStoreFreeTrialValidTill": m43, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("Подписка на PlayStore"), "pleaseCheckYourInternetConnectionAndTryAgain": @@ -1160,14 +1159,14 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Если проблема не устранена, обратитесь в службу поддержки"), - "pleaseEmailUsAt": m42, + "pleaseEmailUsAt": m44, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage("Предоставьте разрешение"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Пожалуйста, войдите снова"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( - "Please select quick links to remove"), - "pleaseSendTheLogsTo": m43, + "Пожалуйста, выберите быстрые ссылки для удаления"), + "pleaseSendTheLogsTo": m45, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage( "Пожалуйста, попробуйте ещё раз"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1204,7 +1203,7 @@ class MessageLookup extends MessageLookupByLibrary { "rateTheApp": MessageLookupByLibrary.simpleMessage("Оценить приложение"), "rateUs": MessageLookupByLibrary.simpleMessage("Оцените нас"), - "rateUsOnStore": m44, + "rateUsOnStore": m46, "recover": MessageLookupByLibrary.simpleMessage("Восстановить"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Восстановить аккаунт"), @@ -1231,15 +1230,16 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Сбросить пароль"), "reddit": MessageLookupByLibrary.simpleMessage("Reddit"), "reenterPassword": - MessageLookupByLibrary.simpleMessage("Re-enter password"), - "reenterPin": MessageLookupByLibrary.simpleMessage("Re-enter PIN"), + MessageLookupByLibrary.simpleMessage("Подтвердите пароль"), + "reenterPin": + MessageLookupByLibrary.simpleMessage("Введите PIN-код ещё раз"), "referFriendsAnd2xYourPlan": MessageLookupByLibrary.simpleMessage( "Пригласите друзей и удвойте свой план"), "referralStep1": MessageLookupByLibrary.simpleMessage( "1. Дайте этот код своим друзьям"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Они подписываются на платный план"), - "referralStep3": m45, + "referralStep3": m47, "referrals": MessageLookupByLibrary.simpleMessage("Рефералы"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Рефералы в настоящее время приостановлены"), @@ -1266,13 +1266,13 @@ class MessageLookup extends MessageLookupByLibrary { "removeLink": MessageLookupByLibrary.simpleMessage("Удалить ссылку"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Исключить участника"), - "removeParticipantBody": m46, + "removeParticipantBody": m48, "removePersonLabel": MessageLookupByLibrary.simpleMessage("Удалить метку человека"), "removePublicLink": MessageLookupByLibrary.simpleMessage("Удалить публичную ссылку"), "removePublicLinks": - MessageLookupByLibrary.simpleMessage("Remove public links"), + MessageLookupByLibrary.simpleMessage("Удалить публичные ссылки"), "removeShareItemsWarning": MessageLookupByLibrary.simpleMessage( "Некоторые элементы, которые вы удаляете, были добавлены другими людьми, и вы потеряете к ним доступ"), "removeWithQuestionMark": @@ -1286,7 +1286,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Переименовать файл"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Продлить подписку"), - "renewsOn": m47, + "renewsOn": m49, "reportABug": MessageLookupByLibrary.simpleMessage("Сообщить об ошибке"), "reportBug": MessageLookupByLibrary.simpleMessage("Сообщить об ошибке"), @@ -1306,6 +1306,8 @@ class MessageLookup extends MessageLookupByLibrary { "retry": MessageLookupByLibrary.simpleMessage("Повторить"), "reviewDeduplicateItems": MessageLookupByLibrary.simpleMessage( "Пожалуйста, проверьте и удалите те элементы, которые вы считаете что это дубликаты."), + "reviewSuggestions": + MessageLookupByLibrary.simpleMessage("Посмотреть предложения"), "right": MessageLookupByLibrary.simpleMessage("Вправо"), "rotate": MessageLookupByLibrary.simpleMessage("Повернуть"), "rotateLeft": MessageLookupByLibrary.simpleMessage("Повернуть влево"), @@ -1354,7 +1356,7 @@ class MessageLookup extends MessageLookupByLibrary { "Групповые фотографии, сделанные в некотором радиусе от фотографии"), "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage( "Пригласите людей, и вы увидите все фотографии, которыми они поделились здесь"), - "searchResultCount": m48, + "searchResultCount": m50, "security": MessageLookupByLibrary.simpleMessage("Безопасность"), "selectALocation": MessageLookupByLibrary.simpleMessage("Выбрать место"), @@ -1380,8 +1382,8 @@ class MessageLookup extends MessageLookupByLibrary { "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage( "Выбранные элементы будут удалены из всех альбомов и перемещены в корзину."), - "selectedPhotos": m49, - "selectedPhotosWithYours": m50, + "selectedPhotos": m1, + "selectedPhotosWithYours": m51, "send": MessageLookupByLibrary.simpleMessage("Отправить"), "sendEmail": MessageLookupByLibrary.simpleMessage( "Отправить электронное письмо"), @@ -1398,8 +1400,9 @@ class MessageLookup extends MessageLookupByLibrary { "setCover": MessageLookupByLibrary.simpleMessage("Установить обложку"), "setLabel": MessageLookupByLibrary.simpleMessage("Установить"), "setNewPassword": - MessageLookupByLibrary.simpleMessage("Set new password"), - "setNewPin": MessageLookupByLibrary.simpleMessage("Set new PIN"), + MessageLookupByLibrary.simpleMessage("Задать новый пароль"), + "setNewPin": + MessageLookupByLibrary.simpleMessage("Установите новый PIN"), "setPasswordTitle": MessageLookupByLibrary.simpleMessage("Установить пароль"), "setRadius": MessageLookupByLibrary.simpleMessage("Установить радиус"), @@ -1413,10 +1416,10 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Поделиться альбомом сейчас"), "shareLink": MessageLookupByLibrary.simpleMessage("Поделиться ссылкой"), - "shareMyVerificationID": m51, + "shareMyVerificationID": m52, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Поделитесь только с теми людьми, с которыми вы хотите"), - "shareTextConfirmOthersVerificationID": m52, + "shareTextConfirmOthersVerificationID": m2, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( "Скачай Ente, чтобы мы могли легко поделиться фотографиями и видео без сжатия\n\nhttps://ente.io"), "shareTextReferralCode": m53, @@ -1529,7 +1532,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("нажмите, чтобы скопировать"), "tapToEnterCode": MessageLookupByLibrary.simpleMessage("Нажмите, чтобы ввести код"), - "tapToUnlock": MessageLookupByLibrary.simpleMessage("Tap to unlock"), + "tapToUnlock": + MessageLookupByLibrary.simpleMessage("Нажмите для разблокировки"), "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Похоже, что-то пошло не так. Пожалуйста, повторите попытку через некоторое время. Если ошибка повторится, обратитесь в нашу службу поддержки."), "terminate": MessageLookupByLibrary.simpleMessage("Завершить"), @@ -1576,17 +1580,14 @@ class MessageLookup extends MessageLookupByLibrary { "Совершив это действие, Вы выйдете из своей учетной записи!"), "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage( - "This will remove public links of all selected quick links."), - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": - MessageLookupByLibrary.simpleMessage( - "To enable app lock, please setup device passcode or screen lock in your system settings."), + "Это удалит публичные ссылки на все выбранные быстрые ссылки."), "toHideAPhotoOrVideo": MessageLookupByLibrary.simpleMessage("Скрыть фото или видео"), "toResetVerifyEmail": MessageLookupByLibrary.simpleMessage( "Чтобы сбросить пароль, сначала подтвердите свой адрес электронной почты."), "todaysLogs": MessageLookupByLibrary.simpleMessage("Сегодняшние логи"), - "tooManyIncorrectAttempts": - MessageLookupByLibrary.simpleMessage("Too many incorrect attempts"), + "tooManyIncorrectAttempts": MessageLookupByLibrary.simpleMessage( + "Слишком много неудачных попыток"), "total": MessageLookupByLibrary.simpleMessage("всего"), "totalSize": MessageLookupByLibrary.simpleMessage("Общий размер"), "trash": MessageLookupByLibrary.simpleMessage("Корзина"), @@ -1637,6 +1638,8 @@ class MessageLookup extends MessageLookupByLibrary { "Скидка 50%, до 4-го декабря."), "usableReferralStorageInfo": MessageLookupByLibrary.simpleMessage( "Доступное хранилище ограничено вашим текущим планом. Избыточное полученное хранилище автоматически станет доступным для использования при улучшении плана."), + "useAsCover": + MessageLookupByLibrary.simpleMessage("Использовать для обложки"), "usePublicLinksForPeopleNotOnEnte": MessageLookupByLibrary.simpleMessage( "Использовать публичные ссылки для людей не на Ente"), @@ -1663,6 +1666,7 @@ class MessageLookup extends MessageLookupByLibrary { "verifying": MessageLookupByLibrary.simpleMessage("Проверка..."), "verifyingRecoveryKey": MessageLookupByLibrary.simpleMessage( "Проверка ключа восстановления..."), + "videoInfo": MessageLookupByLibrary.simpleMessage("Информация о видео"), "videoSmallCase": MessageLookupByLibrary.simpleMessage("видео"), "videos": MessageLookupByLibrary.simpleMessage("Видео"), "viewActiveSessions": @@ -1673,8 +1677,6 @@ class MessageLookup extends MessageLookupByLibrary { "viewAllExifData": MessageLookupByLibrary.simpleMessage("Просмотреть все данные EXIF"), "viewLargeFiles": MessageLookupByLibrary.simpleMessage("Большие файлы"), - "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( - "Просмотр файлов, которые потребляют наибольшее количество памяти"), "viewLogs": MessageLookupByLibrary.simpleMessage("Посмотреть логи"), "viewRecoveryKey": MessageLookupByLibrary.simpleMessage( "Просмотреть ключ восстановления"), diff --git a/mobile/lib/generated/intl/messages_sv.dart b/mobile/lib/generated/intl/messages_sv.dart new file mode 100644 index 0000000000..16f3eafe48 --- /dev/null +++ b/mobile/lib/generated/intl/messages_sv.dart @@ -0,0 +1,548 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a sv locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'sv'; + + static String m9(count) => + "${Intl.plural(count, zero: 'Inga deltagare', one: '1 deltagare', other: '${count} deltagare')}"; + + static String m10(versionValue) => "Version: ${versionValue}"; + + static String m11(freeAmount, storageUnit) => + "${freeAmount} ${storageUnit} gratis"; + + static String m13(user) => + "${user} kommer inte att kunna lägga till fler foton till detta album\n\nDe kommer fortfarande att kunna ta bort befintliga foton som lagts till av dem"; + + static String m19(count) => + "${Intl.plural(count, one: 'Radera ${count} objekt', other: 'Radera ${count} objekt')}"; + + static String m22(supportEmail) => + "Vänligen skicka ett e-postmeddelande till ${supportEmail} från din registrerade e-postadress"; + + static String m26(email) => + "${email} har inte ett Ente-konto.\n\nSkicka dem en inbjudan för att dela bilder."; + + static String m35(count) => + "${Intl.plural(count, one: '${count} objekt', other: '${count} objekt')}"; + + static String m36(expiryTime) => "Länken upphör att gälla ${expiryTime}"; + + static String m37(count) => + "${Intl.plural(count, one: 'Flytta objekt', other: 'Flytta objekt')}"; + + static String m39(name) => "Inte ${name}?"; + + static String m40(familyAdminEmail) => + "Kontakta ${familyAdminEmail} för att ändra din kod."; + + static String m41(passwordStrengthValue) => + "Lösenordsstyrka: ${passwordStrengthValue}"; + + static String m46(storeName) => "Betygsätt oss på ${storeName}"; + + static String m50(count) => + "${Intl.plural(count, one: '${count} resultat hittades', other: '${count} resultat hittades')}"; + + static String m52(verificationID) => + "Här är mitt verifierings-ID: ${verificationID} för ente.io."; + + static String m2(verificationID) => + "Hallå, kan du bekräfta att detta är ditt ente.io verifierings-ID: ${verificationID}"; + + static String m54(numberOfPeople) => + "${Intl.plural(numberOfPeople, zero: 'Dela med specifika personer', one: 'Delad med en person', other: 'Delad med ${numberOfPeople} personer')}"; + + static String m59(storageAmountInGB) => "${storageAmountInGB} GB"; + + static String m65(email) => "Detta är ${email}s verifierings-ID"; + + static String m66(count) => + "${Intl.plural(count, zero: '', one: '1 dag', other: '${count} dagar')}"; + + static String m68(email) => "Bekräfta ${email}"; + + static String m69(email) => + "Vi har skickat ett e-postmeddelande till ${email}"; + + static String m70(count) => + "${Intl.plural(count, one: '${count} år sedan', other: '${count} år sedan')}"; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "aNewVersionOfEnteIsAvailable": MessageLookupByLibrary.simpleMessage( + "En ny version av Ente är tillgänglig."), + "about": MessageLookupByLibrary.simpleMessage("Om"), + "account": MessageLookupByLibrary.simpleMessage("Konto"), + "accountWelcomeBack": + MessageLookupByLibrary.simpleMessage("Välkommen tillbaka!"), + "ackPasswordLostWarning": MessageLookupByLibrary.simpleMessage( + "Jag förstår att om jag förlorar mitt lösenord kan jag förlora mina data eftersom min data är end-to-end-krypterad."), + "activeSessions": + MessageLookupByLibrary.simpleMessage("Aktiva sessioner"), + "addANewEmail": MessageLookupByLibrary.simpleMessage( + "Lägg till en ny e-postadress"), + "addCollaborator": + MessageLookupByLibrary.simpleMessage("Lägg till samarbetspartner"), + "addLocationButton": MessageLookupByLibrary.simpleMessage("Lägg till"), + "addMore": MessageLookupByLibrary.simpleMessage("Lägg till fler"), + "addViewer": MessageLookupByLibrary.simpleMessage("Lägg till bildvy"), + "addedAs": MessageLookupByLibrary.simpleMessage("Lades till som"), + "after1Day": MessageLookupByLibrary.simpleMessage("Om en dag"), + "after1Hour": MessageLookupByLibrary.simpleMessage("Om en timme"), + "after1Month": MessageLookupByLibrary.simpleMessage("Om en månad"), + "after1Week": MessageLookupByLibrary.simpleMessage("Om en vecka"), + "after1Year": MessageLookupByLibrary.simpleMessage("Om ett år"), + "albumOwner": MessageLookupByLibrary.simpleMessage("Ägare"), + "albumParticipantsCount": m9, + "albumUpdated": + MessageLookupByLibrary.simpleMessage("Album uppdaterat"), + "albums": MessageLookupByLibrary.simpleMessage("Album"), + "allowAddPhotosDescription": MessageLookupByLibrary.simpleMessage( + "Tillåt personer med länken att även lägga till foton i det delade albumet."), + "allowAddingPhotos": + MessageLookupByLibrary.simpleMessage("Tillåt lägga till foton"), + "allowDownloads": + MessageLookupByLibrary.simpleMessage("Tillåt nedladdningar"), + "androidCancelButton": MessageLookupByLibrary.simpleMessage("Avbryt"), + "appVersion": m10, + "apply": MessageLookupByLibrary.simpleMessage("Verkställ"), + "applyCodeTitle": MessageLookupByLibrary.simpleMessage("Använd kod"), + "areYouSureYouWantToLogout": MessageLookupByLibrary.simpleMessage( + "Är du säker på att du vill logga ut?"), + "askDeleteReason": MessageLookupByLibrary.simpleMessage( + "Vad är den främsta anledningen till att du raderar ditt konto?"), + "availableStorageSpace": m11, + "blog": MessageLookupByLibrary.simpleMessage("Blogg"), + "cancel": MessageLookupByLibrary.simpleMessage("Avbryt"), + "cannotAddMorePhotosAfterBecomingViewer": m13, + "change": MessageLookupByLibrary.simpleMessage("Ändra"), + "changeEmail": + MessageLookupByLibrary.simpleMessage("Ändra e-postadress"), + "changePassword": + MessageLookupByLibrary.simpleMessage("Ändra lösenord"), + "changePasswordTitle": + MessageLookupByLibrary.simpleMessage("Ändra lösenord"), + "changePermissions": + MessageLookupByLibrary.simpleMessage("Ändra behörighet?"), + "checkInboxAndSpamFolder": MessageLookupByLibrary.simpleMessage( + "Kontrollera din inkorg (och skräppost) för att slutföra verifieringen"), + "cl_guest_view_title": MessageLookupByLibrary.simpleMessage("Gästvy"), + "cl_video_player_title": + MessageLookupByLibrary.simpleMessage("Videospelare"), + "claimed": MessageLookupByLibrary.simpleMessage("Nyttjad"), + "close": MessageLookupByLibrary.simpleMessage("Stäng"), + "codeAppliedPageTitle": + MessageLookupByLibrary.simpleMessage("Kod tillämpad"), + "codeCopiedToClipboard": MessageLookupByLibrary.simpleMessage( + "Koden har kopierats till urklipp"), + "collabLinkSectionDescription": MessageLookupByLibrary.simpleMessage( + "Skapa en länk så att personer kan lägga till och visa foton i ditt delade album utan att behöva en Ente app eller konto. Perfekt för att samla in bilder från evenemang."), + "collaborativeLink": + MessageLookupByLibrary.simpleMessage("Samarbetslänk"), + "collaborator": + MessageLookupByLibrary.simpleMessage("Samarbetspartner"), + "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": + MessageLookupByLibrary.simpleMessage( + "Samarbetspartner kan lägga till foton och videor till det delade albumet."), + "collectPhotos": MessageLookupByLibrary.simpleMessage("Samla in foton"), + "color": MessageLookupByLibrary.simpleMessage("Färg"), + "confirm": MessageLookupByLibrary.simpleMessage("Bekräfta"), + "confirmAccountDeletion": + MessageLookupByLibrary.simpleMessage("Bekräfta radering av konto"), + "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( + "Ja, jag vill ta bort detta konto och all data permanent."), + "confirmPassword": + MessageLookupByLibrary.simpleMessage("Bekräfta lösenord"), + "confirmRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Bekräfta återställningsnyckel"), + "confirmYourRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Bekräfta din återställningsnyckel"), + "contactSupport": + MessageLookupByLibrary.simpleMessage("Kontakta support"), + "contacts": MessageLookupByLibrary.simpleMessage("Kontakter"), + "continueLabel": MessageLookupByLibrary.simpleMessage("Fortsätt"), + "copyEmailAddress": + MessageLookupByLibrary.simpleMessage("Kopiera e-postadress"), + "copyLink": MessageLookupByLibrary.simpleMessage("Kopiera länk"), + "copypasteThisCodentoYourAuthenticatorApp": + MessageLookupByLibrary.simpleMessage( + "Kopiera-klistra in den här koden\ntill din autentiseringsapp"), + "create": MessageLookupByLibrary.simpleMessage("Skapa"), + "createAccount": MessageLookupByLibrary.simpleMessage("Skapa konto"), + "createNewAccount": + MessageLookupByLibrary.simpleMessage("Skapa nytt konto"), + "createPublicLink": + MessageLookupByLibrary.simpleMessage("Skapa offentlig länk"), + "custom": MessageLookupByLibrary.simpleMessage("Anpassad"), + "darkTheme": MessageLookupByLibrary.simpleMessage("Mörkt"), + "decrypting": MessageLookupByLibrary.simpleMessage("Dekrypterar..."), + "delete": MessageLookupByLibrary.simpleMessage("Radera"), + "deleteAccount": MessageLookupByLibrary.simpleMessage("Radera konto"), + "deleteAccountFeedbackPrompt": MessageLookupByLibrary.simpleMessage( + "Vi är ledsna att se dig lämna oss. Vänligen dela dina synpunkter för att hjälpa oss att förbättra."), + "deleteAccountPermanentlyButton": + MessageLookupByLibrary.simpleMessage("Radera kontot permanent"), + "deleteAll": MessageLookupByLibrary.simpleMessage("Radera alla"), + "deleteEmailRequest": MessageLookupByLibrary.simpleMessage( + "Vänligen skicka ett e-postmeddelande till account-deletion@ente.io från din registrerade e-postadress."), + "deleteFromDevice": + MessageLookupByLibrary.simpleMessage("Radera från enhet"), + "deleteItemCount": m19, + "deleteReason1": MessageLookupByLibrary.simpleMessage( + "Det saknas en viktig funktion som jag behöver"), + "deleteReason2": MessageLookupByLibrary.simpleMessage( + "Appen eller en viss funktion beter sig inte som jag tycker det ska"), + "deleteReason3": MessageLookupByLibrary.simpleMessage( + "Jag hittade en annan tjänst som jag gillar bättre"), + "deleteReason4": + MessageLookupByLibrary.simpleMessage("Min orsak finns inte med"), + "deleteRequestSLAText": MessageLookupByLibrary.simpleMessage( + "Din begäran kommer att hanteras inom 72 timmar."), + "disableDownloadWarningBody": MessageLookupByLibrary.simpleMessage( + "Besökare kan fortfarande ta skärmdumpar eller spara en kopia av dina foton med hjälp av externa verktyg"), + "disableDownloadWarningTitle": + MessageLookupByLibrary.simpleMessage("Vänligen notera:"), + "discord": MessageLookupByLibrary.simpleMessage("Discord"), + "doThisLater": MessageLookupByLibrary.simpleMessage("Gör detta senare"), + "done": MessageLookupByLibrary.simpleMessage("Klar"), + "dropSupportEmail": m22, + "edit": MessageLookupByLibrary.simpleMessage("Redigera"), + "email": MessageLookupByLibrary.simpleMessage("E-post"), + "emailNoEnteAccount": m26, + "encryption": MessageLookupByLibrary.simpleMessage("Kryptering"), + "encryptionKeys": + MessageLookupByLibrary.simpleMessage("Krypteringsnycklar"), + "entePhotosPerm": MessageLookupByLibrary.simpleMessage( + "Ente behöver tillåtelse att bevara dina foton"), + "enterCode": MessageLookupByLibrary.simpleMessage("Ange kod"), + "enterCodeDescription": MessageLookupByLibrary.simpleMessage( + "Ange koden som din vän har angett för att få gratis lagring för er båda"), + "enterEmail": MessageLookupByLibrary.simpleMessage("Ange e-post"), + "enterNewPasswordToEncrypt": MessageLookupByLibrary.simpleMessage( + "Ange ett nytt lösenord som vi kan använda för att kryptera din data"), + "enterPassword": MessageLookupByLibrary.simpleMessage("Ange lösenord"), + "enterPasswordToEncrypt": MessageLookupByLibrary.simpleMessage( + "Ange ett lösenord som vi kan använda för att kryptera din data"), + "enterReferralCode": + MessageLookupByLibrary.simpleMessage("Ange hänvisningskod"), + "enterThe6digitCodeFromnyourAuthenticatorApp": + MessageLookupByLibrary.simpleMessage( + "Ange den 6-siffriga koden från din autentiseringsapp"), + "enterValidEmail": MessageLookupByLibrary.simpleMessage( + "Ange en giltig e-postadress."), + "enterYourEmailAddress": + MessageLookupByLibrary.simpleMessage("Ange din e-postadress"), + "enterYourPassword": + MessageLookupByLibrary.simpleMessage("Ange ditt lösenord"), + "enterYourRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Ange din återställningsnyckel"), + "exif": MessageLookupByLibrary.simpleMessage("EXIF"), + "expiredLinkInfo": MessageLookupByLibrary.simpleMessage( + "Denna länk har upphört att gälla. Välj ett nytt datum eller inaktivera tidsbegränsningen."), + "exportYourData": + MessageLookupByLibrary.simpleMessage("Exportera din data"), + "failedToApplyCode": MessageLookupByLibrary.simpleMessage( + "Det gick inte att använda koden"), + "feedback": MessageLookupByLibrary.simpleMessage("Feedback"), + "fileInfoAddDescHint": + MessageLookupByLibrary.simpleMessage("Lägg till en beskrivning..."), + "fileTypes": MessageLookupByLibrary.simpleMessage("Filtyper"), + "forgotPassword": + MessageLookupByLibrary.simpleMessage("Glömt lösenord"), + "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( + "Skapar krypteringsnycklar..."), + "goToSettings": + MessageLookupByLibrary.simpleMessage("Gå till inställningar"), + "guestView": MessageLookupByLibrary.simpleMessage("Gästvy"), + "howItWorks": + MessageLookupByLibrary.simpleMessage("Så här fungerar det"), + "howToViewShareeVerificationID": MessageLookupByLibrary.simpleMessage( + "Be dem att långtrycka på sin e-postadress på inställningsskärmen och verifiera att ID:n på båda enheterna matchar."), + "iOSOkButton": MessageLookupByLibrary.simpleMessage("OK"), + "ignoreUpdate": MessageLookupByLibrary.simpleMessage("Ignorera"), + "incorrectPasswordTitle": + MessageLookupByLibrary.simpleMessage("Felaktigt lösenord"), + "incorrectRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Felaktig återställningsnyckel"), + "incorrectRecoveryKeyBody": MessageLookupByLibrary.simpleMessage( + "Återställningsnyckeln du angav är felaktig"), + "incorrectRecoveryKeyTitle": MessageLookupByLibrary.simpleMessage( + "Felaktig återställningsnyckel"), + "insecureDevice": MessageLookupByLibrary.simpleMessage("Osäker enhet"), + "invalidEmailAddress": + MessageLookupByLibrary.simpleMessage("Ogiltig e-postadress"), + "invalidKey": MessageLookupByLibrary.simpleMessage("Ogiltig nyckel"), + "invalidRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Återställningsnyckeln du angav är inte giltig. Kontrollera att den innehåller 24 ord och kontrollera stavningen av varje ord.\n\nOm du har angett en äldre återställnings kod, se till att den är 64 tecken lång, och kontrollera var och en av bokstäverna."), + "inviteYourFriends": + MessageLookupByLibrary.simpleMessage("Bjud in dina vänner"), + "inviteYourFriendsToEnte": MessageLookupByLibrary.simpleMessage( + "Bjud in dina vänner till Ente"), + "itemCount": m35, + "kiloMeterUnit": MessageLookupByLibrary.simpleMessage("km"), + "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( + "Vänligen hjälp oss med denna information"), + "language": MessageLookupByLibrary.simpleMessage("Språk"), + "leave": MessageLookupByLibrary.simpleMessage("Lämna"), + "lightTheme": MessageLookupByLibrary.simpleMessage("Ljust"), + "linkDeviceLimit": MessageLookupByLibrary.simpleMessage("Enhetsgräns"), + "linkEnabled": MessageLookupByLibrary.simpleMessage("Aktiverat"), + "linkExpired": MessageLookupByLibrary.simpleMessage("Upphört"), + "linkExpiresOn": m36, + "linkExpiry": MessageLookupByLibrary.simpleMessage("Länken upphör"), + "linkHasExpired": + MessageLookupByLibrary.simpleMessage("Länk har upphört att gälla"), + "linkNeverExpires": MessageLookupByLibrary.simpleMessage("Aldrig"), + "lockButtonLabel": MessageLookupByLibrary.simpleMessage("Lås"), + "logInLabel": MessageLookupByLibrary.simpleMessage("Logga in"), + "loginSessionExpiredDetails": MessageLookupByLibrary.simpleMessage( + "Din session har upphört. Logga in igen."), + "loginTerms": MessageLookupByLibrary.simpleMessage( + "Genom att klicka på logga in godkänner jag användarvillkoren och våran integritetspolicy"), + "logout": MessageLookupByLibrary.simpleMessage("Logga ut"), + "lostDevice": MessageLookupByLibrary.simpleMessage("Förlorad enhet?"), + "manage": MessageLookupByLibrary.simpleMessage("Hantera"), + "manageLink": MessageLookupByLibrary.simpleMessage("Hantera länk"), + "manageParticipants": MessageLookupByLibrary.simpleMessage("Hantera"), + "manageSubscription": + MessageLookupByLibrary.simpleMessage("Hantera prenumeration"), + "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), + "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), + "mlConsent": + MessageLookupByLibrary.simpleMessage("Aktivera maskininlärning"), + "mlConsentTitle": + MessageLookupByLibrary.simpleMessage("Aktivera maskininlärning?"), + "moderateStrength": MessageLookupByLibrary.simpleMessage("Måttligt"), + "moveItem": m37, + "moveToAlbum": + MessageLookupByLibrary.simpleMessage("Flytta till album"), + "name": MessageLookupByLibrary.simpleMessage("Namn"), + "never": MessageLookupByLibrary.simpleMessage("Aldrig"), + "newAlbum": MessageLookupByLibrary.simpleMessage("Nytt album"), + "next": MessageLookupByLibrary.simpleMessage("Nästa"), + "no": MessageLookupByLibrary.simpleMessage("Nej"), + "noDeviceLimit": MessageLookupByLibrary.simpleMessage("Ingen"), + "noExifData": MessageLookupByLibrary.simpleMessage("Ingen EXIF-data"), + "noInternetConnection": + MessageLookupByLibrary.simpleMessage("Ingen internetanslutning"), + "noRecoveryKey": + MessageLookupByLibrary.simpleMessage("Ingen återställningsnyckel?"), + "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( + "På grund av vårt punkt-till-punkt-krypteringssystem så kan dina data inte avkrypteras utan ditt lösenord eller återställningsnyckel"), + "noResults": MessageLookupByLibrary.simpleMessage("Inga resultat"), + "noResultsFound": + MessageLookupByLibrary.simpleMessage("Inga resultat hittades"), + "notPersonLabel": m39, + "ok": MessageLookupByLibrary.simpleMessage("OK"), + "onlyFamilyAdminCanChangeCode": m40, + "oops": MessageLookupByLibrary.simpleMessage("Hoppsan"), + "orPickAnExistingOne": + MessageLookupByLibrary.simpleMessage("Eller välj en befintlig"), + "password": MessageLookupByLibrary.simpleMessage("Lösenord"), + "passwordChangedSuccessfully": + MessageLookupByLibrary.simpleMessage("Lösenordet har ändrats"), + "passwordLock": MessageLookupByLibrary.simpleMessage("Lösenordskydd"), + "passwordStrength": m41, + "passwordWarning": MessageLookupByLibrary.simpleMessage( + "Vi lagrar inte detta lösenord, så om du glömmer bort det, kan vi inte dekryptera dina data"), + "photoSmallCase": MessageLookupByLibrary.simpleMessage("foto"), + "pleaseCheckYourInternetConnectionAndTryAgain": + MessageLookupByLibrary.simpleMessage( + "Kontrollera din internetanslutning och försök igen."), + "pleaseLoginAgain": + MessageLookupByLibrary.simpleMessage("Logga in igen"), + "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Försök igen"), + "pleaseWait": MessageLookupByLibrary.simpleMessage("Var god vänta..."), + "privacyPolicyTitle": + MessageLookupByLibrary.simpleMessage("Integritetspolicy"), + "publicLinkEnabled": + MessageLookupByLibrary.simpleMessage("Offentlig länk aktiverad"), + "rateUsOnStore": m46, + "recover": MessageLookupByLibrary.simpleMessage("Återställ"), + "recoverAccount": + MessageLookupByLibrary.simpleMessage("Återställ konto"), + "recoverButton": MessageLookupByLibrary.simpleMessage("Återställ"), + "recoveryKey": + MessageLookupByLibrary.simpleMessage("Återställningsnyckel"), + "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( + "Återställningsnyckel kopierad till urklipp"), + "recoveryKeyOnForgotPassword": MessageLookupByLibrary.simpleMessage( + "Om du glömmer ditt lösenord är det enda sättet du kan återställa dina data med denna nyckel."), + "recoveryKeySaveDescription": MessageLookupByLibrary.simpleMessage( + "Vi lagrar inte och har därför inte åtkomst till denna nyckel, vänligen spara denna 24 ords nyckel på en säker plats."), + "recoveryKeySuccessBody": MessageLookupByLibrary.simpleMessage( + "Grymt! Din återställningsnyckel är giltig. Tack för att du verifierade.\n\nKom ihåg att hålla din återställningsnyckel säker med backups."), + "recoveryKeyVerified": MessageLookupByLibrary.simpleMessage( + "Återställningsnyckel verifierad"), + "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( + "Din återställningsnyckel är det enda sättet att återställa dina foton om du glömmer ditt lösenord. Du hittar din återställningsnyckel i Inställningar > Säkerhet.\n\nAnge din återställningsnyckel här för att verifiera att du har sparat den ordentligt."), + "recoverySuccessful": + MessageLookupByLibrary.simpleMessage("Återställning lyckades!"), + "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( + "Denna enhet är inte tillräckligt kraftfull för att verifiera ditt lösenord, men vi kan återskapa det på ett sätt som fungerar med alla enheter.\n\nLogga in med din återställningsnyckel och återskapa ditt lösenord (du kan använda samma igen om du vill)."), + "recreatePasswordTitle": + MessageLookupByLibrary.simpleMessage("Återskapa lösenord"), + "reddit": MessageLookupByLibrary.simpleMessage("Reddit"), + "remove": MessageLookupByLibrary.simpleMessage("Ta bort"), + "removeLink": MessageLookupByLibrary.simpleMessage("Radera länk"), + "removeParticipant": + MessageLookupByLibrary.simpleMessage("Ta bort användaren"), + "renewSubscription": + MessageLookupByLibrary.simpleMessage("Förnya prenumeration"), + "resendEmail": MessageLookupByLibrary.simpleMessage( + "Skicka e-postmeddelandet igen"), + "resetPasswordTitle": + MessageLookupByLibrary.simpleMessage("Återställ lösenord"), + "resetToDefault": + MessageLookupByLibrary.simpleMessage("Återställ till standard"), + "retry": MessageLookupByLibrary.simpleMessage("Försök igen"), + "save": MessageLookupByLibrary.simpleMessage("Spara"), + "saveKey": MessageLookupByLibrary.simpleMessage("Spara nyckel"), + "saveYourRecoveryKeyIfYouHaventAlready": + MessageLookupByLibrary.simpleMessage( + "Spara din återställningsnyckel om du inte redan har gjort det"), + "scanCode": MessageLookupByLibrary.simpleMessage("Skanna kod"), + "scanThisBarcodeWithnyourAuthenticatorApp": + MessageLookupByLibrary.simpleMessage( + "Skanna denna streckkod med\ndin autentiseringsapp"), + "search": MessageLookupByLibrary.simpleMessage("Sök"), + "searchResultCount": m50, + "selectLanguage": MessageLookupByLibrary.simpleMessage("Välj språk"), + "selectReason": MessageLookupByLibrary.simpleMessage("Välj anledning"), + "send": MessageLookupByLibrary.simpleMessage("Skicka"), + "sendEmail": MessageLookupByLibrary.simpleMessage("Skicka e-post"), + "sendInvite": MessageLookupByLibrary.simpleMessage("Skicka inbjudan"), + "sendLink": MessageLookupByLibrary.simpleMessage("Skicka länk"), + "setAPassword": + MessageLookupByLibrary.simpleMessage("Ange ett lösenord"), + "setPasswordTitle": + MessageLookupByLibrary.simpleMessage("Välj lösenord"), + "setupComplete": + MessageLookupByLibrary.simpleMessage("Konfiguration slutförd"), + "share": MessageLookupByLibrary.simpleMessage("Dela"), + "shareALink": MessageLookupByLibrary.simpleMessage("Dela en länk"), + "shareLink": MessageLookupByLibrary.simpleMessage("Dela länk"), + "shareMyVerificationID": m52, + "shareTextConfirmOthersVerificationID": m2, + "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( + "Ladda ner Ente så att vi enkelt kan dela bilder och videor med originell kvalitet\n\nhttps://ente.io"), + "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( + "Dela med icke-Ente användare"), + "shareWithPeopleSectionTitle": m54, + "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( + "Skapa delade och samarbetande album med andra Ente användare, inklusive användare med gratisnivån."), + "signUpTerms": MessageLookupByLibrary.simpleMessage( + "Jag samtycker till användarvillkoren och integritetspolicyn"), + "someoneSharingAlbumsWithYouShouldSeeTheSameId": + MessageLookupByLibrary.simpleMessage( + "Någon som delar album med dig bör se samma ID på deras enhet."), + "somethingWentWrong": + MessageLookupByLibrary.simpleMessage("Något gick fel"), + "somethingWentWrongPleaseTryAgain": + MessageLookupByLibrary.simpleMessage( + "Något gick fel, vänligen försök igen"), + "sorry": MessageLookupByLibrary.simpleMessage("Förlåt"), + "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": + MessageLookupByLibrary.simpleMessage( + "Tyvärr, vi kunde inte generera säkra nycklar på den här enheten.\n\nVänligen registrera dig från en annan enhet."), + "sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Sortera efter"), + "status": MessageLookupByLibrary.simpleMessage("Status"), + "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Du"), + "storageInGB": m59, + "strongStrength": MessageLookupByLibrary.simpleMessage("Starkt"), + "subscribe": MessageLookupByLibrary.simpleMessage("Prenumerera"), + "subscription": MessageLookupByLibrary.simpleMessage("Prenumeration"), + "tapToCopy": + MessageLookupByLibrary.simpleMessage("tryck för att kopiera"), + "tapToEnterCode": + MessageLookupByLibrary.simpleMessage("Tryck för att ange kod"), + "terminate": MessageLookupByLibrary.simpleMessage("Avsluta"), + "terminateSession": + MessageLookupByLibrary.simpleMessage("Avsluta sessionen?"), + "terms": MessageLookupByLibrary.simpleMessage("Villkor"), + "termsOfServicesTitle": MessageLookupByLibrary.simpleMessage("Villkor"), + "thankYou": MessageLookupByLibrary.simpleMessage("Tack"), + "theRecoveryKeyYouEnteredIsIncorrect": + MessageLookupByLibrary.simpleMessage( + "Återställningsnyckeln du angav är felaktig"), + "theme": MessageLookupByLibrary.simpleMessage("Tema"), + "thisCanBeUsedToRecoverYourAccountIfYou": + MessageLookupByLibrary.simpleMessage( + "Detta kan användas för att återställa ditt konto om du förlorar din andra faktor"), + "thisDevice": MessageLookupByLibrary.simpleMessage("Den här enheten"), + "thisIsPersonVerificationId": m65, + "thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage( + "Detta är ditt verifierings-ID"), + "thisWillLogYouOutOfTheFollowingDevice": + MessageLookupByLibrary.simpleMessage( + "Detta kommer att logga ut dig från följande enhet:"), + "thisWillLogYouOutOfThisDevice": MessageLookupByLibrary.simpleMessage( + "Detta kommer att logga ut dig från denna enhet!"), + "toResetVerifyEmail": MessageLookupByLibrary.simpleMessage( + "För att återställa ditt lösenord måste du först bekräfta din e-postadress."), + "trash": MessageLookupByLibrary.simpleMessage("Papperskorg"), + "trashDaysLeft": m66, + "tryAgain": MessageLookupByLibrary.simpleMessage("Försök igen"), + "twitter": MessageLookupByLibrary.simpleMessage("Twitter"), + "twofactorAuthenticationPageTitle": + MessageLookupByLibrary.simpleMessage("Tvåfaktorsautentisering"), + "twofactorSetup": + MessageLookupByLibrary.simpleMessage("Tvåfaktorskonfiguration"), + "update": MessageLookupByLibrary.simpleMessage("Uppdatera"), + "upgrade": MessageLookupByLibrary.simpleMessage("Uppgradera"), + "useAsCover": MessageLookupByLibrary.simpleMessage("Använd som omslag"), + "useRecoveryKey": + MessageLookupByLibrary.simpleMessage("Använd återställningsnyckel"), + "verificationId": + MessageLookupByLibrary.simpleMessage("Verifierings-ID"), + "verify": MessageLookupByLibrary.simpleMessage("Bekräfta"), + "verifyEmail": + MessageLookupByLibrary.simpleMessage("Bekräfta e-postadress"), + "verifyEmailID": m68, + "verifyPassword": + MessageLookupByLibrary.simpleMessage("Bekräfta lösenord"), + "verifyingRecoveryKey": MessageLookupByLibrary.simpleMessage( + "Verifierar återställningsnyckel..."), + "viewActiveSessions": + MessageLookupByLibrary.simpleMessage("Visa aktiva sessioner"), + "viewAll": MessageLookupByLibrary.simpleMessage("Visa alla"), + "viewLogs": MessageLookupByLibrary.simpleMessage("Visa loggar"), + "viewRecoveryKey": + MessageLookupByLibrary.simpleMessage("Visa återställningsnyckel"), + "viewer": MessageLookupByLibrary.simpleMessage("Bildvy"), + "weHaveSendEmailTo": m69, + "weakStrength": MessageLookupByLibrary.simpleMessage("Svagt"), + "welcomeBack": + MessageLookupByLibrary.simpleMessage("Välkommen tillbaka!"), + "whatsNew": MessageLookupByLibrary.simpleMessage("Nyheter"), + "yearsAgo": m70, + "yes": MessageLookupByLibrary.simpleMessage("Ja"), + "yesCancel": MessageLookupByLibrary.simpleMessage("Ja, avbryt"), + "yesConvertToViewer": + MessageLookupByLibrary.simpleMessage("Ja, konvertera till bildvy"), + "yesDelete": MessageLookupByLibrary.simpleMessage("Ja, radera"), + "yesLogout": MessageLookupByLibrary.simpleMessage("Ja, logga ut"), + "yesRenew": MessageLookupByLibrary.simpleMessage("Ja, förnya"), + "you": MessageLookupByLibrary.simpleMessage("Du"), + "yourAccountHasBeenDeleted": + MessageLookupByLibrary.simpleMessage("Ditt konto har raderats") + }; +} diff --git a/mobile/lib/generated/intl/messages_te.dart b/mobile/lib/generated/intl/messages_te.dart new file mode 100644 index 0000000000..5e415c9da0 --- /dev/null +++ b/mobile/lib/generated/intl/messages_te.dart @@ -0,0 +1,25 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a te locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'te'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => {}; +} diff --git a/mobile/lib/generated/intl/messages_th.dart b/mobile/lib/generated/intl/messages_th.dart new file mode 100644 index 0000000000..a1bc4df70a --- /dev/null +++ b/mobile/lib/generated/intl/messages_th.dart @@ -0,0 +1,365 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a th locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'th'; + + static String m4(count) => "${Intl.plural(count, other: 'เพิ่มรายการ')}"; + + static String m10(versionValue) => "รุ่น: ${versionValue}"; + + static String m19(count) => + "${Intl.plural(count, one: 'ลบ ${count} รายการ', other: 'ลบ ${count} รายการ')}"; + + static String m20(currentlyDeleting, totalCount) => + "กำลังลบ ${currentlyDeleting} / ${totalCount}"; + + static String m22(supportEmail) => + "กรุณาส่งอีเมลไปที่ ${supportEmail} จากที่อยู่อีเมลที่คุณลงทะเบียนไว้"; + + static String m34(currentlyProcessing, totalCount) => + "กำลังประมวลผล ${currentlyProcessing} / ${totalCount}"; + + static String m35(count) => "${Intl.plural(count, other: '${count} รายการ')}"; + + static String m37(count) => "${Intl.plural(count, other: 'ย้ายรายการ')}"; + + static String m41(passwordStrengthValue) => + "ความแข็งแรงของรหัสผ่าน: ${passwordStrengthValue}"; + + static String m60( + usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => + "ใช้ไป ${usedAmount} ${usedStorageUnit} จาก ${totalAmount} ${totalStorageUnit}"; + + static String m69(email) => "เราได้ส่งจดหมายไปยัง ${email}"; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "accountWelcomeBack": + MessageLookupByLibrary.simpleMessage("ยินดีต้อนรับกลับมา!"), + "ackPasswordLostWarning": MessageLookupByLibrary.simpleMessage( + "ฉันเข้าใจว่าหากฉันทำรหัสผ่านหาย ข้อมูลของฉันอาจสูญหายเนื่องจากข้อมูลของฉันมีการเข้ารหัสจากต้นทางถึงปลายทาง"), + "activeSessions": + MessageLookupByLibrary.simpleMessage("เซสชันที่ใช้งานอยู่"), + "addANewEmail": MessageLookupByLibrary.simpleMessage("เพิ่มอีเมลใหม่"), + "addCollaborator": + MessageLookupByLibrary.simpleMessage("เพิ่มผู้ทำงานร่วมกัน"), + "addItem": m4, + "addMore": MessageLookupByLibrary.simpleMessage("เพิ่มอีก"), + "addToAlbum": MessageLookupByLibrary.simpleMessage("เพิ่มไปยังอัลบั้ม"), + "addViewer": MessageLookupByLibrary.simpleMessage("เพิ่มผู้ชม"), + "after1Day": MessageLookupByLibrary.simpleMessage("หลังจาก 1 วัน"), + "after1Hour": MessageLookupByLibrary.simpleMessage("หลังจาก 1 ชั่วโมง"), + "after1Month": MessageLookupByLibrary.simpleMessage("หลังจาก 1 เดือน"), + "after1Week": MessageLookupByLibrary.simpleMessage("หลังจาก 1 สัปดาห์"), + "after1Year": MessageLookupByLibrary.simpleMessage("หลังจาก 1 ปี"), + "albumOwner": MessageLookupByLibrary.simpleMessage("เจ้าของ"), + "allowAddingPhotos": + MessageLookupByLibrary.simpleMessage("อนุญาตให้เพิ่มรูปภาพ"), + "allowDownloads": + MessageLookupByLibrary.simpleMessage("อนุญาตให้ดาวน์โหลด"), + "androidBiometricSuccess": + MessageLookupByLibrary.simpleMessage("สำเร็จ"), + "androidCancelButton": MessageLookupByLibrary.simpleMessage("ยกเลิก"), + "appVersion": m10, + "apply": MessageLookupByLibrary.simpleMessage("นำไปใช้"), + "askDeleteReason": MessageLookupByLibrary.simpleMessage( + "เหตุผลหลักที่คุณลบบัญชีคืออะไร?"), + "authToViewYourRecoveryKey": MessageLookupByLibrary.simpleMessage( + "โปรดตรวจสอบสิทธิ์เพื่อดูคีย์การกู้คืนของคุณ"), + "canOnlyCreateLinkForFilesOwnedByYou": + MessageLookupByLibrary.simpleMessage( + "สามารถสร้างลิงก์ได้เฉพาะไฟล์ที่คุณเป็นเจ้าของ"), + "cancel": MessageLookupByLibrary.simpleMessage("ยกเลิก"), + "changeEmail": MessageLookupByLibrary.simpleMessage("เปลี่ยนอีเมล"), + "changePasswordTitle": + MessageLookupByLibrary.simpleMessage("เปลี่ยนรหัสผ่าน"), + "checkInboxAndSpamFolder": MessageLookupByLibrary.simpleMessage( + "โปรดตรวจสอบกล่องจดหมาย (และสแปม) ของคุณ เพื่อยืนยันให้เสร็จสิ้น"), + "codeCopiedToClipboard": MessageLookupByLibrary.simpleMessage( + "คัดลอกรหัสไปยังคลิปบอร์ดแล้ว"), + "collectPhotos": MessageLookupByLibrary.simpleMessage("รวบรวมรูปภาพ"), + "color": MessageLookupByLibrary.simpleMessage("สี"), + "confirm": MessageLookupByLibrary.simpleMessage("ยืนยัน"), + "confirmAccountDeletion": + MessageLookupByLibrary.simpleMessage("ยืนยันการลบบัญชี"), + "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( + "ใช่ ฉันต้องการลบบัญชีนี้และข้อมูลที่เกี่ยวข้องทั้งหมดแบบถาวร"), + "confirmPassword": + MessageLookupByLibrary.simpleMessage("ยืนยันรหัสผ่าน"), + "confirmRecoveryKey": + MessageLookupByLibrary.simpleMessage("ยืนยันคีย์การกู้คืน"), + "confirmYourRecoveryKey": + MessageLookupByLibrary.simpleMessage("ยืนยันคีย์การกู้คืนของคุณ"), + "contactSupport": + MessageLookupByLibrary.simpleMessage("ติดต่อฝ่ายสนับสนุน"), + "continueLabel": MessageLookupByLibrary.simpleMessage("ดำเนินการต่อ"), + "copyLink": MessageLookupByLibrary.simpleMessage("คัดลอกลิงก์"), + "createAccount": MessageLookupByLibrary.simpleMessage("สร้างบัญชี"), + "createNewAccount": + MessageLookupByLibrary.simpleMessage("สร้างบัญชีใหม่"), + "createPublicLink": + MessageLookupByLibrary.simpleMessage("สร้างลิงก์สาธารณะ"), + "custom": MessageLookupByLibrary.simpleMessage("กำหนดเอง"), + "darkTheme": MessageLookupByLibrary.simpleMessage("มืด"), + "decrypting": MessageLookupByLibrary.simpleMessage("กำลังถอดรหัส..."), + "delete": MessageLookupByLibrary.simpleMessage("ลบ"), + "deleteAccount": MessageLookupByLibrary.simpleMessage("ลบบัญชี"), + "deleteAccountFeedbackPrompt": MessageLookupByLibrary.simpleMessage( + "เราเสียใจที่เห็นคุณไป โปรดแบ่งปันความคิดเห็นของคุณเพื่อช่วยให้เราปรับปรุง"), + "deleteAccountPermanentlyButton": + MessageLookupByLibrary.simpleMessage("ลบบัญชีถาวร"), + "deleteEmailRequest": MessageLookupByLibrary.simpleMessage( + "กรุณาส่งอีเมลไปที่ account-deletion@ente.io จากที่อยู่อีเมลที่คุณลงทะเบียนไว้"), + "deleteEmptyAlbums": + MessageLookupByLibrary.simpleMessage("ลบอัลบั้มที่ว่างเปล่า"), + "deleteEmptyAlbumsWithQuestionMark": + MessageLookupByLibrary.simpleMessage( + "ลบอัลบั้มที่ว่างเปล่าหรือไม่?"), + "deleteItemCount": m19, + "deleteProgress": m20, + "deleteReason1": MessageLookupByLibrary.simpleMessage( + "ขาดคุณสมบัติสำคัญที่ฉันต้องการ"), + "deleteReason2": MessageLookupByLibrary.simpleMessage( + "ตัวแอปหรือคุณสมบัติบางอย่างไม่ทำงานเหมือนที่ฉันคิดว่าควรจะเป็น"), + "deleteReason3": MessageLookupByLibrary.simpleMessage( + "ฉันเจอบริการอื่นที่ฉันชอบมากกว่า"), + "deleteReason4": + MessageLookupByLibrary.simpleMessage("เหตุผลของฉันไม่มีระบุไว้"), + "deleteRequestSLAText": MessageLookupByLibrary.simpleMessage( + "คำขอของคุณจะได้รับการดำเนินการภายใน 72 ชั่วโมง"), + "doThisLater": MessageLookupByLibrary.simpleMessage("ทำในภายหลัง"), + "dropSupportEmail": m22, + "edit": MessageLookupByLibrary.simpleMessage("แก้ไข"), + "editLocationTagTitle": + MessageLookupByLibrary.simpleMessage("แก้ไขตำแหน่ง"), + "eligible": MessageLookupByLibrary.simpleMessage("มีสิทธิ์"), + "email": MessageLookupByLibrary.simpleMessage("อีเมล"), + "enableMaps": MessageLookupByLibrary.simpleMessage("เปิดใช้งานแผนที่"), + "encryption": MessageLookupByLibrary.simpleMessage("การเข้ารหัส"), + "enterCode": MessageLookupByLibrary.simpleMessage("ป้อนรหัส"), + "enterEmail": MessageLookupByLibrary.simpleMessage("ใส่อีเมล"), + "enterNewPasswordToEncrypt": MessageLookupByLibrary.simpleMessage( + "ใส่รหัสผ่านใหม่ที่เราสามารถใช้เพื่อเข้ารหัสข้อมูลของคุณ"), + "enterPasswordToEncrypt": MessageLookupByLibrary.simpleMessage( + "ใส่รหัสผ่านที่เราสามารถใช้เพื่อเข้ารหัสข้อมูลของคุณ"), + "enterValidEmail": MessageLookupByLibrary.simpleMessage( + "โปรดใส่ที่อยู่อีเมลที่ถูกต้อง"), + "enterYourEmailAddress": + MessageLookupByLibrary.simpleMessage("ใส่ที่อยู่อีเมลของคุณ"), + "enterYourPassword": + MessageLookupByLibrary.simpleMessage("ใส่รหัสผ่านของคุณ"), + "enterYourRecoveryKey": + MessageLookupByLibrary.simpleMessage("ป้อนคีย์การกู้คืน"), + "faq": MessageLookupByLibrary.simpleMessage("คำถามที่พบบ่อย"), + "favorite": MessageLookupByLibrary.simpleMessage("ชื่นชอบ"), + "feedback": MessageLookupByLibrary.simpleMessage("ความคิดเห็น"), + "fileInfoAddDescHint": + MessageLookupByLibrary.simpleMessage("เพิ่มคำอธิบาย..."), + "forgotPassword": MessageLookupByLibrary.simpleMessage("ลืมรหัสผ่าน"), + "freeTrial": MessageLookupByLibrary.simpleMessage("ทดลองใช้ฟรี"), + "genericProgress": m34, + "goToSettings": MessageLookupByLibrary.simpleMessage("ไปที่การตั้งค่า"), + "hide": MessageLookupByLibrary.simpleMessage("ซ่อน"), + "hostedAtOsmFrance": + MessageLookupByLibrary.simpleMessage("โฮสต์ที่ OSM ฝรั่งเศส"), + "howItWorks": MessageLookupByLibrary.simpleMessage("วิธีการทำงาน"), + "iOSOkButton": MessageLookupByLibrary.simpleMessage("ตกลง"), + "importing": MessageLookupByLibrary.simpleMessage("กำลังนำเข้า...."), + "incorrectPasswordTitle": + MessageLookupByLibrary.simpleMessage("รหัสผ่านไม่ถูกต้อง"), + "incorrectRecoveryKey": + MessageLookupByLibrary.simpleMessage("คีย์การกู้คืนไม่ถูกต้อง"), + "incorrectRecoveryKeyBody": MessageLookupByLibrary.simpleMessage( + "คีย์การกู้คืนที่คุณป้อนไม่ถูกต้อง"), + "incorrectRecoveryKeyTitle": + MessageLookupByLibrary.simpleMessage("คีย์การกู้คืนไม่ถูกต้อง"), + "insecureDevice": + MessageLookupByLibrary.simpleMessage("อุปกรณ์ไม่ปลอดภัย"), + "invalidEmailAddress": + MessageLookupByLibrary.simpleMessage("ที่อยู่อีเมลไม่ถูกต้อง"), + "invalidKey": MessageLookupByLibrary.simpleMessage("รหัสไม่ถูกต้อง"), + "invalidRecoveryKey": MessageLookupByLibrary.simpleMessage( + "คีย์การกู้คืนที่คุณป้อนไม่ถูกต้อง โปรดตรวจสอบให้แน่ใจว่ามี 24 คำ และตรวจสอบการสะกดของแต่ละคำ\n\nหากคุณป้อนรหัสกู้คืนที่เก่ากว่า ตรวจสอบให้แน่ใจว่ามีความยาว 64 ตัวอักษร และตรวจสอบแต่ละตัวอักษร"), + "itemCount": m35, + "kindlyHelpUsWithThisInformation": + MessageLookupByLibrary.simpleMessage("กรุณาช่วยเราด้วยข้อมูลนี้"), + "lastUpdated": MessageLookupByLibrary.simpleMessage("อัปเดตล่าสุด"), + "lightTheme": MessageLookupByLibrary.simpleMessage("สว่าง"), + "linkCopiedToClipboard": MessageLookupByLibrary.simpleMessage( + "คัดลอกลิงก์ไปยังคลิปบอร์ดแล้ว"), + "linkHasExpired": + MessageLookupByLibrary.simpleMessage("ลิงก์หมดอายุแล้ว"), + "loadMessage9": MessageLookupByLibrary.simpleMessage( + "เราใช้ Xchacha20Poly1305 เพื่อเข้ารหัสข้อมูลของคุณอย่างปลอดภัย"), + "logInLabel": MessageLookupByLibrary.simpleMessage("เข้าสู่ระบบ"), + "loginTerms": MessageLookupByLibrary.simpleMessage( + "โดยการคลิกเข้าสู่ระบบ ฉันยอมรับเงื่อนไขการให้บริการและนโยบายความเป็นส่วนตัว"), + "manageParticipants": MessageLookupByLibrary.simpleMessage("จัดการ"), + "map": MessageLookupByLibrary.simpleMessage("แผนที่"), + "maps": MessageLookupByLibrary.simpleMessage("แผนที่"), + "moderateStrength": MessageLookupByLibrary.simpleMessage("ปานกลาง"), + "moveItem": m37, + "moveToAlbum": MessageLookupByLibrary.simpleMessage("ย้ายไปยังอัลบั้ม"), + "name": MessageLookupByLibrary.simpleMessage("ชื่อ"), + "newest": MessageLookupByLibrary.simpleMessage("ใหม่สุด"), + "noRecoveryKey": + MessageLookupByLibrary.simpleMessage("ไม่มีคีย์การกู้คืน?"), + "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( + "เนื่องจากลักษณะของโปรโตคอลการเข้ารหัสตั้งแต่ต้นทางถึงปลายทางของเรา ข้อมูลของคุณจึงไม่สามารถถอดรหัสได้หากไม่มีรหัสผ่านหรือคีย์การกู้คืน"), + "ok": MessageLookupByLibrary.simpleMessage("ตกลง"), + "onEnte": MessageLookupByLibrary.simpleMessage( + "บน ente"), + "oops": MessageLookupByLibrary.simpleMessage("อ๊ะ"), + "oopsSomethingWentWrong": + MessageLookupByLibrary.simpleMessage("อ๊ะ มีบางอย่างผิดพลาด"), + "openstreetmapContributors": + MessageLookupByLibrary.simpleMessage("ผู้มีส่วนร่วม OpenStreetMap"), + "orPickAnExistingOne": + MessageLookupByLibrary.simpleMessage("หรือเลือกที่มีอยู่แล้ว"), + "password": MessageLookupByLibrary.simpleMessage("รหัสผ่าน"), + "passwordChangedSuccessfully": + MessageLookupByLibrary.simpleMessage("เปลี่ยนรหัสผ่านสำเร็จ"), + "passwordStrength": m41, + "passwordWarning": MessageLookupByLibrary.simpleMessage( + "เราไม่จัดเก็บรหัสผ่านนี้ ดังนั้นหากคุณลืม เราจะไม่สามารถถอดรหัสข้อมูลของคุณ"), + "peopleUsingYourCode": + MessageLookupByLibrary.simpleMessage("ผู้คนที่ใช้รหัสของคุณ"), + "permanentlyDelete": + MessageLookupByLibrary.simpleMessage("ลบอย่างถาวร"), + "photoSmallCase": MessageLookupByLibrary.simpleMessage("รูปภาพ"), + "pleaseTryAgain": + MessageLookupByLibrary.simpleMessage("กรุณาลองอีกครั้ง"), + "pleaseWait": MessageLookupByLibrary.simpleMessage("กรุณารอสักครู่..."), + "privacyPolicyTitle": + MessageLookupByLibrary.simpleMessage("นโยบายความเป็นส่วนตัว"), + "publicLinkCreated": + MessageLookupByLibrary.simpleMessage("สร้างลิงก์สาธารณะแล้ว"), + "publicLinkEnabled": + MessageLookupByLibrary.simpleMessage("เปิดใช้ลิงก์สาธารณะแล้ว"), + "recover": MessageLookupByLibrary.simpleMessage("กู้คืน"), + "recoverAccount": MessageLookupByLibrary.simpleMessage("กู้คืนบัญชี"), + "recoverButton": MessageLookupByLibrary.simpleMessage("กู้คืน"), + "recoveryKey": MessageLookupByLibrary.simpleMessage("คีย์การกู้คืน"), + "recoveryKeyCopiedToClipboard": MessageLookupByLibrary.simpleMessage( + "คัดลอกคีย์การกู้คืนไปยังคลิปบอร์ดแล้ว"), + "recoveryKeyOnForgotPassword": MessageLookupByLibrary.simpleMessage( + "หากคุณลืมรหัสผ่าน วิธีเดียวที่คุณสามารถกู้คืนข้อมูลของคุณได้คือการใช้คีย์นี้"), + "recoveryKeySaveDescription": MessageLookupByLibrary.simpleMessage( + "เราไม่จัดเก็บคีย์นี้ โปรดบันทึกคีย์ 24 คำนี้ไว้ในที่ที่ปลอดภัย"), + "recoveryKeySuccessBody": MessageLookupByLibrary.simpleMessage( + "ยอดเยี่ยม! คีย์การกู้คืนของคุณถูกต้อง ขอบคุณสำหรับการยืนยัน\n\nโปรดอย่าลืมสำรองคีย์การกู้คืนของคุณไว้อย่างปลอดภัย"), + "recoveryKeyVerified": + MessageLookupByLibrary.simpleMessage("ยืนยันคีย์การกู้คืนแล้ว"), + "recoveryKeyVerifyReason": MessageLookupByLibrary.simpleMessage( + "คีย์การกู้คืนเป็นวิธีเดียวที่จะกู้คืนรูปภาพของคุณหากคุณลืมรหัสผ่าน คุณสามารถหาคีย์การกู้คืนของคุณได้ในการตั้งค่า > ความปลอดภัย\n\nโปรดป้อนคีย์การกู้คืนของคุณที่นี่เพื่อยืนยันว่าคุณได้บันทึกไว้อย่างถูกต้อง"), + "recoverySuccessful": + MessageLookupByLibrary.simpleMessage("กู้คืนสำเร็จ!"), + "recreatePasswordBody": MessageLookupByLibrary.simpleMessage( + "อุปกรณ์ปัจจุบันไม่ทรงพลังพอที่จะยืนยันรหัสผ่านของคุณ แต่เราสามารถสร้างใหม่ในลักษณะที่ใช้ได้กับอุปกรณ์ทั้งหมดได้\n\nกรุณาเข้าสู่ระบบโดยใช้คีย์การกู้คืนของคุณและสร้างรหัสผ่านใหม่ (คุณสามารถใช้รหัสเดิมอีกครั้งได้หากต้องการ)"), + "recreatePasswordTitle": + MessageLookupByLibrary.simpleMessage("สร้างรหัสผ่านใหม่"), + "resendEmail": MessageLookupByLibrary.simpleMessage("ส่งอีเมลอีกครั้ง"), + "resetPasswordTitle": + MessageLookupByLibrary.simpleMessage("รีเซ็ตรหัสผ่าน"), + "restore": MessageLookupByLibrary.simpleMessage(" กู้คืน"), + "restoreToAlbum": + MessageLookupByLibrary.simpleMessage("กู้คืนไปยังอัลบั้ม"), + "save": MessageLookupByLibrary.simpleMessage("บันทึก"), + "saveCopy": MessageLookupByLibrary.simpleMessage("บันทึกสำเนา"), + "saveKey": MessageLookupByLibrary.simpleMessage("บันทึกคีย์"), + "saveYourRecoveryKeyIfYouHaventAlready": + MessageLookupByLibrary.simpleMessage( + "บันทึกคีย์การกู้คืนของคุณหากคุณยังไม่ได้ทำ"), + "scanCode": MessageLookupByLibrary.simpleMessage("สแกนรหัส"), + "selectAll": MessageLookupByLibrary.simpleMessage("เลือกทั้งหมด"), + "selectReason": MessageLookupByLibrary.simpleMessage("เลือกเหตุผล"), + "sendEmail": MessageLookupByLibrary.simpleMessage("ส่งอีเมล"), + "sendLink": MessageLookupByLibrary.simpleMessage("ส่งลิงก์"), + "setPasswordTitle": + MessageLookupByLibrary.simpleMessage("ตั้งรหัสผ่าน"), + "setupComplete": + MessageLookupByLibrary.simpleMessage("ตั้งค่าเสร็จสมบูรณ์"), + "share": MessageLookupByLibrary.simpleMessage("แชร์"), + "shareALink": MessageLookupByLibrary.simpleMessage("แชร์​ลิงก์"), + "shareLink": MessageLookupByLibrary.simpleMessage("แชร์​ลิงก์"), + "signUpTerms": MessageLookupByLibrary.simpleMessage( + "ฉันยอมรับเงื่อนไขการให้บริการและนโยบายความเป็นส่วนตัว"), + "skip": MessageLookupByLibrary.simpleMessage("ข้าม"), + "somethingWentWrongPleaseTryAgain": + MessageLookupByLibrary.simpleMessage( + "มีบางอย่างผิดพลาด โปรดลองอีกครั้ง"), + "sorry": MessageLookupByLibrary.simpleMessage("ขออภัย"), + "status": MessageLookupByLibrary.simpleMessage("สถานะ"), + "storageBreakupFamily": + MessageLookupByLibrary.simpleMessage("ครอบครัว"), + "storageBreakupYou": MessageLookupByLibrary.simpleMessage("คุณ"), + "storageUsageInfo": m60, + "strongStrength": MessageLookupByLibrary.simpleMessage("แข็งแรง"), + "syncStopped": MessageLookupByLibrary.simpleMessage("หยุดการซิงค์แล้ว"), + "syncing": MessageLookupByLibrary.simpleMessage("กำลังซิงค์..."), + "systemTheme": MessageLookupByLibrary.simpleMessage("ระบบ"), + "tapToCopy": MessageLookupByLibrary.simpleMessage("แตะเพื่อคัดลอก"), + "tapToEnterCode": + MessageLookupByLibrary.simpleMessage("แตะเพื่อป้อนรหัส"), + "termsOfServicesTitle": + MessageLookupByLibrary.simpleMessage("เงื่อนไข"), + "theRecoveryKeyYouEnteredIsIncorrect": + MessageLookupByLibrary.simpleMessage( + "คีย์การกู้คืนที่คุณป้อนไม่ถูกต้อง"), + "thisDevice": MessageLookupByLibrary.simpleMessage("อุปกรณ์นี้"), + "toResetVerifyEmail": MessageLookupByLibrary.simpleMessage( + "เพื่อรีเซ็ตรหัสผ่านของคุณ โปรดยืนยันอีเมลของคุณก่อน"), + "total": MessageLookupByLibrary.simpleMessage("รวม"), + "trash": MessageLookupByLibrary.simpleMessage("ถังขยะ"), + "tryAgain": MessageLookupByLibrary.simpleMessage("ลองอีกครั้ง"), + "twofactorSetup": + MessageLookupByLibrary.simpleMessage("การตั้งค่าสองปัจจัย"), + "unarchive": MessageLookupByLibrary.simpleMessage("เลิกเก็บถาวร"), + "uncategorized": MessageLookupByLibrary.simpleMessage("ไม่มีหมวดหมู่"), + "unhide": MessageLookupByLibrary.simpleMessage("เลิกซ่อน"), + "unhideToAlbum": + MessageLookupByLibrary.simpleMessage("เลิกซ่อนไปยังอัลบั้ม"), + "unselectAll": MessageLookupByLibrary.simpleMessage("ไม่เลือกทั้งหมด"), + "useRecoveryKey": + MessageLookupByLibrary.simpleMessage("ใช้คีย์การกู้คืน"), + "verify": MessageLookupByLibrary.simpleMessage("ยืนยัน"), + "verifyEmail": MessageLookupByLibrary.simpleMessage("ยืนยันอีเมล"), + "verifyIDLabel": MessageLookupByLibrary.simpleMessage("ยืนยัน"), + "verifyPassword": + MessageLookupByLibrary.simpleMessage("ยืนยันรหัสผ่าน"), + "verifyingRecoveryKey": + MessageLookupByLibrary.simpleMessage("กำลังยืนยันคีย์การกู้คืน..."), + "videoSmallCase": MessageLookupByLibrary.simpleMessage("วิดีโอ"), + "viewRecoveryKey": + MessageLookupByLibrary.simpleMessage("ดูคีย์การกู้คืน"), + "waitingForWifi": + MessageLookupByLibrary.simpleMessage("กำลังรอ WiFi..."), + "weHaveSendEmailTo": m69, + "weakStrength": MessageLookupByLibrary.simpleMessage("อ่อน"), + "welcomeBack": + MessageLookupByLibrary.simpleMessage("ยินดีต้อนรับกลับมา!"), + "you": MessageLookupByLibrary.simpleMessage("คุณ"), + "youCanManageYourLinksInTheShareTab": + MessageLookupByLibrary.simpleMessage( + "คุณสามารถจัดการลิงก์ของคุณได้ในแท็บแชร์"), + "yourAccountHasBeenDeleted": + MessageLookupByLibrary.simpleMessage("บัญชีของคุณถูกลบแล้ว") + }; +} diff --git a/mobile/lib/generated/intl/messages_ti.dart b/mobile/lib/generated/intl/messages_ti.dart new file mode 100644 index 0000000000..775cc78213 --- /dev/null +++ b/mobile/lib/generated/intl/messages_ti.dart @@ -0,0 +1,25 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a ti locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'ti'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => {}; +} diff --git a/mobile/lib/generated/intl/messages_tr.dart b/mobile/lib/generated/intl/messages_tr.dart index 28813655f0..fd82236d0d 100644 --- a/mobile/lib/generated/intl/messages_tr.dart +++ b/mobile/lib/generated/intl/messages_tr.dart @@ -20,155 +20,138 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'tr'; - static String m0(count) => + static String m3(count) => "${Intl.plural(count, zero: 'Ortak çalışan ekle', one: 'Ortak çalışan ekle', other: 'Ortak çalışan ekle')}"; - static String m2(count) => + static String m4(count) => "${Intl.plural(count, one: 'Öğeyi taşı', other: 'Öğeleri taşı')}"; - static String m3(storageAmount, endDate) => + static String m5(storageAmount, endDate) => "${storageAmount} eklentiniz ${endDate} tarihine kadar geçerlidir"; - static String m1(count) => + static String m6(count) => "${Intl.plural(count, zero: 'Görüntüleyen ekle', one: 'Görüntüleyen ekle', other: 'Görüntüleyen ekle')}"; - static String m4(emailOrName) => "${emailOrName} tarafından eklendi"; + static String m7(emailOrName) => "${emailOrName} tarafından eklendi"; - static String m5(albumName) => "${albumName} albümüne başarıyla eklendi"; + static String m8(albumName) => "${albumName} albümüne başarıyla eklendi"; - static String m6(count) => + static String m9(count) => "${Intl.plural(count, zero: 'Katılımcı Yok', one: '1 Katılımcı', other: '${count} Katılımcı')}"; - static String m7(versionValue) => "Sürüm: ${versionValue}"; + static String m10(versionValue) => "Sürüm: ${versionValue}"; - static String m8(freeAmount, storageUnit) => - "${freeAmount} ${storageUnit} free"; - - static String m9(paymentProvider) => + static String m12(paymentProvider) => "Lütfen önce mevcut aboneliğinizi ${paymentProvider} adresinden iptal edin"; - static String m10(user) => + static String m13(user) => "${user}, bu albüme daha fazla fotoğraf ekleyemeyecek.\n\nAncak, kendi eklediği mevcut fotoğrafları kaldırmaya devam edebilecektir"; - static String m11(isFamilyMember, storageAmountInGb) => + static String m14(isFamilyMember, storageAmountInGb) => "${Intl.select(isFamilyMember, { 'true': 'Şu ana kadar aileniz ${storageAmountInGb} GB aldı', 'false': 'Şu ana kadar ${storageAmountInGb} GB aldınız', 'other': 'Şu ana kadar ${storageAmountInGb} GB aldınız!', })}"; - static String m12(albumName) => + static String m15(albumName) => "${albumName} için ortak çalışma bağlantısı oluşturuldu"; - static String m13(familyAdminEmail) => + static String m16(familyAdminEmail) => "Aboneliğinizi yönetmek için lütfen ${familyAdminEmail} ile iletişime geçin"; - static String m14(provider) => + static String m17(provider) => "Lütfen ${provider} aboneliğinizi yönetmek için support@ente.io adresinden bizimle iletişime geçin."; - static String m15(endpoint) => "${endpoint}\'e bağlanıldı"; + static String m18(endpoint) => "${endpoint}\'e bağlanıldı"; - static String m16(count) => + static String m19(count) => "${Intl.plural(count, one: 'Delete ${count} item', other: 'Delete ${count} items')}"; - static String m17(currentlyDeleting, totalCount) => + static String m20(currentlyDeleting, totalCount) => "Siliniyor ${currentlyDeleting} / ${totalCount}"; - static String m18(albumName) => + static String m21(albumName) => "Bu, \"${albumName}\"e erişim için olan genel bağlantıyı kaldıracaktır."; - static String m19(supportEmail) => + static String m22(supportEmail) => "Lütfen kayıtlı e-posta adresinizden ${supportEmail} adresine bir e-posta gönderin"; - static String m20(count, storageSaved) => + static String m23(count, storageSaved) => "You have cleaned up ${Intl.plural(count, one: '${count} duplicate file', other: '${count} duplicate files')}, saving (${storageSaved}!)"; - static String m21(count, formattedSize) => + static String m24(count, formattedSize) => "${count} dosyalar, ${formattedSize} her biri"; - static String m22(newEmail) => "E-posta ${newEmail} olarak değiştirildi"; + static String m25(newEmail) => "E-posta ${newEmail} olarak değiştirildi"; - static String m23(email) => - "${email} does not have an Ente account.\n\nSend them an invite to share photos."; - - static String m24(count, formattedNumber) => + static String m27(count, formattedNumber) => "Bu cihazdaki ${Intl.plural(count, one: '1 file', other: '${formattedNumber} dosya')} güvenli bir şekilde yedeklendi"; - static String m25(count, formattedNumber) => + static String m28(count, formattedNumber) => "Bu albümdeki ${Intl.plural(count, one: '1 file', other: '${formattedNumber} dosya')} güvenli bir şekilde yedeklendi"; - static String m26(storageAmountInGB) => + static String m29(storageAmountInGB) => "Birisinin davet kodunuzu uygulayıp ücretli hesap açtığı her seferede ${storageAmountInGB} GB"; - static String m27(endDate) => "Ücretsiz deneme ${endDate} sona erir"; + static String m30(endDate) => "Ücretsiz deneme ${endDate} sona erir"; - static String m28(count) => - "You can still access ${Intl.plural(count, one: 'it', other: 'them')} on Ente as long as you have an active subscription"; + static String m32(sizeInMBorGB) => "${sizeInMBorGB} yer açın"; - static String m29(sizeInMBorGB) => "${sizeInMBorGB} yer açın"; - - static String m30(count, formattedSize) => + static String m33(count, formattedSize) => "${Intl.plural(count, one: 'Yer açmak için cihazdan silinebilir ${formattedSize}', other: 'Yer açmak için cihazdan silinebilir ${formattedSize}')}"; - static String m31(currentlyProcessing, totalCount) => + static String m34(currentlyProcessing, totalCount) => "Siliniyor ${currentlyProcessing} / ${totalCount}"; - static String m32(count) => + static String m35(count) => "${Intl.plural(count, one: '${count} öğe', other: '${count} öğeler')}"; - static String m33(expiryTime) => + static String m36(expiryTime) => "Bu bağlantı ${expiryTime} dan sonra geçersiz olacaktır"; - static String m34(count, formattedCount) => + static String m0(count, formattedCount) => "${Intl.plural(count, zero: 'anı yok', one: '${formattedCount} anı', other: '${formattedCount} anılar')}"; - static String m35(count) => + static String m37(count) => "${Intl.plural(count, one: 'Öğeyi taşı', other: 'Öğeleri taşı')}"; - static String m36(albumName) => "${albumName} adlı albüme başarıyla taşındı"; + static String m38(albumName) => "${albumName} adlı albüme başarıyla taşındı"; - static String m37(name) => "Not ${name}?"; - - static String m39(passwordStrengthValue) => + static String m41(passwordStrengthValue) => "Şifrenin güçlülük seviyesi: ${passwordStrengthValue}"; - static String m40(providerName) => + static String m42(providerName) => "Sizden ücret alındıysa lütfen ${providerName} destek ekibiyle görüşün"; - static String m41(endDate) => - "Free trial valid till ${endDate}.\nYou can choose a paid plan afterwards."; + static String m44(toEmail) => "Lütfen bize ${toEmail} adresinden ulaşın"; - static String m42(toEmail) => "Lütfen bize ${toEmail} adresinden ulaşın"; - - static String m43(toEmail) => + static String m45(toEmail) => "Lütfen günlükleri şu adrese gönderin\n${toEmail}"; - static String m44(storeName) => "Bizi ${storeName} üzerinden değerlendirin"; + static String m46(storeName) => "Bizi ${storeName} üzerinden değerlendirin"; - static String m45(storageInGB) => "3. Hepimiz ${storageInGB} GB* bedava alın"; + static String m47(storageInGB) => "3. Hepimiz ${storageInGB} GB* bedava alın"; - static String m46(userEmail) => + static String m48(userEmail) => "${userEmail} bu paylaşılan albümden kaldırılacaktır\n\nOnlar tarafından eklenen tüm fotoğraflar da albümden kaldırılacaktır"; - static String m47(endDate) => "Abonelik ${endDate} tarihinde yenilenir"; + static String m49(endDate) => "Abonelik ${endDate} tarihinde yenilenir"; - static String m48(count) => + static String m50(count) => "${Intl.plural(count, one: '${count} yıl önce', other: '${count} yıl önce')}"; - static String m49(count) => "${count} seçildi"; + static String m1(count) => "${count} seçildi"; - static String m50(count, yourCount) => + static String m51(count, yourCount) => "Seçilenler: ${count} (${yourCount} sizin seçiminiz)"; - static String m51(verificationID) => + static String m52(verificationID) => "İşte ente.io için doğrulama kimliğim: ${verificationID}."; - static String m52(verificationID) => + static String m2(verificationID) => "Merhaba, bu ente.io doğrulama kimliğinizin doğruluğunu onaylayabilir misiniz: ${verificationID}"; - static String m53(referralCode, referralStorageInGB) => - "Ente referral code: ${referralCode} \n\nApply it in Settings → General → Referrals to get ${referralStorageInGB} GB free after you signup for a paid plan\n\nhttps://ente.io"; - static String m54(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Belirli kişilerle paylaş', one: '1 kişiyle paylaşıldı', other: '${numberOfPeople} kişiyle paylaşıldı')}"; @@ -176,20 +159,12 @@ class MessageLookup extends MessageLookupByLibrary { static String m56(fileType) => "Bu ${fileType}, cihazınızdan silinecek."; - static String m57(fileType) => - "This ${fileType} is in both Ente and your device."; - - static String m58(fileType) => "This ${fileType} will be deleted from Ente."; - static String m59(storageAmountInGB) => "${storageAmountInGB} GB"; static String m60( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} / ${totalAmount} ${totalStorageUnit} kullanıldı"; - static String m61(id) => - "Your ${id} is already linked to another Ente account.\nIf you would like to use your ${id} with this account, please contact our support\'\'"; - static String m62(endDate) => "Aboneliğiniz ${endDate} tarihinde iptal edilecektir"; @@ -218,8 +193,6 @@ class MessageLookup extends MessageLookupByLibrary { final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { - "aNewVersionOfEnteIsAvailable": MessageLookupByLibrary.simpleMessage( - "A new version of Ente is available."), "about": MessageLookupByLibrary.simpleMessage("Hakkında"), "account": MessageLookupByLibrary.simpleMessage("Hesap"), "accountWelcomeBack": @@ -228,35 +201,33 @@ class MessageLookup extends MessageLookupByLibrary { "Şifremi kaybedersem, verilerim uçtan uca şifrelendiği için verilerimi kaybedebileceğimi farkındayım."), "activeSessions": MessageLookupByLibrary.simpleMessage("Aktif oturumlar"), - "addAName": MessageLookupByLibrary.simpleMessage("Add a name"), "addANewEmail": MessageLookupByLibrary.simpleMessage("Yeni e-posta ekle"), "addCollaborator": MessageLookupByLibrary.simpleMessage("Düzenleyici ekle"), - "addCollaborators": m0, + "addCollaborators": m3, "addFromDevice": MessageLookupByLibrary.simpleMessage("Cihazdan ekle"), - "addItem": m2, + "addItem": m4, "addLocation": MessageLookupByLibrary.simpleMessage("Konum Ekle"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Ekle"), "addMore": MessageLookupByLibrary.simpleMessage("Daha fazla ekle"), "addNew": MessageLookupByLibrary.simpleMessage("Yeni ekle"), "addOnPageSubtitle": MessageLookupByLibrary.simpleMessage("Eklentilerin ayrıntıları"), - "addOnValidTill": m3, + "addOnValidTill": m5, "addOns": MessageLookupByLibrary.simpleMessage("Eklentiler"), "addPhotos": MessageLookupByLibrary.simpleMessage("Fotoğraf ekle"), "addSelected": MessageLookupByLibrary.simpleMessage("Seçileni ekle"), "addToAlbum": MessageLookupByLibrary.simpleMessage("Albüme ekle"), - "addToEnte": MessageLookupByLibrary.simpleMessage("Add to Ente"), "addToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Gizli albüme ekle"), "addViewer": MessageLookupByLibrary.simpleMessage("Görüntüleyici ekle"), - "addViewers": m1, + "addViewers": m6, "addYourPhotosNow": MessageLookupByLibrary.simpleMessage( "Fotoğraflarınızı şimdi ekleyin"), "addedAs": MessageLookupByLibrary.simpleMessage("Eklendi"), - "addedBy": m4, - "addedSuccessfullyTo": m5, + "addedBy": m7, + "addedSuccessfullyTo": m8, "addingToFavorites": MessageLookupByLibrary.simpleMessage("Favorilere ekleniyor..."), "advanced": MessageLookupByLibrary.simpleMessage("Gelişmiş"), @@ -267,7 +238,7 @@ class MessageLookup extends MessageLookupByLibrary { "after1Week": MessageLookupByLibrary.simpleMessage("1 hafta sonra"), "after1Year": MessageLookupByLibrary.simpleMessage("1 yıl sonra"), "albumOwner": MessageLookupByLibrary.simpleMessage("Sahip"), - "albumParticipantsCount": m6, + "albumParticipantsCount": m9, "albumTitle": MessageLookupByLibrary.simpleMessage("Albüm Başlığı"), "albumUpdated": MessageLookupByLibrary.simpleMessage("Albüm güncellendi"), @@ -304,10 +275,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Android, iOS, Web, Masaüstü"), "androidSignInTitle": MessageLookupByLibrary.simpleMessage("Kimlik doğrulaması gerekli"), - "appLock": MessageLookupByLibrary.simpleMessage("App lock"), - "appLockDescriptions": MessageLookupByLibrary.simpleMessage( - "Choose between your device\'s default lock screen and a custom lock screen with a PIN or password."), - "appVersion": m7, + "appVersion": m10, "appleId": MessageLookupByLibrary.simpleMessage("Apple kimliği"), "apply": MessageLookupByLibrary.simpleMessage("Uygula"), "applyCodeTitle": MessageLookupByLibrary.simpleMessage("Kodu girin"), @@ -352,8 +320,6 @@ class MessageLookup extends MessageLookupByLibrary { "İki faktörlü kimlik doğrulamayı yapılandırmak için lütfen kimlik doğrulaması yapın"), "authToInitiateAccountDeletion": MessageLookupByLibrary.simpleMessage( "Hesap silme işlemini başlatmak için lütfen kimlik doğrulaması yapın"), - "authToViewPasskey": MessageLookupByLibrary.simpleMessage( - "Please authenticate to view your passkey"), "authToViewYourActiveSessions": MessageLookupByLibrary.simpleMessage( "Aktif oturumlarınızı görüntülemek için lütfen kimliğinizi doğrulayın"), "authToViewYourHiddenFiles": MessageLookupByLibrary.simpleMessage( @@ -369,20 +335,7 @@ class MessageLookup extends MessageLookupByLibrary { "Kimlik doğrulama başarısız oldu, lütfen tekrar deneyin"), "authenticationSuccessful": MessageLookupByLibrary.simpleMessage("Kimlik doğrulama başarılı!"), - "autoCastDialogBody": MessageLookupByLibrary.simpleMessage( - "You\'ll see available Cast devices here."), - "autoCastiOSPermission": MessageLookupByLibrary.simpleMessage( - "Make sure Local Network permissions are turned on for the Ente Photos app, in Settings."), - "autoLock": MessageLookupByLibrary.simpleMessage("Auto lock"), - "autoLockFeatureDescription": MessageLookupByLibrary.simpleMessage( - "Time after which the app locks after being put in the background"), - "autoLogoutMessage": MessageLookupByLibrary.simpleMessage( - "Due to technical glitch, you have been logged out. Our apologies for the inconvenience."), - "autoPair": MessageLookupByLibrary.simpleMessage("Auto pair"), - "autoPairDesc": MessageLookupByLibrary.simpleMessage( - "Auto pair works only with devices that support Chromecast."), "available": MessageLookupByLibrary.simpleMessage("Mevcut"), - "availableStorageSpace": m8, "backedUpFolders": MessageLookupByLibrary.simpleMessage("Yedeklenmiş klasörler"), "backup": MessageLookupByLibrary.simpleMessage("Yedekle"), @@ -409,16 +362,12 @@ class MessageLookup extends MessageLookupByLibrary { "canOnlyRemoveFilesOwnedByYou": MessageLookupByLibrary.simpleMessage( "Yalnızca size ait dosyaları kaldırabilir"), "cancel": MessageLookupByLibrary.simpleMessage("İptal Et"), - "cancelOtherSubscription": m9, + "cancelOtherSubscription": m12, "cancelSubscription": MessageLookupByLibrary.simpleMessage("Abonelik iptali"), - "cannotAddMorePhotosAfterBecomingViewer": m10, + "cannotAddMorePhotosAfterBecomingViewer": m13, "cannotDeleteSharedFiles": MessageLookupByLibrary.simpleMessage("Dosyalar silinemiyor"), - "castIPMismatchBody": MessageLookupByLibrary.simpleMessage( - "Please make sure you are on the same network as the TV."), - "castIPMismatchTitle": - MessageLookupByLibrary.simpleMessage("Failed to cast album"), "castInstruction": MessageLookupByLibrary.simpleMessage( "Eşleştirmek istediğiniz cihazda cast.ente.io adresini ziyaret edin.\n\nAlbümü TV\'nizde oynatmak için aşağıdaki kodu girin."), "centerPoint": MessageLookupByLibrary.simpleMessage("Merkez noktası"), @@ -436,27 +385,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Güncellemeleri kontol et"), "checkInboxAndSpamFolder": MessageLookupByLibrary.simpleMessage( "Lütfen doğrulama işlemini tamamlamak için gelen kutunuzu (ve spam klasörünüzü) kontrol edin"), - "checkStatus": MessageLookupByLibrary.simpleMessage("Check status"), "checking": MessageLookupByLibrary.simpleMessage("Kontrol ediliyor..."), - "cl_guest_view_call_to_action": MessageLookupByLibrary.simpleMessage( - "Fotoğrafları seçin ve \"Misafir Görünümü\"nü deneyin."), - "cl_guest_view_description": MessageLookupByLibrary.simpleMessage( - "Telefonunuzu bir arkadaşınıza fotoğraf göstermek için mi veriyorsunuz? Fazla kaydırmasından endişelenmeyin. Misafir görünümü seçtiğiniz fotoğraflarla sınırlı kalır."), - "cl_guest_view_title": - MessageLookupByLibrary.simpleMessage("Misafir Görünümü"), - "cl_panorama_viewer_description": MessageLookupByLibrary.simpleMessage( - "360 derece görüşe sahip panorama fotoğrafları görüntüleme desteği ekledik. Hareket tabanlı gezinme ile etkileyici bir deneyim sunar!"), - "cl_panorama_viewer_title": - MessageLookupByLibrary.simpleMessage("Panorama Görüntüleyici"), - "cl_video_player_description": MessageLookupByLibrary.simpleMessage( - "Geliştirilmiş oynatma kontrolleri ve HDR video desteği ile yeni bir video oynatıcı sunuyoruz."), - "cl_video_player_title": - MessageLookupByLibrary.simpleMessage("Video Oynatıcı"), "claimFreeStorage": MessageLookupByLibrary.simpleMessage("Bedava alan talep edin"), "claimMore": MessageLookupByLibrary.simpleMessage("Arttır!"), "claimed": MessageLookupByLibrary.simpleMessage("Alındı"), - "claimedStorageSoFar": m11, + "claimedStorageSoFar": m14, "cleanUncategorized": MessageLookupByLibrary.simpleMessage("Temiz Genel"), "cleanUncategorizedDescription": MessageLookupByLibrary.simpleMessage( @@ -472,19 +406,15 @@ class MessageLookup extends MessageLookupByLibrary { "Yakalama zamanına göre kulüp"), "clubByFileName": MessageLookupByLibrary.simpleMessage("Dosya adına göre kulüp"), - "clusteringProgress": - MessageLookupByLibrary.simpleMessage("Clustering progress"), "codeAppliedPageTitle": MessageLookupByLibrary.simpleMessage("Kod kabul edildi"), "codeCopiedToClipboard": MessageLookupByLibrary.simpleMessage("Kodunuz panoya kopyalandı"), "codeUsedByYou": MessageLookupByLibrary.simpleMessage("Sizin kullandığınız kod"), - "collabLinkSectionDescription": MessageLookupByLibrary.simpleMessage( - "Create a link to allow people to add and view photos in your shared album without needing an Ente app or account. Great for collecting event photos."), "collaborativeLink": MessageLookupByLibrary.simpleMessage("Organizasyon bağlantısı"), - "collaborativeLinkCreatedFor": m12, + "collaborativeLinkCreatedFor": m15, "collaborator": MessageLookupByLibrary.simpleMessage("Düzenleyici"), "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": MessageLookupByLibrary.simpleMessage( @@ -512,12 +442,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Kurtarma anahtarını doğrula"), "confirmYourRecoveryKey": MessageLookupByLibrary.simpleMessage( "Kurtarma anahtarını doğrulayın"), - "connectToDevice": - MessageLookupByLibrary.simpleMessage("Connect to device"), - "contactFamilyAdmin": m13, + "contactFamilyAdmin": m16, "contactSupport": MessageLookupByLibrary.simpleMessage("Destek ile iletişim"), - "contactToManageSubscription": m14, + "contactToManageSubscription": m17, "contacts": MessageLookupByLibrary.simpleMessage("Kişiler"), "contents": MessageLookupByLibrary.simpleMessage("İçerikler"), "continueLabel": MessageLookupByLibrary.simpleMessage("Devam edin"), @@ -544,8 +472,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Hesap oluşturun"), "createAlbumActionHint": MessageLookupByLibrary.simpleMessage( "Fotoğrafları seçmek için uzun basın ve + düğmesine tıklayarak bir albüm oluşturun"), - "createCollaborativeLink": - MessageLookupByLibrary.simpleMessage("Create collaborative link"), "createCollage": MessageLookupByLibrary.simpleMessage("Kolaj oluştur"), "createNewAccount": MessageLookupByLibrary.simpleMessage("Yeni bir hesap oluşturun"), @@ -557,11 +483,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Bağlantı oluşturuluyor..."), "criticalUpdateAvailable": MessageLookupByLibrary.simpleMessage("Kritik güncelleme mevcut"), - "crop": MessageLookupByLibrary.simpleMessage("Crop"), "currentUsageIs": MessageLookupByLibrary.simpleMessage("Güncel kullanımınız "), "custom": MessageLookupByLibrary.simpleMessage("Kişisel"), - "customEndpoint": m15, + "customEndpoint": m18, "darkTheme": MessageLookupByLibrary.simpleMessage("Karanlık"), "dayToday": MessageLookupByLibrary.simpleMessage("Bugün"), "dayYesterday": MessageLookupByLibrary.simpleMessage("Dün"), @@ -583,8 +508,6 @@ class MessageLookup extends MessageLookupByLibrary { "deleteAlbumsDialogBody": MessageLookupByLibrary.simpleMessage( "Bu, tüm boş albümleri silecektir. Bu, albüm listenizdeki dağınıklığı azaltmak istediğinizde kullanışlıdır."), "deleteAll": MessageLookupByLibrary.simpleMessage("Hepsini Sil"), - "deleteConfirmDialogBody": MessageLookupByLibrary.simpleMessage( - "This account is linked to other Ente apps, if you use any. Your uploaded data, across all Ente apps, will be scheduled for deletion, and your account will be permanently deleted."), "deleteEmailRequest": MessageLookupByLibrary.simpleMessage( "Lütfen kayıtlı e-posta adresinizden account-deletion@ente.io\'a e-posta gönderiniz."), "deleteEmptyAlbums": @@ -595,13 +518,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Her ikisinden de sil"), "deleteFromDevice": MessageLookupByLibrary.simpleMessage("Cihazınızdan silin"), - "deleteFromEnte": - MessageLookupByLibrary.simpleMessage("Delete from Ente"), - "deleteItemCount": m16, + "deleteItemCount": m19, "deleteLocation": MessageLookupByLibrary.simpleMessage("Konumu sil"), "deletePhotos": MessageLookupByLibrary.simpleMessage("Fotoğrafları sil"), - "deleteProgress": m17, + "deleteProgress": m20, "deleteReason1": MessageLookupByLibrary.simpleMessage( "İhtiyacım olan önemli bir özellik eksik"), "deleteReason2": MessageLookupByLibrary.simpleMessage( @@ -627,11 +548,6 @@ class MessageLookup extends MessageLookupByLibrary { "developerSettingsWarning": MessageLookupByLibrary.simpleMessage( "Geliştirici ayarlarını değiştirmek istediğinizden emin misiniz?"), "deviceCodeHint": MessageLookupByLibrary.simpleMessage("Kodu girin"), - "deviceFilesAutoUploading": MessageLookupByLibrary.simpleMessage( - "Files added to this device album will automatically get uploaded to Ente."), - "deviceLock": MessageLookupByLibrary.simpleMessage("Device lock"), - "deviceLockExplanation": MessageLookupByLibrary.simpleMessage( - "Disable the device screen lock when Ente is in the foreground and there is a backup in progress. This is normally not needed, but may help big uploads and initial imports of large libraries complete faster."), "deviceNotFound": MessageLookupByLibrary.simpleMessage("Cihaz bulunamadı"), "didYouKnow": MessageLookupByLibrary.simpleMessage("Biliyor musun?"), @@ -641,7 +557,7 @@ class MessageLookup extends MessageLookupByLibrary { "Görüntüleyiciler, hala harici araçlar kullanarak ekran görüntüsü alabilir veya fotoğraflarınızın bir kopyasını kaydedebilir. Lütfen bunu göz önünde bulundurunuz"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("Lütfen dikkate alın"), - "disableLinkMessage": m18, + "disableLinkMessage": m21, "disableTwofactor": MessageLookupByLibrary.simpleMessage( "İki Aşamalı Doğrulamayı Devre Dışı Bırak"), "disablingTwofactorAuthentication": @@ -662,9 +578,9 @@ class MessageLookup extends MessageLookupByLibrary { "downloadFailed": MessageLookupByLibrary.simpleMessage("İndirme başarısız"), "downloading": MessageLookupByLibrary.simpleMessage("İndiriliyor..."), - "dropSupportEmail": m19, - "duplicateFileCountWithStorageSaved": m20, - "duplicateItemsGroup": m21, + "dropSupportEmail": m22, + "duplicateFileCountWithStorageSaved": m23, + "duplicateItemsGroup": m24, "edit": MessageLookupByLibrary.simpleMessage("Düzenle"), "editLocation": MessageLookupByLibrary.simpleMessage("Konumu düzenle"), "editLocationTagTitle": @@ -676,8 +592,7 @@ class MessageLookup extends MessageLookupByLibrary { "Konumda yapılan düzenlemeler yalnızca Ente\'de görülecektir"), "eligible": MessageLookupByLibrary.simpleMessage("uygun"), "email": MessageLookupByLibrary.simpleMessage("E-Posta"), - "emailChangedTo": m22, - "emailNoEnteAccount": m23, + "emailChangedTo": m25, "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("E-posta doğrulama"), "emailYourLogs": MessageLookupByLibrary.simpleMessage( @@ -698,13 +613,6 @@ class MessageLookup extends MessageLookupByLibrary { "Fatura başarıyla güncellendi"), "endtoendEncryptedByDefault": MessageLookupByLibrary.simpleMessage( "Varsayılan olarak uçtan uca şifrelenmiş"), - "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": - MessageLookupByLibrary.simpleMessage( - "Ente can encrypt and preserve files only if you grant access to them"), - "entePhotosPerm": MessageLookupByLibrary.simpleMessage( - "Ente needs permission to preserve your photos"), - "enteSubscriptionPitch": MessageLookupByLibrary.simpleMessage( - "Ente preserves your memories, so they\'re always available to you, even if you lose your device."), "enteSubscriptionShareWithFamily": MessageLookupByLibrary.simpleMessage( "Aileniz de planınıza eklenebilir."), "enterAlbumName": @@ -722,9 +630,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Şifrenizi girin"), "enterPasswordToEncrypt": MessageLookupByLibrary.simpleMessage( "Verilerinizi şifrelemek için kullanabileceğimiz bir şifre girin"), - "enterPersonName": - MessageLookupByLibrary.simpleMessage("Enter person name"), - "enterPin": MessageLookupByLibrary.simpleMessage("Enter PIN"), "enterReferralCode": MessageLookupByLibrary.simpleMessage("Davet kodunuzu girin"), "enterThe6digitCodeFromnyourAuthenticatorApp": @@ -749,8 +654,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Günlüğü dışa aktar"), "exportYourData": MessageLookupByLibrary.simpleMessage("Veriyi dışarı aktar"), - "faceRecognition": - MessageLookupByLibrary.simpleMessage("Face recognition"), "faces": MessageLookupByLibrary.simpleMessage("Yüzler"), "failedToApplyCode": MessageLookupByLibrary.simpleMessage("Uygulanırken hata oluştu"), @@ -768,8 +671,6 @@ class MessageLookup extends MessageLookupByLibrary { "Abonelik yenilenirken hata oluştu"), "failedToVerifyPaymentStatus": MessageLookupByLibrary.simpleMessage("Ödeme durumu doğrulanamadı"), - "familyPlanOverview": MessageLookupByLibrary.simpleMessage( - "Add 5 family members to your existing plan without paying extra.\n\nEach member gets their own private space, and cannot see each other\'s files unless they\'re shared.\n\nFamily plans are available to customers who have a paid Ente subscription.\n\nSubscribe now to get started!"), "familyPlanPortalTitle": MessageLookupByLibrary.simpleMessage("Aile"), "familyPlans": MessageLookupByLibrary.simpleMessage("Aile Planı"), "faq": MessageLookupByLibrary.simpleMessage("Sıkça sorulan sorular"), @@ -785,41 +686,33 @@ class MessageLookup extends MessageLookupByLibrary { "fileTypes": MessageLookupByLibrary.simpleMessage("Dosya türü"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("Dosya türleri ve adları"), - "filesBackedUpFromDevice": m24, - "filesBackedUpInAlbum": m25, + "filesBackedUpFromDevice": m27, + "filesBackedUpInAlbum": m28, "filesDeleted": MessageLookupByLibrary.simpleMessage("Dosyalar silinmiş"), - "filesSavedToGallery": - MessageLookupByLibrary.simpleMessage("Files saved to gallery"), - "findPeopleByName": - MessageLookupByLibrary.simpleMessage("Find people quickly by name"), "flip": MessageLookupByLibrary.simpleMessage("Çevir"), "forYourMemories": MessageLookupByLibrary.simpleMessage("anıların için"), "forgotPassword": MessageLookupByLibrary.simpleMessage("Şifremi unuttum"), - "foundFaces": MessageLookupByLibrary.simpleMessage("Found faces"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("Alınan bedava alan"), - "freeStorageOnReferralSuccess": m26, + "freeStorageOnReferralSuccess": m29, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("Kullanılabilir bedava alan"), "freeTrial": MessageLookupByLibrary.simpleMessage("Ücretsiz deneme"), - "freeTrialValidTill": m27, - "freeUpAccessPostDelete": m28, - "freeUpAmount": m29, + "freeTrialValidTill": m30, + "freeUpAmount": m32, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("Cihaz alanını boşaltın"), - "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( - "Save space on your device by clearing files that have been already backed up."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Boş alan"), - "freeUpSpaceSaving": m30, + "freeUpSpaceSaving": m33, "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( "Galeride 1000\'e kadar anı gösterilir"), "general": MessageLookupByLibrary.simpleMessage("Genel"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Şifreleme anahtarı oluşturuluyor..."), - "genericProgress": m31, + "genericProgress": m34, "goToSettings": MessageLookupByLibrary.simpleMessage("Ayarlara git"), "googlePlayId": MessageLookupByLibrary.simpleMessage("Google play kimliği"), @@ -829,9 +722,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("İzinleri değiştir"), "groupNearbyPhotos": MessageLookupByLibrary.simpleMessage( "Yakındaki fotoğrafları gruplandır"), - "guestView": MessageLookupByLibrary.simpleMessage("Guest view"), - "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( - "To enable guest view, please setup device passcode or screen lock in your system settings."), "hearUsExplanation": MessageLookupByLibrary.simpleMessage( "Biz uygulama kurulumlarını takip etmiyoruz. Bizi nereden duyduğunuzdan bahsetmeniz bize çok yardımcı olacak!"), "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( @@ -839,11 +729,6 @@ class MessageLookup extends MessageLookupByLibrary { "help": MessageLookupByLibrary.simpleMessage("Yardım"), "hidden": MessageLookupByLibrary.simpleMessage("Gizle"), "hide": MessageLookupByLibrary.simpleMessage("Gizle"), - "hideContent": MessageLookupByLibrary.simpleMessage("Hide content"), - "hideContentDescriptionAndroid": MessageLookupByLibrary.simpleMessage( - "Hides app content in the app switcher and disables screenshots"), - "hideContentDescriptionIos": MessageLookupByLibrary.simpleMessage( - "Hides app content in the app switcher"), "hiding": MessageLookupByLibrary.simpleMessage("Gizleniyor..."), "hostedAtOsmFrance": MessageLookupByLibrary.simpleMessage("OSM Fransa\'da ağırlandı"), @@ -856,9 +741,6 @@ class MessageLookup extends MessageLookupByLibrary { "Biyometrik kimlik doğrulama devre dışı. Etkinleştirmek için lütfen ekranınızı kilitleyin ve kilidini açın."), "iOSOkButton": MessageLookupByLibrary.simpleMessage("Tamam"), "ignoreUpdate": MessageLookupByLibrary.simpleMessage("Yoksay"), - "ignoredFolderUploadReason": MessageLookupByLibrary.simpleMessage( - "Some files in this album are ignored from upload because they had previously been deleted from Ente."), - "immediately": MessageLookupByLibrary.simpleMessage("Immediately"), "importing": MessageLookupByLibrary.simpleMessage("İçeri aktarılıyor...."), "incorrectCode": MessageLookupByLibrary.simpleMessage("Yanlış kod"), @@ -872,8 +754,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Yanlış kurtarma kodu"), "indexedItems": MessageLookupByLibrary.simpleMessage("Yeni öğeleri indeksle"), - "indexingIsPaused": MessageLookupByLibrary.simpleMessage( - "Indexing is paused. It will automatically resume when device is ready."), "insecureDevice": MessageLookupByLibrary.simpleMessage("Güvenilir olmayan cihaz"), "installManually": @@ -888,15 +768,12 @@ class MessageLookup extends MessageLookupByLibrary { "invalidRecoveryKey": MessageLookupByLibrary.simpleMessage( "Girdiğiniz kurtarma anahtarı geçerli değil. Lütfen anahtarın 24 kelime içerdiğinden ve her bir kelimenin doğru şekilde yazıldığından emin olun.\n\nEğer eski bir kurtarma kodu girdiyseniz, o zaman kodun 64 karakter uzunluğunda olduğunu kontrol edin."), "invite": MessageLookupByLibrary.simpleMessage("Davet et"), - "inviteToEnte": MessageLookupByLibrary.simpleMessage("Invite to Ente"), "inviteYourFriends": MessageLookupByLibrary.simpleMessage("Arkadaşlarını davet et"), - "inviteYourFriendsToEnte": - MessageLookupByLibrary.simpleMessage("Invite your friends to Ente"), "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Bir şeyler ters gitmiş gibi görünüyor. Lütfen bir süre sonra tekrar deneyin. Hata devam ederse, lütfen destek ekibimizle iletişime geçin."), - "itemCount": m32, + "itemCount": m35, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage( "Öğeler, kalıcı olarak silinmeden önce kalan gün sayısını gösterir"), @@ -918,7 +795,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Aile planından ayrıl"), "leaveSharedAlbum": MessageLookupByLibrary.simpleMessage( "Paylaşılan albüm silinsin mi?"), - "left": MessageLookupByLibrary.simpleMessage("Left"), "light": MessageLookupByLibrary.simpleMessage("Aydınlık"), "lightTheme": MessageLookupByLibrary.simpleMessage("Aydınlık"), "linkCopiedToClipboard": @@ -926,7 +802,7 @@ class MessageLookup extends MessageLookupByLibrary { "linkDeviceLimit": MessageLookupByLibrary.simpleMessage("Cihaz limiti"), "linkEnabled": MessageLookupByLibrary.simpleMessage("Geçerli"), "linkExpired": MessageLookupByLibrary.simpleMessage("Süresi dolmuş"), - "linkExpiresOn": m33, + "linkExpiresOn": m36, "linkExpiry": MessageLookupByLibrary.simpleMessage("Linkin geçerliliği"), "linkHasExpired": @@ -970,10 +846,6 @@ class MessageLookup extends MessageLookupByLibrary { "logInLabel": MessageLookupByLibrary.simpleMessage("Giriş yap"), "loggingOut": MessageLookupByLibrary.simpleMessage("Çıkış yapılıyor..."), - "loginSessionExpired": - MessageLookupByLibrary.simpleMessage("Session expired"), - "loginSessionExpiredDetails": MessageLookupByLibrary.simpleMessage( - "Your session has expired. Please login again."), "loginTerms": MessageLookupByLibrary.simpleMessage( "\"Giriş yap\" düğmesine tıklayarak, Hizmet Şartları\'nı ve Gizlilik Politikası\'nı kabul ediyorum"), "logout": MessageLookupByLibrary.simpleMessage("Çıkış yap"), @@ -998,16 +870,12 @@ class MessageLookup extends MessageLookupByLibrary { "manageParticipants": MessageLookupByLibrary.simpleMessage("Yönet"), "manageSubscription": MessageLookupByLibrary.simpleMessage("Abonelikleri yönet"), - "manualPairDesc": MessageLookupByLibrary.simpleMessage( - "Pair with PIN works with any screen you wish to view your album on."), "map": MessageLookupByLibrary.simpleMessage("Harita"), "maps": MessageLookupByLibrary.simpleMessage("Haritalar"), "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), - "memoryCount": m34, + "memoryCount": m0, "merchandise": MessageLookupByLibrary.simpleMessage("Ürünler"), - "mlIndexingDescription": MessageLookupByLibrary.simpleMessage( - "Please note that machine learning will result in a higher bandwidth and battery usage until all items are indexed."), "mobileWebDesktop": MessageLookupByLibrary.simpleMessage("Mobil, Web, Masaüstü"), "moderateStrength": MessageLookupByLibrary.simpleMessage("Ilımlı"), @@ -1016,11 +884,11 @@ class MessageLookup extends MessageLookupByLibrary { "Sorgunuzu değiştirin veya aramayı deneyin"), "moments": MessageLookupByLibrary.simpleMessage("Anlar"), "monthly": MessageLookupByLibrary.simpleMessage("Aylık"), - "moveItem": m35, + "moveItem": m37, "moveToAlbum": MessageLookupByLibrary.simpleMessage("Albüme taşı"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Gizli albüme ekle"), - "movedSuccessfullyTo": m36, + "movedSuccessfullyTo": m38, "movedToTrash": MessageLookupByLibrary.simpleMessage("Cöp kutusuna taşı"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage( @@ -1032,14 +900,10 @@ class MessageLookup extends MessageLookupByLibrary { "Ente\'ye bağlanılamıyor. Lütfen ağ ayarlarınızı kontrol edin ve hata devam ederse destek ekibiyle iletişime geçin."), "never": MessageLookupByLibrary.simpleMessage("Asla"), "newAlbum": MessageLookupByLibrary.simpleMessage("Yeni albüm"), - "newToEnte": MessageLookupByLibrary.simpleMessage("New to Ente"), "newest": MessageLookupByLibrary.simpleMessage("En yeni"), - "next": MessageLookupByLibrary.simpleMessage("Next"), "no": MessageLookupByLibrary.simpleMessage("Hayır"), "noAlbumsSharedByYouYet": MessageLookupByLibrary.simpleMessage( "Henüz paylaştığınız albüm yok"), - "noDeviceFound": - MessageLookupByLibrary.simpleMessage("No device found"), "noDeviceLimit": MessageLookupByLibrary.simpleMessage("Yok"), "noDeviceThatCanBeDeleted": MessageLookupByLibrary.simpleMessage( "Bu cihazda silinebilecek hiçbir dosyanız yok"), @@ -1057,8 +921,6 @@ class MessageLookup extends MessageLookupByLibrary { "Şu anda hiçbir fotoğraf yedeklenmiyor"), "noPhotosFoundHere": MessageLookupByLibrary.simpleMessage("Burada fotoğraf bulunamadı"), - "noQuickLinksSelected": - MessageLookupByLibrary.simpleMessage("No quick links selected"), "noRecoveryKey": MessageLookupByLibrary.simpleMessage("Kurtarma kodunuz yok mu?"), "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( @@ -1066,9 +928,6 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Sonuç bulunamadı"), "noResultsFound": MessageLookupByLibrary.simpleMessage("Hiçbir sonuç bulunamadı"), - "noSystemLockFound": - MessageLookupByLibrary.simpleMessage("No system lock found"), - "notPersonLabel": m37, "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( "Henüz sizinle paylaşılan bir şey yok"), "nothingToSeeHere": MessageLookupByLibrary.simpleMessage( @@ -1092,11 +951,6 @@ class MessageLookup extends MessageLookupByLibrary { "orPickAnExistingOne": MessageLookupByLibrary.simpleMessage("Veya mevcut birini seçiniz"), "pair": MessageLookupByLibrary.simpleMessage("Eşleştir"), - "pairWithPin": MessageLookupByLibrary.simpleMessage("Pair with PIN"), - "pairingComplete": - MessageLookupByLibrary.simpleMessage("Pairing complete"), - "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage( - "Verification is still pending"), "passkey": MessageLookupByLibrary.simpleMessage("Parola Anahtarı"), "passkeyAuthTitle": MessageLookupByLibrary.simpleMessage("Geçiş anahtarı doğrulaması"), @@ -1104,9 +958,7 @@ class MessageLookup extends MessageLookupByLibrary { "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage( "Şifreniz başarılı bir şekilde değiştirildi"), "passwordLock": MessageLookupByLibrary.simpleMessage("Sifre kilidi"), - "passwordStrength": m39, - "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( - "Password strength is calculated considering the length of the password, used characters, and whether or not the password appears in the top 10,000 most used passwords"), + "passwordStrength": m41, "passwordWarning": MessageLookupByLibrary.simpleMessage( "Şifrelerinizi saklamıyoruz, bu yüzden unutursanız, verilerinizi deşifre edemeyiz"), "paymentDetails": @@ -1115,11 +967,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ödeme başarısız oldu"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Maalesef ödemeniz başarısız oldu. Lütfen destekle iletişime geçin, size yardımcı olacağız!"), - "paymentFailedTalkToProvider": m40, + "paymentFailedTalkToProvider": m42, "pendingItems": MessageLookupByLibrary.simpleMessage("Bekleyen Öğeler"), "pendingSync": MessageLookupByLibrary.simpleMessage("Senkronizasyon bekleniyor"), - "people": MessageLookupByLibrary.simpleMessage("People"), "peopleUsingYourCode": MessageLookupByLibrary.simpleMessage("Kodunuzu kullananlar"), "permDeleteWarning": MessageLookupByLibrary.simpleMessage( @@ -1140,9 +991,7 @@ class MessageLookup extends MessageLookupByLibrary { "pickCenterPoint": MessageLookupByLibrary.simpleMessage("Merkez noktasını seçin"), "pinAlbum": MessageLookupByLibrary.simpleMessage("Albümü sabitle"), - "pinLock": MessageLookupByLibrary.simpleMessage("PIN lock"), "playOnTv": MessageLookupByLibrary.simpleMessage("Albümü TV\'de oynat"), - "playStoreFreeTrialValidTill": m41, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("PlayStore aboneliği"), "pleaseCheckYourInternetConnectionAndTryAgain": @@ -1154,14 +1003,12 @@ class MessageLookup extends MessageLookupByLibrary { "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage( "Bu hata devam ederse lütfen desteğe başvurun"), - "pleaseEmailUsAt": m42, + "pleaseEmailUsAt": m44, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage("Lütfen izin ver"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("Lütfen tekrar giriş yapın"), - "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage( - "Please select quick links to remove"), - "pleaseSendTheLogsTo": m43, + "pleaseSendTheLogsTo": m45, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("Lütfen tekrar deneyiniz"), "pleaseVerifyTheCodeYouHaveEntered": @@ -1198,7 +1045,7 @@ class MessageLookup extends MessageLookupByLibrary { "rateTheApp": MessageLookupByLibrary.simpleMessage("Uygulamaya puan verin"), "rateUs": MessageLookupByLibrary.simpleMessage("Bizi değerlendirin"), - "rateUsOnStore": m44, + "rateUsOnStore": m46, "recover": MessageLookupByLibrary.simpleMessage("Kurtarma"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Hesabı kurtar"), "recoverButton": MessageLookupByLibrary.simpleMessage("Kurtar"), @@ -1223,16 +1070,13 @@ class MessageLookup extends MessageLookupByLibrary { "recreatePasswordTitle": MessageLookupByLibrary.simpleMessage( "Sifrenizi tekrardan oluşturun"), "reddit": MessageLookupByLibrary.simpleMessage("Reddit"), - "reenterPassword": - MessageLookupByLibrary.simpleMessage("Re-enter password"), - "reenterPin": MessageLookupByLibrary.simpleMessage("Re-enter PIN"), "referFriendsAnd2xYourPlan": MessageLookupByLibrary.simpleMessage( "Arkadaşlarınıza önerin ve planınızı 2 katına çıkarın"), "referralStep1": MessageLookupByLibrary.simpleMessage( "1. Bu kodu arkadaşlarınıza verin"), "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Ücretli bir plan için kaydolsunlar"), - "referralStep3": m45, + "referralStep3": m47, "referrals": MessageLookupByLibrary.simpleMessage("Referanslar"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage( "Davetler şu anda durmuş durumda"), @@ -1248,24 +1092,16 @@ class MessageLookup extends MessageLookupByLibrary { "remove": MessageLookupByLibrary.simpleMessage("Kaldır"), "removeDuplicates": MessageLookupByLibrary.simpleMessage("Yinelenenleri kaldır"), - "removeDuplicatesDesc": MessageLookupByLibrary.simpleMessage( - "Review and remove files that are exact duplicates."), "removeFromAlbum": MessageLookupByLibrary.simpleMessage("Albümden çıkar"), "removeFromAlbumTitle": MessageLookupByLibrary.simpleMessage("Albümden çıkarılsın mı?"), - "removeFromFavorite": - MessageLookupByLibrary.simpleMessage("Favorilerimden kaldır"), "removeLink": MessageLookupByLibrary.simpleMessage("Linki kaldır"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Katılımcıyı kaldır"), - "removeParticipantBody": m46, - "removePersonLabel": - MessageLookupByLibrary.simpleMessage("Remove person label"), + "removeParticipantBody": m48, "removePublicLink": MessageLookupByLibrary.simpleMessage("Herkese açık link oluştur"), - "removePublicLinks": - MessageLookupByLibrary.simpleMessage("Remove public links"), "removeShareItemsWarning": MessageLookupByLibrary.simpleMessage( "Kaldırdığınız öğelerden bazıları başkaları tarafından eklenmiştir ve bunlara erişiminizi kaybedeceksiniz"), "removeWithQuestionMark": @@ -1279,7 +1115,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Dosyayı yeniden adlandır"), "renewSubscription": MessageLookupByLibrary.simpleMessage("Abonelik yenileme"), - "renewsOn": m47, + "renewsOn": m49, "reportABug": MessageLookupByLibrary.simpleMessage("Hatayı bildir"), "reportBug": MessageLookupByLibrary.simpleMessage("Hata bildir"), "resendEmail": @@ -1297,10 +1133,6 @@ class MessageLookup extends MessageLookupByLibrary { "retry": MessageLookupByLibrary.simpleMessage("Tekrar dene"), "reviewDeduplicateItems": MessageLookupByLibrary.simpleMessage( "Lütfen kopya olduğunu düşündüğünüz öğeleri inceleyin ve silin."), - "reviewSuggestions": - MessageLookupByLibrary.simpleMessage("Review suggestions"), - "right": MessageLookupByLibrary.simpleMessage("Right"), - "rotate": MessageLookupByLibrary.simpleMessage("Rotate"), "rotateLeft": MessageLookupByLibrary.simpleMessage("Sola döndür"), "rotateRight": MessageLookupByLibrary.simpleMessage("Sağa döndür"), "safelyStored": @@ -1313,12 +1145,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage( "Henüz yapmadıysanız kurtarma anahtarınızı kaydetmeyi unutmayın"), "saving": MessageLookupByLibrary.simpleMessage("Kaydediliyor..."), - "savingEdits": MessageLookupByLibrary.simpleMessage("Saving edits..."), "scanCode": MessageLookupByLibrary.simpleMessage("Kodu tarayın"), "scanThisBarcodeWithnyourAuthenticatorApp": MessageLookupByLibrary.simpleMessage( "Kimlik doğrulama uygulamanız ile kodu tarayın"), - "search": MessageLookupByLibrary.simpleMessage("Search"), "searchAlbumsEmptySection": MessageLookupByLibrary.simpleMessage("Albümler"), "searchByAlbumNameHint": @@ -1329,8 +1159,6 @@ class MessageLookup extends MessageLookupByLibrary { "Fotoğraf bilgilerini burada hızlı bir şekilde bulmak için \"#trip\" gibi açıklamalar ekleyin"), "searchDatesEmptySection": MessageLookupByLibrary.simpleMessage( "Tarihe, aya veya yıla göre arama yapın"), - "searchFaceEmptySection": MessageLookupByLibrary.simpleMessage( - "People will be shown here once indexing is done"), "searchFileTypesAndNamesEmptySection": MessageLookupByLibrary.simpleMessage("Dosya türleri ve adları"), "searchHint1": @@ -1346,7 +1174,7 @@ class MessageLookup extends MessageLookupByLibrary { "Bir fotoğrafın belli bir yarıçapında çekilen fotoğrafları gruplandırın"), "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage( "İnsanları davet ettiğinizde onların paylaştığı tüm fotoğrafları burada göreceksiniz"), - "searchResultCount": m48, + "searchResultCount": m50, "security": MessageLookupByLibrary.simpleMessage("Güvenlik"), "selectALocation": MessageLookupByLibrary.simpleMessage("Bir konum seçin"), @@ -1365,16 +1193,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ayrılma nedeninizi seçin"), "selectYourPlan": MessageLookupByLibrary.simpleMessage("Planınızı seçin"), - "selectedFilesAreNotOnEnte": MessageLookupByLibrary.simpleMessage( - "Selected files are not on Ente"), "selectedFoldersWillBeEncryptedAndBackedUp": MessageLookupByLibrary.simpleMessage( "Seçilen klasörler şifrelenecek ve yedeklenecektir"), "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage( "Seçilen öğeler tüm albümlerden silinecek ve çöp kutusuna taşınacak."), - "selectedPhotos": m49, - "selectedPhotosWithYours": m50, + "selectedPhotos": m1, + "selectedPhotosWithYours": m51, "send": MessageLookupByLibrary.simpleMessage("Gönder"), "sendEmail": MessageLookupByLibrary.simpleMessage("E-posta gönder"), "sendInvite": MessageLookupByLibrary.simpleMessage("Davet kodu gönder"), @@ -1387,9 +1213,6 @@ class MessageLookup extends MessageLookupByLibrary { "setAs": MessageLookupByLibrary.simpleMessage("Şu şekilde ayarla"), "setCover": MessageLookupByLibrary.simpleMessage("Kapak Belirle"), "setLabel": MessageLookupByLibrary.simpleMessage("Ayarla"), - "setNewPassword": - MessageLookupByLibrary.simpleMessage("Set new password"), - "setNewPin": MessageLookupByLibrary.simpleMessage("Set new PIN"), "setPasswordTitle": MessageLookupByLibrary.simpleMessage("Parola ayarlayın"), "setRadius": MessageLookupByLibrary.simpleMessage("Yarıçapı ayarla"), @@ -1402,20 +1225,13 @@ class MessageLookup extends MessageLookupByLibrary { "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("Şimdi bir albüm paylaşın"), "shareLink": MessageLookupByLibrary.simpleMessage("Linki paylaş"), - "shareMyVerificationID": m51, + "shareMyVerificationID": m52, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Yalnızca istediğiniz kişilerle paylaşın"), - "shareTextConfirmOthersVerificationID": m52, - "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( - "Download Ente so we can easily share original quality photos and videos\n\nhttps://ente.io"), - "shareTextReferralCode": m53, - "shareWithNonenteUsers": - MessageLookupByLibrary.simpleMessage("Share with non-Ente users"), + "shareTextConfirmOthersVerificationID": m2, "shareWithPeopleSectionTitle": m54, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage("İlk albümünüzü paylaşın"), - "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( - "Create shared and collaborative albums with other Ente users, including users on free plans."), "sharedByMe": MessageLookupByLibrary.simpleMessage("Benim paylaştıklarım"), "sharedByYou": MessageLookupByLibrary.simpleMessage("Paylaştıklarınız"), @@ -1441,13 +1257,8 @@ class MessageLookup extends MessageLookupByLibrary { "singleFileDeleteFromDevice": m56, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage("Tüm albümlerden silinecek."), - "singleFileInBothLocalAndRemote": m57, - "singleFileInRemoteOnly": m58, "skip": MessageLookupByLibrary.simpleMessage("Geç"), "social": MessageLookupByLibrary.simpleMessage("Sosyal Medya"), - "someItemsAreInBothEnteAndYourDevice": - MessageLookupByLibrary.simpleMessage( - "Some items are in both Ente and your device."), "someOfTheFilesYouAreTryingToDeleteAre": MessageLookupByLibrary.simpleMessage( "Silmeye çalıştığınız dosyalardan bazıları yalnızca cihazınızda mevcuttur ve silindiği takdirde kurtarılamaz"), @@ -1479,10 +1290,6 @@ class MessageLookup extends MessageLookupByLibrary { "startBackup": MessageLookupByLibrary.simpleMessage("Yedeklemeyi başlat"), "status": MessageLookupByLibrary.simpleMessage("Durum"), - "stopCastingBody": MessageLookupByLibrary.simpleMessage( - "Do you want to stop casting?"), - "stopCastingTitle": - MessageLookupByLibrary.simpleMessage("Stop casting"), "storage": MessageLookupByLibrary.simpleMessage("Depolama"), "storageBreakupFamily": MessageLookupByLibrary.simpleMessage("Aile"), "storageBreakupYou": MessageLookupByLibrary.simpleMessage("Sen"), @@ -1491,7 +1298,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Depolama sınırı aşıldı"), "storageUsageInfo": m60, "strongStrength": MessageLookupByLibrary.simpleMessage("Güçlü"), - "subAlreadyLinkedErrMessage": m61, "subWillBeCancelledOn": m62, "subscribe": MessageLookupByLibrary.simpleMessage("Abone ol"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( @@ -1518,7 +1324,6 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("kopyalamak için dokunun"), "tapToEnterCode": MessageLookupByLibrary.simpleMessage("Kodu girmek icin tıklayın"), - "tapToUnlock": MessageLookupByLibrary.simpleMessage("Tap to unlock"), "tempErrorContactSupportIfPersists": MessageLookupByLibrary.simpleMessage( "Bir şeyler ters gitmiş gibi görünüyor. Lütfen bir süre sonra tekrar deneyin. Hata devam ederse, lütfen destek ekibimizle iletişime geçin."), "terminate": MessageLookupByLibrary.simpleMessage("Sonlandır"), @@ -1562,28 +1367,17 @@ class MessageLookup extends MessageLookupByLibrary { "Bu, sizi aşağıdaki cihazdan çıkış yapacak:"), "thisWillLogYouOutOfThisDevice": MessageLookupByLibrary.simpleMessage( "Bu cihazdaki oturumunuz kapatılacak!"), - "thisWillRemovePublicLinksOfAllSelectedQuickLinks": - MessageLookupByLibrary.simpleMessage( - "This will remove public links of all selected quick links."), - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": - MessageLookupByLibrary.simpleMessage( - "To enable app lock, please setup device passcode or screen lock in your system settings."), "toHideAPhotoOrVideo": MessageLookupByLibrary.simpleMessage( "Bir fotoğrafı veya videoyu gizlemek için"), "toResetVerifyEmail": MessageLookupByLibrary.simpleMessage( "Şifrenizi sıfılamak için lütfen e-postanızı girin."), "todaysLogs": MessageLookupByLibrary.simpleMessage("Bugünün günlükleri"), - "tooManyIncorrectAttempts": - MessageLookupByLibrary.simpleMessage("Too many incorrect attempts"), "total": MessageLookupByLibrary.simpleMessage("total"), "totalSize": MessageLookupByLibrary.simpleMessage("Toplam boyut"), "trash": MessageLookupByLibrary.simpleMessage("Cöp kutusu"), "trashDaysLeft": m66, - "trim": MessageLookupByLibrary.simpleMessage("Trim"), "tryAgain": MessageLookupByLibrary.simpleMessage("Tekrar deneyiniz"), - "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( - "Turn on backup to automatically upload files added to this device folder to Ente."), "twitter": MessageLookupByLibrary.simpleMessage("Twitter"), "twoMonthsFreeOnYearlyPlans": MessageLookupByLibrary.simpleMessage( "Yıllık planlarda 2 ay ücretsiz"), @@ -1626,10 +1420,6 @@ class MessageLookup extends MessageLookupByLibrary { "4 Aralık\'a kadar %50\'ye varan indirim."), "usableReferralStorageInfo": MessageLookupByLibrary.simpleMessage( "Kullanılabilir depolama alanı mevcut planınızla sınırlıdır. Talep edilen fazla depolama alanı, planınızı yükselttiğinizde otomatik olarak kullanılabilir hale gelecektir."), - "useAsCover": MessageLookupByLibrary.simpleMessage("Use as cover"), - "usePublicLinksForPeopleNotOnEnte": - MessageLookupByLibrary.simpleMessage( - "Use public links for people not on Ente"), "useRecoveryKey": MessageLookupByLibrary.simpleMessage("Kurtarma anahtarını kullan"), "useSelectedPhoto": @@ -1662,9 +1452,6 @@ class MessageLookup extends MessageLookupByLibrary { "viewAll": MessageLookupByLibrary.simpleMessage("Tümünü görüntüle"), "viewAllExifData": MessageLookupByLibrary.simpleMessage( "Tüm EXIF verilerini görüntüle"), - "viewLargeFiles": MessageLookupByLibrary.simpleMessage("Large files"), - "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( - "View files that are consuming the most amount of storage"), "viewLogs": MessageLookupByLibrary.simpleMessage("Günlükleri göster"), "viewRecoveryKey": MessageLookupByLibrary.simpleMessage( "Kurtarma anahtarını görüntüle"), @@ -1684,7 +1471,6 @@ class MessageLookup extends MessageLookupByLibrary { "weakStrength": MessageLookupByLibrary.simpleMessage("Zayıf"), "welcomeBack": MessageLookupByLibrary.simpleMessage("Tekrardan hoşgeldin!"), - "whatsNew": MessageLookupByLibrary.simpleMessage("What\'s new"), "yearly": MessageLookupByLibrary.simpleMessage("Yıllık"), "yearsAgo": m70, "yes": MessageLookupByLibrary.simpleMessage("Evet"), diff --git a/mobile/lib/generated/intl/messages_zh.dart b/mobile/lib/generated/intl/messages_zh.dart index 793ab08d5c..2a34fee561 100644 --- a/mobile/lib/generated/intl/messages_zh.dart +++ b/mobile/lib/generated/intl/messages_zh.dart @@ -20,137 +20,139 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'zh'; - static String m0(count) => + static String m3(count) => "${Intl.plural(count, zero: '添加协作者', one: '添加协作者', other: '添加协作者')}"; - static String m2(count) => + static String m4(count) => "${Intl.plural(count, one: '添加一个项目', other: '添加一些项目')}"; - static String m3(storageAmount, endDate) => + static String m5(storageAmount, endDate) => "您的 ${storageAmount} 插件有效期至 ${endDate}"; - static String m1(count) => + static String m6(count) => "${Intl.plural(count, zero: '添加查看者', one: '添加查看者', other: '添加查看者')}"; - static String m4(emailOrName) => "由 ${emailOrName} 添加"; + static String m7(emailOrName) => "由 ${emailOrName} 添加"; - static String m5(albumName) => "成功添加到 ${albumName}"; + static String m8(albumName) => "成功添加到 ${albumName}"; - static String m6(count) => + static String m9(count) => "${Intl.plural(count, zero: '无参与者', one: '1个参与者', other: '${count} 个参与者')}"; - static String m7(versionValue) => "版本: ${versionValue}"; + static String m10(versionValue) => "版本: ${versionValue}"; - static String m8(freeAmount, storageUnit) => + static String m11(freeAmount, storageUnit) => "${freeAmount} ${storageUnit} 空闲"; - static String m9(paymentProvider) => "请先取消您现有的订阅 ${paymentProvider}"; + static String m12(paymentProvider) => "请先取消您现有的订阅 ${paymentProvider}"; - static String m10(user) => "${user} 将无法添加更多照片到此相册\n\n他们仍然能够删除他们添加的现有照片"; + static String m13(user) => "${user} 将无法添加更多照片到此相册\n\n他们仍然能够删除他们添加的现有照片"; - static String m11(isFamilyMember, storageAmountInGb) => + static String m14(isFamilyMember, storageAmountInGb) => "${Intl.select(isFamilyMember, { 'true': '到目前为止,您的家庭已经领取了 ${storageAmountInGb} GB', 'false': '到目前为止,您已经领取了 ${storageAmountInGb} GB', 'other': '到目前为止,您已经领取了${storageAmountInGb} GB', })}"; - static String m12(albumName) => "为 ${albumName} 创建了协作链接"; + static String m15(albumName) => "为 ${albumName} 创建了协作链接"; - static String m13(familyAdminEmail) => + static String m16(familyAdminEmail) => "请联系 ${familyAdminEmail} 来管理您的订阅"; - static String m14(provider) => + static String m17(provider) => "请通过support@ente.io 用英语联系我们来管理您的 ${provider} 订阅。"; - static String m15(endpoint) => "已连接至 ${endpoint}"; + static String m18(endpoint) => "已连接至 ${endpoint}"; - static String m16(count) => + static String m19(count) => "${Intl.plural(count, one: '删除 ${count} 个项目', other: '删除 ${count} 个项目')}"; - static String m17(currentlyDeleting, totalCount) => + static String m20(currentlyDeleting, totalCount) => "正在删除 ${currentlyDeleting} /共 ${totalCount}"; - static String m18(albumName) => "这将删除用于访问\"${albumName}\"的公开链接。"; + static String m21(albumName) => "这将删除用于访问\"${albumName}\"的公开链接。"; - static String m19(supportEmail) => "请从您注册的邮箱发送一封邮件到 ${supportEmail}"; + static String m22(supportEmail) => "请从您注册的邮箱发送一封邮件到 ${supportEmail}"; - static String m20(count, storageSaved) => + static String m23(count, storageSaved) => "您已经清理了 ${Intl.plural(count, other: '${count} 个重复文件')}, 释放了 (${storageSaved}!)"; - static String m21(count, formattedSize) => + static String m24(count, formattedSize) => "${count} 个文件,每个文件 ${formattedSize}"; - static String m22(newEmail) => "电子邮件已更改为 ${newEmail}"; + static String m25(newEmail) => "电子邮件已更改为 ${newEmail}"; - static String m23(email) => "${email} 没有 Ente 帐户。\n\n向他们发出共享照片的邀请。"; + static String m26(email) => "${email} 没有 Ente 帐户。\n\n向他们发出共享照片的邀请。"; - static String m24(count, formattedNumber) => + static String m27(count, formattedNumber) => "此设备上的 ${Intl.plural(count, one: '1 个文件', other: '${formattedNumber} 个文件')} 已安全备份"; - static String m25(count, formattedNumber) => + static String m28(count, formattedNumber) => "此相册中的 ${Intl.plural(count, one: '1 个文件', other: '${formattedNumber} 个文件')} 已安全备份"; - static String m26(storageAmountInGB) => + static String m29(storageAmountInGB) => "每当有人使用您的代码注册付费计划时您将获得${storageAmountInGB} GB"; - static String m27(endDate) => "免费试用有效期至 ${endDate}"; + static String m30(endDate) => "免费试用有效期至 ${endDate}"; - static String m28(count) => + static String m31(count) => "只要您有有效的订阅,您仍然可以在 Ente 上访问 ${Intl.plural(count, one: '它', other: '它们')}"; - static String m29(sizeInMBorGB) => "释放 ${sizeInMBorGB}"; + static String m32(sizeInMBorGB) => "释放 ${sizeInMBorGB}"; - static String m30(count, formattedSize) => + static String m33(count, formattedSize) => "${Intl.plural(count, one: '它可以从设备中删除以释放 ${formattedSize}', other: '它们可以从设备中删除以释放 ${formattedSize}')}"; - static String m31(currentlyProcessing, totalCount) => + static String m34(currentlyProcessing, totalCount) => "正在处理 ${currentlyProcessing} / ${totalCount}"; - static String m32(count) => + static String m35(count) => "${Intl.plural(count, one: '${count} 个项目', other: '${count} 个项目')}"; - static String m33(expiryTime) => "链接将在 ${expiryTime} 过期"; + static String m36(expiryTime) => "链接将在 ${expiryTime} 过期"; - static String m34(count, formattedCount) => + static String m0(count, formattedCount) => "${Intl.plural(count, zero: '没有回忆', one: '${formattedCount} 个回忆', other: '${formattedCount} 个回忆')}"; - static String m35(count) => + static String m37(count) => "${Intl.plural(count, one: '移动一个项目', other: '移动一些项目')}"; - static String m36(albumName) => "成功移动到 ${albumName}"; + static String m38(albumName) => "成功移动到 ${albumName}"; - static String m37(name) => "不是 ${name}?"; + static String m39(name) => "不是 ${name}?"; - static String m39(passwordStrengthValue) => "密码强度: ${passwordStrengthValue}"; + static String m40(familyAdminEmail) => "请联系${familyAdminEmail} 以更改您的代码。"; - static String m40(providerName) => "如果您被收取费用,请用英语与 ${providerName} 的客服聊天"; + static String m41(passwordStrengthValue) => "密码强度: ${passwordStrengthValue}"; - static String m41(endDate) => "免费试用有效期至 ${endDate}。\n在此之后您可以选择付费计划。"; + static String m42(providerName) => "如果您被收取费用,请用英语与 ${providerName} 的客服聊天"; - static String m42(toEmail) => "请给我们发送电子邮件至 ${toEmail}"; + static String m43(endDate) => "免费试用有效期至 ${endDate}。\n在此之后您可以选择付费计划。"; - static String m43(toEmail) => "请将日志发送至 \n${toEmail}"; + static String m44(toEmail) => "请给我们发送电子邮件至 ${toEmail}"; - static String m44(storeName) => "在 ${storeName} 上给我们评分"; + static String m45(toEmail) => "请将日志发送至 \n${toEmail}"; - static String m45(storageInGB) => "3. 你和朋友都将免费获得 ${storageInGB} GB*"; + static String m46(storeName) => "在 ${storeName} 上给我们评分"; - static String m46(userEmail) => + static String m47(storageInGB) => "3. 你和朋友都将免费获得 ${storageInGB} GB*"; + + static String m48(userEmail) => "${userEmail} 将从这个共享相册中删除\n\nTA们添加的任何照片也将从相册中删除"; - static String m47(endDate) => "在 ${endDate} 前续费"; + static String m49(endDate) => "在 ${endDate} 前续费"; - static String m48(count) => + static String m50(count) => "${Intl.plural(count, other: '已找到 ${count} 个结果')}"; - static String m49(count) => "已选择 ${count} 个"; + static String m1(count) => "已选择 ${count} 个"; - static String m50(count, yourCount) => "选择了 ${count} 个 (您的 ${yourCount} 个)"; + static String m51(count, yourCount) => "选择了 ${count} 个 (您的 ${yourCount} 个)"; - static String m51(verificationID) => "这是我的ente.io 的验证 ID: ${verificationID}。"; + static String m52(verificationID) => "这是我的ente.io 的验证 ID: ${verificationID}。"; - static String m52(verificationID) => + static String m2(verificationID) => "嘿,你能确认这是你的 ente.io 验证 ID吗:${verificationID}"; static String m53(referralCode, referralStorageInGB) => @@ -211,15 +213,15 @@ class MessageLookup extends MessageLookupByLibrary { "addAName": MessageLookupByLibrary.simpleMessage("添加一个名称"), "addANewEmail": MessageLookupByLibrary.simpleMessage("添加新的电子邮件"), "addCollaborator": MessageLookupByLibrary.simpleMessage("添加协作者"), - "addCollaborators": m0, + "addCollaborators": m3, "addFromDevice": MessageLookupByLibrary.simpleMessage("从设备添加"), - "addItem": m2, + "addItem": m4, "addLocation": MessageLookupByLibrary.simpleMessage("添加地点"), "addLocationButton": MessageLookupByLibrary.simpleMessage("添加"), "addMore": MessageLookupByLibrary.simpleMessage("添加更多"), "addNew": MessageLookupByLibrary.simpleMessage("新建"), "addOnPageSubtitle": MessageLookupByLibrary.simpleMessage("附加组件详情"), - "addOnValidTill": m3, + "addOnValidTill": m5, "addOns": MessageLookupByLibrary.simpleMessage("附加组件"), "addPhotos": MessageLookupByLibrary.simpleMessage("添加照片"), "addSelected": MessageLookupByLibrary.simpleMessage("添加所选项"), @@ -227,11 +229,11 @@ class MessageLookup extends MessageLookupByLibrary { "addToEnte": MessageLookupByLibrary.simpleMessage("添加到 Ente"), "addToHiddenAlbum": MessageLookupByLibrary.simpleMessage("添加到隐藏相册"), "addViewer": MessageLookupByLibrary.simpleMessage("添加查看者"), - "addViewers": m1, + "addViewers": m6, "addYourPhotosNow": MessageLookupByLibrary.simpleMessage("立即添加您的照片"), "addedAs": MessageLookupByLibrary.simpleMessage("已添加为"), - "addedBy": m4, - "addedSuccessfullyTo": m5, + "addedBy": m7, + "addedSuccessfullyTo": m8, "addingToFavorites": MessageLookupByLibrary.simpleMessage("正在添加到收藏..."), "advanced": MessageLookupByLibrary.simpleMessage("高级设置"), "advancedSettings": MessageLookupByLibrary.simpleMessage("高级设置"), @@ -241,7 +243,7 @@ class MessageLookup extends MessageLookupByLibrary { "after1Week": MessageLookupByLibrary.simpleMessage("1 周后"), "after1Year": MessageLookupByLibrary.simpleMessage("1 年后"), "albumOwner": MessageLookupByLibrary.simpleMessage("所有者"), - "albumParticipantsCount": m6, + "albumParticipantsCount": m9, "albumTitle": MessageLookupByLibrary.simpleMessage("相册标题"), "albumUpdated": MessageLookupByLibrary.simpleMessage("相册已更新"), "albums": MessageLookupByLibrary.simpleMessage("相册"), @@ -272,8 +274,8 @@ class MessageLookup extends MessageLookupByLibrary { "androidSignInTitle": MessageLookupByLibrary.simpleMessage("需要身份验证"), "appLock": MessageLookupByLibrary.simpleMessage("应用锁"), "appLockDescriptions": MessageLookupByLibrary.simpleMessage( - "Choose between your device\'s default lock screen and a custom lock screen with a PIN or password."), - "appVersion": m7, + "在设备的默认锁定屏幕和带有 PIN 或密码的自定义锁定屏幕之间进行选择。"), + "appVersion": m10, "appleId": MessageLookupByLibrary.simpleMessage("Apple ID"), "apply": MessageLookupByLibrary.simpleMessage("应用"), "applyCodeTitle": MessageLookupByLibrary.simpleMessage("应用代码"), @@ -313,8 +315,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("请进行身份验证以配置双重身份认证"), "authToInitiateAccountDeletion": MessageLookupByLibrary.simpleMessage("请进行身份验证以启动账户删除"), - "authToViewPasskey": MessageLookupByLibrary.simpleMessage( - "Please authenticate to view your passkey"), + "authToViewPasskey": + MessageLookupByLibrary.simpleMessage("请验证身份以查看您的通行密钥"), "authToViewYourActiveSessions": MessageLookupByLibrary.simpleMessage("请验证以查看您的活动会话"), "authToViewYourHiddenFiles": @@ -341,7 +343,7 @@ class MessageLookup extends MessageLookupByLibrary { "autoPairDesc": MessageLookupByLibrary.simpleMessage("自动配对仅适用于支持 Chromecast 的设备。"), "available": MessageLookupByLibrary.simpleMessage("可用"), - "availableStorageSpace": m8, + "availableStorageSpace": m11, "backedUpFolders": MessageLookupByLibrary.simpleMessage("已备份的文件夹"), "backup": MessageLookupByLibrary.simpleMessage("备份"), "backupFailed": MessageLookupByLibrary.simpleMessage("备份失败"), @@ -360,9 +362,9 @@ class MessageLookup extends MessageLookupByLibrary { "canOnlyRemoveFilesOwnedByYou": MessageLookupByLibrary.simpleMessage("只能删除您拥有的文件"), "cancel": MessageLookupByLibrary.simpleMessage("取消"), - "cancelOtherSubscription": m9, + "cancelOtherSubscription": m12, "cancelSubscription": MessageLookupByLibrary.simpleMessage("取消订阅"), - "cannotAddMorePhotosAfterBecomingViewer": m10, + "cannotAddMorePhotosAfterBecomingViewer": m13, "cannotDeleteSharedFiles": MessageLookupByLibrary.simpleMessage("无法删除共享文件"), "castIPMismatchBody": @@ -371,33 +373,36 @@ class MessageLookup extends MessageLookupByLibrary { "castInstruction": MessageLookupByLibrary.simpleMessage( "在您要配对的设备上访问 cast.ente.io。\n在下框中输入代码即可在电视上播放相册。"), "centerPoint": MessageLookupByLibrary.simpleMessage("中心点"), + "change": MessageLookupByLibrary.simpleMessage("更改"), "changeEmail": MessageLookupByLibrary.simpleMessage("修改邮箱"), "changeLocationOfSelectedItems": MessageLookupByLibrary.simpleMessage("确定要更改所选项目的位置吗?"), "changePassword": MessageLookupByLibrary.simpleMessage("修改密码"), "changePasswordTitle": MessageLookupByLibrary.simpleMessage("修改密码"), "changePermissions": MessageLookupByLibrary.simpleMessage("要修改权限吗?"), + "changeYourReferralCode": + MessageLookupByLibrary.simpleMessage("更改您的推荐代码"), "checkForUpdates": MessageLookupByLibrary.simpleMessage("检查更新"), "checkInboxAndSpamFolder": MessageLookupByLibrary.simpleMessage( "请检查您的收件箱 (或者是在您的“垃圾邮件”列表内) 以完成验证"), "checkStatus": MessageLookupByLibrary.simpleMessage("检查状态"), "checking": MessageLookupByLibrary.simpleMessage("正在检查..."), "cl_guest_view_call_to_action": - MessageLookupByLibrary.simpleMessage("选择照片并查看\"访客视图\"。"), + MessageLookupByLibrary.simpleMessage("选择照片并使用“访客视图”。"), "cl_guest_view_description": MessageLookupByLibrary.simpleMessage( - "要把手机递给朋友看照片?别担心他们滑动太远。访客视图将锁定您选择的照片。"), + "把手机交给朋友看照片?不用担心 Ta 们滑动屏幕乱看照片。访客视图会将 Ta 们锁定在您选择的照片中。"), "cl_guest_view_title": MessageLookupByLibrary.simpleMessage("访客视图"), "cl_panorama_viewer_description": MessageLookupByLibrary.simpleMessage( - "我们新增了支持 360 度全景照片查看功能。结合动作导航,体验更加身临其境!"), + "我们添加了对 360 度全景照片的支持。通过基于动作的导航,用户可获得身临其境的体验!"), "cl_panorama_viewer_title": - MessageLookupByLibrary.simpleMessage("全景查看器"), + MessageLookupByLibrary.simpleMessage("全景图查看器"), "cl_video_player_description": MessageLookupByLibrary.simpleMessage( - "推出全新的视频播放器,具有更好的播放控制功能并支持 HDR 视频。"), + "推出全新的视频播放器,提供更好的播放控制并添加了对 HDR 视频的支持。"), "cl_video_player_title": MessageLookupByLibrary.simpleMessage("视频播放器"), "claimFreeStorage": MessageLookupByLibrary.simpleMessage("领取免费存储"), "claimMore": MessageLookupByLibrary.simpleMessage("领取更多!"), "claimed": MessageLookupByLibrary.simpleMessage("已领取"), - "claimedStorageSoFar": m11, + "claimedStorageSoFar": m14, "cleanUncategorized": MessageLookupByLibrary.simpleMessage("清除未分类的"), "cleanUncategorizedDescription": MessageLookupByLibrary.simpleMessage("从“未分类”中删除其他相册中存在的所有文件"), @@ -411,13 +416,15 @@ class MessageLookup extends MessageLookupByLibrary { "clubByFileName": MessageLookupByLibrary.simpleMessage("按文件名排序"), "clusteringProgress": MessageLookupByLibrary.simpleMessage("聚类进展"), "codeAppliedPageTitle": MessageLookupByLibrary.simpleMessage("代码已应用"), + "codeChangeLimitReached": + MessageLookupByLibrary.simpleMessage("抱歉,您已达到代码更改的限制。"), "codeCopiedToClipboard": MessageLookupByLibrary.simpleMessage("代码已复制到剪贴板"), "codeUsedByYou": MessageLookupByLibrary.simpleMessage("您所使用的代码"), "collabLinkSectionDescription": MessageLookupByLibrary.simpleMessage( "创建一个链接来让他人无需 Ente 应用程序或账户即可在您的共享相册中添加和查看照片。非常适合收集活动照片。"), "collaborativeLink": MessageLookupByLibrary.simpleMessage("协作链接"), - "collaborativeLinkCreatedFor": m12, + "collaborativeLinkCreatedFor": m15, "collaborator": MessageLookupByLibrary.simpleMessage("协作者"), "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": MessageLookupByLibrary.simpleMessage("协作者可以将照片和视频添加到共享相册中。"), @@ -439,9 +446,9 @@ class MessageLookup extends MessageLookupByLibrary { "confirmYourRecoveryKey": MessageLookupByLibrary.simpleMessage("确认您的恢复密钥"), "connectToDevice": MessageLookupByLibrary.simpleMessage("连接到设备"), - "contactFamilyAdmin": m13, + "contactFamilyAdmin": m16, "contactSupport": MessageLookupByLibrary.simpleMessage("联系支持"), - "contactToManageSubscription": m14, + "contactToManageSubscription": m17, "contacts": MessageLookupByLibrary.simpleMessage("联系人"), "contents": MessageLookupByLibrary.simpleMessage("内容"), "continueLabel": MessageLookupByLibrary.simpleMessage("继续"), @@ -474,7 +481,7 @@ class MessageLookup extends MessageLookupByLibrary { "crop": MessageLookupByLibrary.simpleMessage("裁剪"), "currentUsageIs": MessageLookupByLibrary.simpleMessage("当前用量 "), "custom": MessageLookupByLibrary.simpleMessage("自定义"), - "customEndpoint": m15, + "customEndpoint": m18, "darkTheme": MessageLookupByLibrary.simpleMessage("深色"), "dayToday": MessageLookupByLibrary.simpleMessage("今天"), "dayYesterday": MessageLookupByLibrary.simpleMessage("昨天"), @@ -503,10 +510,10 @@ class MessageLookup extends MessageLookupByLibrary { "deleteFromBoth": MessageLookupByLibrary.simpleMessage("同时从两者中删除"), "deleteFromDevice": MessageLookupByLibrary.simpleMessage("从设备中删除"), "deleteFromEnte": MessageLookupByLibrary.simpleMessage("从 Ente 中删除"), - "deleteItemCount": m16, + "deleteItemCount": m19, "deleteLocation": MessageLookupByLibrary.simpleMessage("删除位置"), "deletePhotos": MessageLookupByLibrary.simpleMessage("删除照片"), - "deleteProgress": m17, + "deleteProgress": m20, "deleteReason1": MessageLookupByLibrary.simpleMessage("找不到我想要的功能"), "deleteReason2": MessageLookupByLibrary.simpleMessage("应用或某个功能没有按我的预期运行"), @@ -538,7 +545,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("查看者仍然可以使用外部工具截图或保存您的照片副本"), "disableDownloadWarningTitle": MessageLookupByLibrary.simpleMessage("请注意"), - "disableLinkMessage": m18, + "disableLinkMessage": m21, "disableTwofactor": MessageLookupByLibrary.simpleMessage("禁用双重认证"), "disablingTwofactorAuthentication": MessageLookupByLibrary.simpleMessage("正在禁用双重认证..."), @@ -555,9 +562,9 @@ class MessageLookup extends MessageLookupByLibrary { "download": MessageLookupByLibrary.simpleMessage("下载"), "downloadFailed": MessageLookupByLibrary.simpleMessage("下載失敗"), "downloading": MessageLookupByLibrary.simpleMessage("正在下载..."), - "dropSupportEmail": m19, - "duplicateFileCountWithStorageSaved": m20, - "duplicateItemsGroup": m21, + "dropSupportEmail": m22, + "duplicateFileCountWithStorageSaved": m23, + "duplicateItemsGroup": m24, "edit": MessageLookupByLibrary.simpleMessage("编辑"), "editLocation": MessageLookupByLibrary.simpleMessage("编辑位置"), "editLocationTagTitle": MessageLookupByLibrary.simpleMessage("编辑位置"), @@ -566,16 +573,20 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("对位置的编辑只能在 Ente 内看到"), "eligible": MessageLookupByLibrary.simpleMessage("符合资格"), "email": MessageLookupByLibrary.simpleMessage("电子邮件地址"), - "emailChangedTo": m22, - "emailNoEnteAccount": m23, + "emailChangedTo": m25, + "emailNoEnteAccount": m26, "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("电子邮件验证"), "emailYourLogs": MessageLookupByLibrary.simpleMessage("通过电子邮件发送您的日志"), "empty": MessageLookupByLibrary.simpleMessage("清空"), "emptyTrash": MessageLookupByLibrary.simpleMessage("要清空回收站吗?"), + "enable": MessageLookupByLibrary.simpleMessage("启用"), + "enableMLIndexingDesc": MessageLookupByLibrary.simpleMessage( + "Ente 支持设备上的机器学习,实现人脸识别、魔法搜索和其他高级搜索功能"), "enableMaps": MessageLookupByLibrary.simpleMessage("启用地图"), "enableMapsDesc": MessageLookupByLibrary.simpleMessage( "这将在世界地图上显示您的照片。\n\n该地图由 Open Street Map 托管,并且您的照片的确切位置永远不会共享。\n\n您可以随时从“设置”中禁用此功能。"), + "enabled": MessageLookupByLibrary.simpleMessage("已启用"), "encryptingBackup": MessageLookupByLibrary.simpleMessage("正在加密备份..."), "encryption": MessageLookupByLibrary.simpleMessage("加密"), "encryptionKeys": MessageLookupByLibrary.simpleMessage("加密密钥"), @@ -649,8 +660,8 @@ class MessageLookup extends MessageLookupByLibrary { "fileSavedToGallery": MessageLookupByLibrary.simpleMessage("文件已保存到相册"), "fileTypes": MessageLookupByLibrary.simpleMessage("文件类型"), "fileTypesAndNames": MessageLookupByLibrary.simpleMessage("文件类型和名称"), - "filesBackedUpFromDevice": m24, - "filesBackedUpInAlbum": m25, + "filesBackedUpFromDevice": m27, + "filesBackedUpInAlbum": m28, "filesDeleted": MessageLookupByLibrary.simpleMessage("文件已删除"), "filesSavedToGallery": MessageLookupByLibrary.simpleMessage("多个文件已保存到相册"), @@ -660,23 +671,23 @@ class MessageLookup extends MessageLookupByLibrary { "forgotPassword": MessageLookupByLibrary.simpleMessage("忘记密码"), "foundFaces": MessageLookupByLibrary.simpleMessage("已找到的人脸"), "freeStorageClaimed": MessageLookupByLibrary.simpleMessage("已领取的免费存储"), - "freeStorageOnReferralSuccess": m26, + "freeStorageOnReferralSuccess": m29, "freeStorageUsable": MessageLookupByLibrary.simpleMessage("可用的免费存储"), "freeTrial": MessageLookupByLibrary.simpleMessage("免费试用"), - "freeTrialValidTill": m27, - "freeUpAccessPostDelete": m28, - "freeUpAmount": m29, + "freeTrialValidTill": m30, + "freeUpAccessPostDelete": m31, + "freeUpAmount": m32, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("释放设备空间"), "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage("通过清除已备份的文件来节省设备空间。"), "freeUpSpace": MessageLookupByLibrary.simpleMessage("释放空间"), - "freeUpSpaceSaving": m30, + "freeUpSpaceSaving": m33, "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage("在图库中显示最多1000个回忆"), "general": MessageLookupByLibrary.simpleMessage("通用"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage("正在生成加密密钥..."), - "genericProgress": m31, + "genericProgress": m34, "goToSettings": MessageLookupByLibrary.simpleMessage("前往设置"), "googlePlayId": MessageLookupByLibrary.simpleMessage("Google Play ID"), "grantFullAccessPrompt": @@ -742,7 +753,7 @@ class MessageLookup extends MessageLookupByLibrary { "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "看起来出了点问题。 请稍后重试。 如果错误仍然存在,请联系我们的支持团队。"), - "itemCount": m32, + "itemCount": m35, "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": MessageLookupByLibrary.simpleMessage("项目显示永久删除前剩余的天数"), "itemsWillBeRemovedFromAlbum": @@ -766,7 +777,7 @@ class MessageLookup extends MessageLookupByLibrary { "linkDeviceLimit": MessageLookupByLibrary.simpleMessage("设备限制"), "linkEnabled": MessageLookupByLibrary.simpleMessage("已启用"), "linkExpired": MessageLookupByLibrary.simpleMessage("已过期"), - "linkExpiresOn": m33, + "linkExpiresOn": m36, "linkExpiry": MessageLookupByLibrary.simpleMessage("链接过期"), "linkHasExpired": MessageLookupByLibrary.simpleMessage("链接已过期"), "linkNeverExpires": MessageLookupByLibrary.simpleMessage("永不"), @@ -817,6 +828,8 @@ class MessageLookup extends MessageLookupByLibrary { "lostDevice": MessageLookupByLibrary.simpleMessage("设备丢失?"), "machineLearning": MessageLookupByLibrary.simpleMessage("机器学习"), "magicSearch": MessageLookupByLibrary.simpleMessage("魔法搜索"), + "magicSearchHint": MessageLookupByLibrary.simpleMessage( + "魔法搜索允许按内容搜索照片,例如“lower\'”、“red car”、“identity documents”"), "manage": MessageLookupByLibrary.simpleMessage("管理"), "manageDeviceStorage": MessageLookupByLibrary.simpleMessage("管理设备存储"), "manageFamily": MessageLookupByLibrary.simpleMessage("管理家庭计划"), @@ -829,10 +842,18 @@ class MessageLookup extends MessageLookupByLibrary { "maps": MessageLookupByLibrary.simpleMessage("地图"), "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), - "memoryCount": m34, + "memoryCount": m0, "merchandise": MessageLookupByLibrary.simpleMessage("商品"), + "mlConsent": MessageLookupByLibrary.simpleMessage("启用机器学习"), + "mlConsentConfirmation": + MessageLookupByLibrary.simpleMessage("我了解了,并希望启用机器学习"), + "mlConsentDescription": MessageLookupByLibrary.simpleMessage( + "如果您启用机器学习,Ente 将从文件(包括与您共享的文件)中提取面部几何形状等信息。\n\n这将在您的设备上进行,并且任何生成的生物特征信息都将被端到端加密。"), + "mlConsentPrivacy": + MessageLookupByLibrary.simpleMessage("请点击此处查看我们隐私政策中有关此功能的更多详细信息"), + "mlConsentTitle": MessageLookupByLibrary.simpleMessage("要启用机器学习吗?"), "mlIndexingDescription": MessageLookupByLibrary.simpleMessage( - "请注意,机器学习将使用更高的带宽和更多的电量,直到所有项目都被索引为止。"), + "请注意,机器学习会导致带宽和电池使用量增加,直到所有项目都被索引。请考虑使用桌面应用程序来加快索引速度,所有结果都将自动同步。"), "mobileWebDesktop": MessageLookupByLibrary.simpleMessage("移动端, 网页端, 桌面端"), "moderateStrength": MessageLookupByLibrary.simpleMessage("中等"), @@ -840,10 +861,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("修改您的查询,或尝试搜索"), "moments": MessageLookupByLibrary.simpleMessage("瞬间"), "monthly": MessageLookupByLibrary.simpleMessage("每月"), - "moveItem": m35, + "moreDetails": MessageLookupByLibrary.simpleMessage("更多详情"), + "moveItem": m37, "moveToAlbum": MessageLookupByLibrary.simpleMessage("移动到相册"), "moveToHiddenAlbum": MessageLookupByLibrary.simpleMessage("移至隐藏相册"), - "movedSuccessfullyTo": m36, + "movedSuccessfullyTo": m38, "movedToTrash": MessageLookupByLibrary.simpleMessage("已移至回收站"), "movingFilesToAlbum": MessageLookupByLibrary.simpleMessage("正在将文件移动到相册..."), @@ -881,7 +903,7 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("无结果"), "noResultsFound": MessageLookupByLibrary.simpleMessage("未找到任何结果"), "noSystemLockFound": MessageLookupByLibrary.simpleMessage("未找到系统锁"), - "notPersonLabel": m37, + "notPersonLabel": m39, "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage("尚未与您共享任何内容"), "nothingToSeeHere": MessageLookupByLibrary.simpleMessage("这里空空如也! 👀"), @@ -890,6 +912,7 @@ class MessageLookup extends MessageLookupByLibrary { "onDevice": MessageLookupByLibrary.simpleMessage("在设备上"), "onEnte": MessageLookupByLibrary.simpleMessage( "在 ente 上"), + "onlyFamilyAdminCanChangeCode": m40, "oops": MessageLookupByLibrary.simpleMessage("哎呀"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage("糟糕,无法保存编辑"), @@ -915,7 +938,7 @@ class MessageLookup extends MessageLookupByLibrary { "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage("密码修改成功"), "passwordLock": MessageLookupByLibrary.simpleMessage("密码锁"), - "passwordStrength": m39, + "passwordStrength": m41, "passwordStrengthInfo": MessageLookupByLibrary.simpleMessage( "密码强度的计算考虑了密码的长度、使用的字符以及密码是否出现在最常用的 10,000 个密码中"), "passwordWarning": MessageLookupByLibrary.simpleMessage( @@ -924,7 +947,7 @@ class MessageLookup extends MessageLookupByLibrary { "paymentFailed": MessageLookupByLibrary.simpleMessage("支付失败"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "不幸的是,您的付款失败。请联系支持人员,我们将为您提供帮助!"), - "paymentFailedTalkToProvider": m40, + "paymentFailedTalkToProvider": m42, "pendingItems": MessageLookupByLibrary.simpleMessage("待处理项目"), "pendingSync": MessageLookupByLibrary.simpleMessage("正在等待同步"), "people": MessageLookupByLibrary.simpleMessage("人物"), @@ -944,7 +967,7 @@ class MessageLookup extends MessageLookupByLibrary { "pinAlbum": MessageLookupByLibrary.simpleMessage("置顶相册"), "pinLock": MessageLookupByLibrary.simpleMessage("PIN 锁定"), "playOnTv": MessageLookupByLibrary.simpleMessage("在电视上播放相册"), - "playStoreFreeTrialValidTill": m41, + "playStoreFreeTrialValidTill": m43, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("PlayStore 订阅"), "pleaseCheckYourInternetConnectionAndTryAgain": @@ -954,12 +977,12 @@ class MessageLookup extends MessageLookupByLibrary { "请用英语联系 support@ente.io ,我们将乐意提供帮助!"), "pleaseContactSupportIfTheProblemPersists": MessageLookupByLibrary.simpleMessage("如果问题仍然存在,请联系支持"), - "pleaseEmailUsAt": m42, + "pleaseEmailUsAt": m44, "pleaseGrantPermissions": MessageLookupByLibrary.simpleMessage("请授予权限"), "pleaseLoginAgain": MessageLookupByLibrary.simpleMessage("请重新登录"), "pleaseSelectQuickLinksToRemove": MessageLookupByLibrary.simpleMessage("请选择要删除的快速链接"), - "pleaseSendTheLogsTo": m43, + "pleaseSendTheLogsTo": m45, "pleaseTryAgain": MessageLookupByLibrary.simpleMessage("请重试"), "pleaseVerifyTheCodeYouHaveEntered": MessageLookupByLibrary.simpleMessage("请验证您输入的代码"), @@ -985,7 +1008,7 @@ class MessageLookup extends MessageLookupByLibrary { "raiseTicket": MessageLookupByLibrary.simpleMessage("提升工单"), "rateTheApp": MessageLookupByLibrary.simpleMessage("为此应用评分"), "rateUs": MessageLookupByLibrary.simpleMessage("给我们评分"), - "rateUsOnStore": m44, + "rateUsOnStore": m46, "recover": MessageLookupByLibrary.simpleMessage("恢复"), "recoverAccount": MessageLookupByLibrary.simpleMessage("恢复账户"), "recoverButton": MessageLookupByLibrary.simpleMessage("恢复"), @@ -1012,7 +1035,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("把我们推荐给你的朋友然后获得延长一倍的订阅计划"), "referralStep1": MessageLookupByLibrary.simpleMessage("1. 将此代码提供给您的朋友"), "referralStep2": MessageLookupByLibrary.simpleMessage("2. 他们注册一个付费计划"), - "referralStep3": m45, + "referralStep3": m47, "referrals": MessageLookupByLibrary.simpleMessage("推荐"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage("推荐已暂停"), @@ -1033,7 +1056,7 @@ class MessageLookup extends MessageLookupByLibrary { "removeFromFavorite": MessageLookupByLibrary.simpleMessage("从收藏中移除"), "removeLink": MessageLookupByLibrary.simpleMessage("移除链接"), "removeParticipant": MessageLookupByLibrary.simpleMessage("移除参与者"), - "removeParticipantBody": m46, + "removeParticipantBody": m48, "removePersonLabel": MessageLookupByLibrary.simpleMessage("移除人物标签"), "removePublicLink": MessageLookupByLibrary.simpleMessage("删除公开链接"), "removePublicLinks": MessageLookupByLibrary.simpleMessage("删除公开链接"), @@ -1046,7 +1069,7 @@ class MessageLookup extends MessageLookupByLibrary { "renameAlbum": MessageLookupByLibrary.simpleMessage("重命名相册"), "renameFile": MessageLookupByLibrary.simpleMessage("重命名文件"), "renewSubscription": MessageLookupByLibrary.simpleMessage("续费订阅"), - "renewsOn": m47, + "renewsOn": m49, "reportABug": MessageLookupByLibrary.simpleMessage("报告错误"), "reportBug": MessageLookupByLibrary.simpleMessage("报告错误"), "resendEmail": MessageLookupByLibrary.simpleMessage("重新发送电子邮件"), @@ -1056,6 +1079,7 @@ class MessageLookup extends MessageLookupByLibrary { "restore": MessageLookupByLibrary.simpleMessage("恢复"), "restoreToAlbum": MessageLookupByLibrary.simpleMessage("恢复到相册"), "restoringFiles": MessageLookupByLibrary.simpleMessage("正在恢复文件..."), + "resumableUploads": MessageLookupByLibrary.simpleMessage("可续传上传"), "retry": MessageLookupByLibrary.simpleMessage("重试"), "reviewDeduplicateItems": MessageLookupByLibrary.simpleMessage("请检查并删除您认为重复的项目。"), @@ -1098,7 +1122,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("在照片的一定半径内拍摄的几组照片"), "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage("邀请他人,您将在此看到他们分享的所有照片"), - "searchResultCount": m48, + "searchResultCount": m50, "security": MessageLookupByLibrary.simpleMessage("安全"), "selectALocation": MessageLookupByLibrary.simpleMessage("选择一个位置"), "selectALocationFirst": @@ -1118,8 +1142,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("所选文件夹将被加密并备份"), "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": MessageLookupByLibrary.simpleMessage("所选项目将从所有相册中删除并移动到回收站。"), - "selectedPhotos": m49, - "selectedPhotosWithYours": m50, + "selectedPhotos": m1, + "selectedPhotosWithYours": m51, "send": MessageLookupByLibrary.simpleMessage("发送"), "sendEmail": MessageLookupByLibrary.simpleMessage("发送电子邮件"), "sendInvite": MessageLookupByLibrary.simpleMessage("发送邀请"), @@ -1141,10 +1165,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("打开相册并点击右上角的分享按钮进行分享"), "shareAnAlbumNow": MessageLookupByLibrary.simpleMessage("立即分享相册"), "shareLink": MessageLookupByLibrary.simpleMessage("分享链接"), - "shareMyVerificationID": m51, + "shareMyVerificationID": m52, "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage("仅与您想要的人分享"), - "shareTextConfirmOthersVerificationID": m52, + "shareTextConfirmOthersVerificationID": m2, "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage("下载 Ente,让我们轻松共享高质量的原始照片和视频"), "shareTextReferralCode": m53, @@ -1276,7 +1300,7 @@ class MessageLookup extends MessageLookupByLibrary { "thisWillRemovePublicLinksOfAllSelectedQuickLinks": MessageLookupByLibrary.simpleMessage("这将删除所有选定的快速链接的公共链接。"), "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": - MessageLookupByLibrary.simpleMessage("要启用应用锁,请在系统设置中设置设备密码或屏幕锁定。"), + MessageLookupByLibrary.simpleMessage("要启用应用锁,请在系统设置中设置设备密码或屏幕锁。"), "toHideAPhotoOrVideo": MessageLookupByLibrary.simpleMessage("隐藏照片或视频"), "toResetVerifyEmail": MessageLookupByLibrary.simpleMessage("要重置您的密码,请先验证您的电子邮件。"), @@ -1305,6 +1329,8 @@ class MessageLookup extends MessageLookupByLibrary { "unarchive": MessageLookupByLibrary.simpleMessage("取消存档"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("取消存档相册"), "unarchiving": MessageLookupByLibrary.simpleMessage("正在取消存档..."), + "unavailableReferralCode": + MessageLookupByLibrary.simpleMessage("抱歉,此代码不可用。"), "uncategorized": MessageLookupByLibrary.simpleMessage("未分类的"), "unhide": MessageLookupByLibrary.simpleMessage("取消隐藏"), "unhideToAlbum": MessageLookupByLibrary.simpleMessage("取消隐藏到相册"), @@ -1353,7 +1379,7 @@ class MessageLookup extends MessageLookupByLibrary { "viewAllExifData": MessageLookupByLibrary.simpleMessage("查看所有 EXIF 数据"), "viewLargeFiles": MessageLookupByLibrary.simpleMessage("大文件"), "viewLargeFilesDesc": - MessageLookupByLibrary.simpleMessage("查看占用存储空间最多的文件"), + MessageLookupByLibrary.simpleMessage("查看占用存储空间最多的文件。"), "viewLogs": MessageLookupByLibrary.simpleMessage("查看日志"), "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("查看恢复密钥"), "viewer": MessageLookupByLibrary.simpleMessage("查看者"), diff --git a/mobile/lib/generated/l10n.dart b/mobile/lib/generated/l10n.dart index 479a187c97..e88b25f990 100644 --- a/mobile/lib/generated/l10n.dart +++ b/mobile/lib/generated/l10n.dart @@ -9502,17 +9502,34 @@ class AppLocalizationDelegate extends LocalizationsDelegate { List get supportedLocales { return const [ Locale.fromSubtags(languageCode: 'en'), + Locale.fromSubtags(languageCode: 'ar'), + Locale.fromSubtags(languageCode: 'bg'), + Locale.fromSubtags(languageCode: 'ca'), Locale.fromSubtags(languageCode: 'cs'), + Locale.fromSubtags(languageCode: 'da'), Locale.fromSubtags(languageCode: 'de'), + Locale.fromSubtags(languageCode: 'el'), Locale.fromSubtags(languageCode: 'es'), + Locale.fromSubtags(languageCode: 'et'), + Locale.fromSubtags(languageCode: 'fa'), Locale.fromSubtags(languageCode: 'fr'), + Locale.fromSubtags(languageCode: 'gu'), + Locale.fromSubtags(languageCode: 'he'), + Locale.fromSubtags(languageCode: 'hi'), + Locale.fromSubtags(languageCode: 'id'), Locale.fromSubtags(languageCode: 'it'), + Locale.fromSubtags(languageCode: 'ja'), + Locale.fromSubtags(languageCode: 'km'), Locale.fromSubtags(languageCode: 'ko'), Locale.fromSubtags(languageCode: 'nl'), Locale.fromSubtags(languageCode: 'no'), Locale.fromSubtags(languageCode: 'pl'), Locale.fromSubtags(languageCode: 'pt'), Locale.fromSubtags(languageCode: 'ru'), + Locale.fromSubtags(languageCode: 'sv'), + Locale.fromSubtags(languageCode: 'te'), + Locale.fromSubtags(languageCode: 'th'), + Locale.fromSubtags(languageCode: 'ti'), Locale.fromSubtags(languageCode: 'tr'), Locale.fromSubtags(languageCode: 'zh'), ]; diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index b13a3237f0..1852638d13 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -12,7 +12,7 @@ description: ente photos application # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 0.9.30+930 +version: 0.9.31+931 publish_to: none environment: From b9dd371676a3d3cd6591f72c78c4234ba528db67 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 18:13:25 +0530 Subject: [PATCH 044/275] [mob] bump version --- mobile/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index 1852638d13..b13a3237f0 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -12,7 +12,7 @@ description: ente photos application # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 0.9.31+931 +version: 0.9.30+930 publish_to: none environment: From 15ba2dd2970d210dc3884d9ad8a6232447bb88d0 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 13:50:45 +0530 Subject: [PATCH 045/275] Start working on clustering again --- web/apps/photos/src/services/searchService.ts | 3 ++- web/packages/new/photos/services/ml/index.ts | 17 +++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/web/apps/photos/src/services/searchService.ts b/web/apps/photos/src/services/searchService.ts index 02a0062270..bbf10fde0b 100644 --- a/web/apps/photos/src/services/searchService.ts +++ b/web/apps/photos/src/services/searchService.ts @@ -6,6 +6,7 @@ import { isMLEnabled, isMLSupported, mlStatusSnapshot, + wipClusterEnable, } from "@/new/photos/services/ml"; import { parseDateComponents } from "@/new/photos/services/search"; import type { @@ -341,8 +342,8 @@ function convertSuggestionToSearchQuery(option: Suggestion): Search { // let done = false; // eslint-disable-next-line @typescript-eslint/no-unused-vars async function getAllPeople(_limit: number = undefined) { + if (!(await wipClusterEnable())) return []; return []; - // if (!(await wipClusterEnable())) return []; // if (done) return []; // done = true; diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 20e8f995cd..7c3cc669f3 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -6,6 +6,7 @@ import { isDesktop } from "@/base/app"; import { assertionFailed } from "@/base/assert"; import { blobCache } from "@/base/blob-cache"; import { ensureElectron } from "@/base/electron"; +import { isDevBuild } from "@/base/env"; import log from "@/base/log"; import type { Electron } from "@/base/types/ipc"; import { ComlinkWorker } from "@/base/worker/comlink-worker"; @@ -14,6 +15,7 @@ import type { EnteFile } from "@/new/photos/types/file"; import { ensure } from "@/utils/ensure"; import { throttled } from "@/utils/promise"; import { proxy, transfer } from "comlink"; +import { isInternalUser } from "../feature-flags"; import { getRemoteFlag, updateRemoteFlag } from "../remote-store"; import type { UploadItem } from "../upload/types"; import { regenerateFaceCrops } from "./crop"; @@ -318,14 +320,13 @@ export const indexNewUpload = (enteFile: EnteFile, uploadItem: UploadItem) => { // // TODO-Cluster temporary import here // let last: SearchPerson[] | undefined; -// /** -// * WIP! Don't enable, dragon eggs are hatching here. -// */ -// export const wipClusterEnable = async () => { -// if (!process.env.NEXT_PUBLIC_ENTE_WIP_CL) return false; -// if (!isDevBuild || !(await isInternalUser())) return false; -// return true; -// }; +/** + * WIP! Don't enable, dragon eggs are hatching here. + */ +export const wipClusterEnable = async () => + process.env.NEXT_PUBLIC_ENTE_WIP_CL && + isDevBuild && + (await isInternalUser()); // export const wipCluster = async () => { // if (!(await wipClusterEnable())) return; From 3f12ff2830122b568dfef00418ded3db202f8597 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 14:01:51 +0530 Subject: [PATCH 046/275] Opt --- .../new/photos/components/MLSettings.tsx | 22 ++++++++++++++++++- web/packages/new/photos/services/ml/index.ts | 4 ++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/web/packages/new/photos/components/MLSettings.tsx b/web/packages/new/photos/components/MLSettings.tsx index 55fc07c466..f6ed650a1f 100644 --- a/web/packages/new/photos/components/MLSettings.tsx +++ b/web/packages/new/photos/components/MLSettings.tsx @@ -1,12 +1,14 @@ import { EnteDrawer } from "@/base/components/EnteDrawer"; -import { MenuItemGroup } from "@/base/components/Menu"; +import { MenuItemGroup, MenuSectionTitle } from "@/base/components/Menu"; import { Titlebar } from "@/base/components/Titlebar"; +import { ut } from "@/base/i18n"; import log from "@/base/log"; import { disableML, enableML, mlStatusSnapshot, mlStatusSubscribe, + wipClusterEnable, type MLStatus, } from "@/new/photos/services/ml"; import EnteSpinner from "@ente/shared/components/EnteSpinner"; @@ -295,8 +297,11 @@ const ManageML: React.FC = ({ onDisableML, setDialogBoxAttributesV2, }) => { + const [showClusterOpt, setShowClusterOpt] = useState(false); const { phase, nSyncedFiles, nTotalFiles } = mlStatus; + useEffect(() => void wipClusterEnable().then(setShowClusterOpt), []); + let status: string; switch (phase) { case "scheduled": @@ -372,6 +377,21 @@ const ManageML: React.FC = ({ + {showClusterOpt && ( + + + + + + + )} ); }; diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 7c3cc669f3..86fb3fdc75 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -323,8 +323,8 @@ export const indexNewUpload = (enteFile: EnteFile, uploadItem: UploadItem) => { /** * WIP! Don't enable, dragon eggs are hatching here. */ -export const wipClusterEnable = async () => - process.env.NEXT_PUBLIC_ENTE_WIP_CL && +export const wipClusterEnable = async (): Promise => + !!process.env.NEXT_PUBLIC_ENTE_WIP_CL && isDevBuild && (await isInternalUser()); From 1a9a36cb4cd9b51d2edb288b260b59d8a721c029 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 14:39:48 +0530 Subject: [PATCH 047/275] Scaffold --- .../new/photos/components/MLSettings.tsx | 14 ++- web/packages/new/photos/services/ml/index.ts | 106 ++++++++++-------- 2 files changed, 69 insertions(+), 51 deletions(-) diff --git a/web/packages/new/photos/components/MLSettings.tsx b/web/packages/new/photos/components/MLSettings.tsx index f6ed650a1f..0871a2b9f0 100644 --- a/web/packages/new/photos/components/MLSettings.tsx +++ b/web/packages/new/photos/components/MLSettings.tsx @@ -1,13 +1,14 @@ import { EnteDrawer } from "@/base/components/EnteDrawer"; import { MenuItemGroup, MenuSectionTitle } from "@/base/components/Menu"; import { Titlebar } from "@/base/components/Titlebar"; -import { ut } from "@/base/i18n"; +import { pt, ut } from "@/base/i18n"; import log from "@/base/log"; import { disableML, enableML, mlStatusSnapshot, mlStatusSubscribe, + wipCluster, wipClusterEnable, type MLStatus, } from "@/new/photos/services/ml"; @@ -313,7 +314,10 @@ const ManageML: React.FC = ({ case "indexing": status = t("indexing_status_running"); break; - // TODO: Clustering + case "clustering": + // TODO-Cluster + status = pt("Grouping faces"); + break; default: status = t("indexing_status_done"); break; @@ -334,6 +338,8 @@ const ManageML: React.FC = ({ }); }; + const wipClusterNow = () => void wipCluster(); + return ( @@ -382,12 +388,12 @@ const ManageML: React.FC = ({ diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 86fb3fdc75..6673ba9a16 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -13,7 +13,7 @@ import { ComlinkWorker } from "@/base/worker/comlink-worker"; import { FileType } from "@/media/file-type"; import type { EnteFile } from "@/new/photos/types/file"; import { ensure } from "@/utils/ensure"; -import { throttled } from "@/utils/promise"; +import { throttled, wait } from "@/utils/promise"; import { proxy, transfer } from "comlink"; import { isInternalUser } from "../feature-flags"; import { getRemoteFlag, updateRemoteFlag } from "../remote-store"; @@ -317,9 +317,6 @@ export const indexNewUpload = (enteFile: EnteFile, uploadItem: UploadItem) => { void worker().then((w) => w.onUpload(enteFile, uploadItem)); }; -// // TODO-Cluster temporary import here -// let last: SearchPerson[] | undefined; - /** * WIP! Don't enable, dragon eggs are hatching here. */ @@ -328,54 +325,67 @@ export const wipClusterEnable = async (): Promise => isDevBuild && (await isInternalUser()); -// export const wipCluster = async () => { -// if (!(await wipClusterEnable())) return; +// // TODO-Cluster temporary import here +// let last: SearchPerson[] | undefined; +let _wip_isClustering = false; -// if (last) return last; +export const wipCluster = async () => { + if (!(await wipClusterEnable())) return; -// const { clusters, cgroups } = await clusterFaces(await faceIndexes()); -// const clusterByID = new Map( -// clusters.map((cluster) => [cluster.id, cluster]), -// ); + log.info("clustering"); + _wip_isClustering = true; + triggerStatusUpdate(); -// const localFiles = await getAllLocalFiles(); -// const localFilesByID = new Map(localFiles.map((f) => [f.id, f])); + await wait(2000); -// const result: SearchPerson[] = []; -// for (const cgroup of cgroups) { -// let avatarFaceID = cgroup.avatarFaceID; -// // TODO-Cluster -// // Temp -// if (!avatarFaceID) { -// // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -// avatarFaceID = cgroup.clusterIDs -// .map((id) => clusterByID.get(id)) -// .flatMap((cluster) => cluster?.faceIDs ?? [])[0]!; -// } -// cgroup.clusterIDs; -// const avatarFaceFileID = fileIDFromFaceID(avatarFaceID); -// const avatarFaceFile = localFilesByID.get(avatarFaceFileID ?? 0); -// if (!avatarFaceFileID || !avatarFaceFile) { -// assertionFailed(`Face ID ${avatarFaceID} without local file`); -// continue; -// } -// const files = cgroup.clusterIDs -// .map((id) => clusterByID.get(id)) -// .flatMap((cluster) => cluster?.faceIDs ?? []) -// .map((faceID) => fileIDFromFaceID(faceID)) -// .filter((fileID) => fileID !== undefined); -// result.push({ -// id: cgroup.id, -// name: cgroup.name, -// files, -// displayFaceID: avatarFaceID, -// displayFaceFile: avatarFaceFile, -// }); -// } + // if (last) return last; -// last = result; -// return result; -// }; + // const { clusters, cgroups } = await clusterFaces(await faceIndexes()); + // const clusterByID = new Map( + // clusters.map((cluster) => [cluster.id, cluster]), + // ); + + // const localFiles = await getAllLocalFiles(); + // const localFilesByID = new Map(localFiles.map((f) => [f.id, f])); + + // const result: SearchPerson[] = []; + // for (const cgroup of cgroups) { + // let avatarFaceID = cgroup.avatarFaceID; + // // TODO-Cluster + // // Temp + // if (!avatarFaceID) { + // // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + // avatarFaceID = cgroup.clusterIDs + // .map((id) => clusterByID.get(id)) + // .flatMap((cluster) => cluster?.faceIDs ?? [])[0]!; + // } + // cgroup.clusterIDs; + // const avatarFaceFileID = fileIDFromFaceID(avatarFaceID); + // const avatarFaceFile = localFilesByID.get(avatarFaceFileID ?? 0); + // if (!avatarFaceFileID || !avatarFaceFile) { + // assertionFailed(`Face ID ${avatarFaceID} without local file`); + // continue; + // } + // const files = cgroup.clusterIDs + // .map((id) => clusterByID.get(id)) + // .flatMap((cluster) => cluster?.faceIDs ?? []) + // .map((faceID) => fileIDFromFaceID(faceID)) + // .filter((fileID) => fileID !== undefined); + // result.push({ + // id: cgroup.id, + // name: cgroup.name, + // files, + // displayFaceID: avatarFaceID, + // displayFaceFile: avatarFaceFile, + // }); + // } + + _wip_isClustering = false; + triggerStatusUpdate(); + + // last = result; + // return result; +}; export type MLStatus = | { phase: "disabled" /* The ML remote flag is off */ } @@ -476,6 +486,8 @@ const getMLStatus = async (): Promise => { const state = await (await worker()).state; if (state == "indexing" || state == "fetching") { phase = state; + } else if (_wip_isClustering) { + phase = "clustering"; } else if (state == "init" || indexableCount > 0) { phase = "scheduled"; } else { From 52bfe0310acf3677e7abb8096db9110374d6d636 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 18:28:52 +0530 Subject: [PATCH 048/275] Algo --- web/apps/photos/src/services/searchService.ts | 10 +- .../new/photos/components/MLSettings.tsx | 2 +- web/packages/new/photos/services/ml/index.ts | 100 ++++++++++-------- 3 files changed, 61 insertions(+), 51 deletions(-) diff --git a/web/apps/photos/src/services/searchService.ts b/web/apps/photos/src/services/searchService.ts index bbf10fde0b..76b1d5cb2b 100644 --- a/web/apps/photos/src/services/searchService.ts +++ b/web/apps/photos/src/services/searchService.ts @@ -6,7 +6,7 @@ import { isMLEnabled, isMLSupported, mlStatusSnapshot, - wipClusterEnable, + wipSearchPersons, } from "@/new/photos/services/ml"; import { parseDateComponents } from "@/new/photos/services/search"; import type { @@ -339,11 +339,9 @@ function convertSuggestionToSearchQuery(option: Suggestion): Search { } } -// let done = false; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -async function getAllPeople(_limit: number = undefined) { - if (!(await wipClusterEnable())) return []; - return []; +async function getAllPeople(limit: number = undefined) { + return (await wipSearchPersons()).slice(0, limit); + // TODO-Clustetr // if (done) return []; // done = true; diff --git a/web/packages/new/photos/components/MLSettings.tsx b/web/packages/new/photos/components/MLSettings.tsx index 0871a2b9f0..43dc1231e3 100644 --- a/web/packages/new/photos/components/MLSettings.tsx +++ b/web/packages/new/photos/components/MLSettings.tsx @@ -393,7 +393,7 @@ const ManageML: React.FC = ({ diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 6673ba9a16..192f544dd9 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -17,11 +17,19 @@ import { throttled, wait } from "@/utils/promise"; import { proxy, transfer } from "comlink"; import { isInternalUser } from "../feature-flags"; import { getRemoteFlag, updateRemoteFlag } from "../remote-store"; +import type { SearchPerson } from "../search/types"; import type { UploadItem } from "../upload/types"; +import { clusterFaces } from "./cluster-new"; import { regenerateFaceCrops } from "./crop"; -import { clearMLDB, faceIndex, indexableAndIndexedCounts } from "./db"; +import { + clearMLDB, + faceIndex, + faceIndexes, + indexableAndIndexedCounts, +} from "./db"; import { MLWorker } from "./worker"; import type { CLIPMatches } from "./worker-types"; +import { getAllLocalFiles } from "../files"; /** * Internal state of the ML subsystem. @@ -325,9 +333,14 @@ export const wipClusterEnable = async (): Promise => isDevBuild && (await isInternalUser()); -// // TODO-Cluster temporary import here -// let last: SearchPerson[] | undefined; +// // TODO-Cluster temporary state here let _wip_isClustering = false; +let _wip_searchPersons: SearchPerson[] | undefined; + +export const wipSearchPersons = async () => { + if (!(await wipClusterEnable())) return []; + return _wip_searchPersons ?? []; +}; export const wipCluster = async () => { if (!(await wipClusterEnable())) return; @@ -337,54 +350,53 @@ export const wipCluster = async () => { triggerStatusUpdate(); await wait(2000); + _wip_searchPersons = undefined; - // if (last) return last; + const { clusters, cgroups } = await clusterFaces(await faceIndexes()); + const clusterByID = new Map( + clusters.map((cluster) => [cluster.id, cluster]), + ); - // const { clusters, cgroups } = await clusterFaces(await faceIndexes()); - // const clusterByID = new Map( - // clusters.map((cluster) => [cluster.id, cluster]), - // ); + const localFiles = await getAllLocalFiles(); + const localFilesByID = new Map(localFiles.map((f) => [f.id, f])); - // const localFiles = await getAllLocalFiles(); - // const localFilesByID = new Map(localFiles.map((f) => [f.id, f])); + const result: SearchPerson[] = []; + for (const cgroup of cgroups) { + let avatarFaceID = cgroup.avatarFaceID; + // TODO-Cluster + // Temp + if (!avatarFaceID) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + avatarFaceID = cgroup.clusterIDs + .map((id) => clusterByID.get(id)) + .flatMap((cluster) => cluster?.faceIDs ?? [])[0]!; + } + cgroup.clusterIDs; + const avatarFaceFileID = fileIDFromFaceID(avatarFaceID); + const avatarFaceFile = localFilesByID.get(avatarFaceFileID ?? 0); + if (!avatarFaceFileID || !avatarFaceFile) { + assertionFailed(`Face ID ${avatarFaceID} without local file`); + continue; + } + const files = cgroup.clusterIDs + .map((id) => clusterByID.get(id)) + .flatMap((cluster) => cluster?.faceIDs ?? []) + .map((faceID) => fileIDFromFaceID(faceID)) + .filter((fileID) => fileID !== undefined); + result.push({ + id: cgroup.id, + name: cgroup.name, + files, + displayFaceID: avatarFaceID, + displayFaceFile: avatarFaceFile, + }); + } - // const result: SearchPerson[] = []; - // for (const cgroup of cgroups) { - // let avatarFaceID = cgroup.avatarFaceID; - // // TODO-Cluster - // // Temp - // if (!avatarFaceID) { - // // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - // avatarFaceID = cgroup.clusterIDs - // .map((id) => clusterByID.get(id)) - // .flatMap((cluster) => cluster?.faceIDs ?? [])[0]!; - // } - // cgroup.clusterIDs; - // const avatarFaceFileID = fileIDFromFaceID(avatarFaceID); - // const avatarFaceFile = localFilesByID.get(avatarFaceFileID ?? 0); - // if (!avatarFaceFileID || !avatarFaceFile) { - // assertionFailed(`Face ID ${avatarFaceID} without local file`); - // continue; - // } - // const files = cgroup.clusterIDs - // .map((id) => clusterByID.get(id)) - // .flatMap((cluster) => cluster?.faceIDs ?? []) - // .map((faceID) => fileIDFromFaceID(faceID)) - // .filter((fileID) => fileID !== undefined); - // result.push({ - // id: cgroup.id, - // name: cgroup.name, - // files, - // displayFaceID: avatarFaceID, - // displayFaceFile: avatarFaceFile, - // }); - // } + const searchPersons = result.sort((a, b) => b.files.length - a.files.length); _wip_isClustering = false; + _wip_searchPersons = searchPersons; triggerStatusUpdate(); - - // last = result; - // return result; }; export type MLStatus = From 1fcc425779d8a1bf83f94f8dddbf45cb41fc8ae8 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 18:31:07 +0530 Subject: [PATCH 049/275] Integrate --- web/packages/new/photos/services/ml/index.ts | 14 +++++++------- web/packages/new/photos/services/ml/worker.ts | 16 ++++++++-------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 192f544dd9..6ad354a25a 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -16,6 +16,7 @@ import { ensure } from "@/utils/ensure"; import { throttled, wait } from "@/utils/promise"; import { proxy, transfer } from "comlink"; import { isInternalUser } from "../feature-flags"; +import { getAllLocalFiles } from "../files"; import { getRemoteFlag, updateRemoteFlag } from "../remote-store"; import type { SearchPerson } from "../search/types"; import type { UploadItem } from "../upload/types"; @@ -29,7 +30,6 @@ import { } from "./db"; import { MLWorker } from "./worker"; import type { CLIPMatches } from "./worker-types"; -import { getAllLocalFiles } from "../files"; /** * Internal state of the ML subsystem. @@ -353,12 +353,10 @@ export const wipCluster = async () => { _wip_searchPersons = undefined; const { clusters, cgroups } = await clusterFaces(await faceIndexes()); - const clusterByID = new Map( - clusters.map((cluster) => [cluster.id, cluster]), - ); + const clusterByID = new Map(clusters.map((c) => [c.id, c])); const localFiles = await getAllLocalFiles(); - const localFilesByID = new Map(localFiles.map((f) => [f.id, f])); + const localFileByID = new Map(localFiles.map((f) => [f.id, f])); const result: SearchPerson[] = []; for (const cgroup of cgroups) { @@ -373,7 +371,7 @@ export const wipCluster = async () => { } cgroup.clusterIDs; const avatarFaceFileID = fileIDFromFaceID(avatarFaceID); - const avatarFaceFile = localFilesByID.get(avatarFaceFileID ?? 0); + const avatarFaceFile = localFileByID.get(avatarFaceFileID ?? 0); if (!avatarFaceFileID || !avatarFaceFile) { assertionFailed(`Face ID ${avatarFaceID} without local file`); continue; @@ -392,7 +390,9 @@ export const wipCluster = async () => { }); } - const searchPersons = result.sort((a, b) => b.files.length - a.files.length); + const searchPersons = result.sort( + (a, b) => b.files.length - a.files.length, + ); _wip_isClustering = false; _wip_searchPersons = searchPersons; diff --git a/web/packages/new/photos/services/ml/worker.ts b/web/packages/new/photos/services/ml/worker.ts index fdcb1ac595..f21f58d85a 100644 --- a/web/packages/new/photos/services/ml/worker.ts +++ b/web/packages/new/photos/services/ml/worker.ts @@ -246,14 +246,14 @@ export class MLWorker { private async backfillQ() { const userID = ensure(await getKVN("userID")); // Find files that our local DB thinks need syncing. - const filesByID = await syncWithLocalFilesAndGetFilesToIndex( + const fileByID = await syncWithLocalFilesAndGetFilesToIndex( userID, 200, ); - if (!filesByID.size) return []; + if (!fileByID.size) return []; // Fetch their existing ML data (if any). - const mlDataByID = await fetchMLData(filesByID); + const mlDataByID = await fetchMLData(fileByID); // If the number of files for which remote gave us data is more than 50% // of what we asked of it, assume we are "fetching", not "indexing". @@ -263,10 +263,10 @@ export class MLWorker { if (this.state != "indexing" && this.state != "fetching") assertionFailed(`Unexpected state ${this.state}`); this.state = - mlDataByID.size * 2 > filesByID.size ? "fetching" : "indexing"; + mlDataByID.size * 2 > fileByID.size ? "fetching" : "indexing"; // Return files after annotating them with their existing ML data. - return Array.from(filesByID, ([id, file]) => ({ + return Array.from(fileByID, ([id, file]) => ({ enteFile: file, uploadItem: undefined, remoteMLData: mlDataByID.get(id), @@ -364,20 +364,20 @@ const syncWithLocalFilesAndGetFilesToIndex = async ( const isIndexable = (f: EnteFile) => f.ownerID == userID; const localFiles = await getAllLocalFiles(); - const localFilesByID = new Map( + const localFileByID = new Map( localFiles.filter(isIndexable).map((f) => [f.id, f]), ); const localTrashFileIDs = (await getLocalTrashedFiles()).map((f) => f.id); await updateAssumingLocalFiles( - Array.from(localFilesByID.keys()), + Array.from(localFileByID.keys()), localTrashFileIDs, ); const fileIDsToIndex = await indexableFileIDs(count); return new Map( - fileIDsToIndex.map((id) => [id, ensure(localFilesByID.get(id))]), + fileIDsToIndex.map((id) => [id, ensure(localFileByID.get(id))]), ); }; From 92859aa748a1c7601222a3a413bfb687794ab3b6 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 18:44:51 +0530 Subject: [PATCH 050/275] Doc --- .../new/photos/services/ml/cluster-new.ts | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index ff28b75260..fdd83809de 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -60,15 +60,17 @@ export interface CGroup { /** * A nanoid for this cluster group. * - * This is the ID of the "cgroup" user entity, it is not contained as part - * of the group entity payload itself. + * This is the ID of the "cgroup" user entity (the envelope), and it is not + * contained as part of the group entity payload itself. */ id: string; /** * A name assigned by the user to this cluster group. * - * This should be set to an empty string for an unnamed cluster that was - * hidden. + * The client should handle both empty strings and undefined as indicating a + * cgroup without a name. When the client needs to set this to an "empty" + * value, which happens when hiding an unnamed cluster, it should it to an + * empty string. That is, expect `"" | undefined`, but set `""`. */ name: string | undefined; /** @@ -92,13 +94,20 @@ export interface CGroup { * The ID of the face that should be used as the cover photo for this * cluster group (if the user has set one). * - * {@link avatarFaceID} is the user selected face. {@link displayFaceID} is - * the automatic placeholder. + * This is similar to the [@link displayFaceID}, the difference being: + * + * - {@link avatarFaceID} is the face selected by the user. + * + * - {@link displayFaceID} is the automatic placeholder, and only comes + * into effect if the user has not explicitly selected a face. */ avatarFaceID: string | undefined; /** * Locally determined ID of the "best" face that should be used as the * display face, to represent this cluster group in the UI. + * + * This property is not synced with remote. For more details, see + * {@link avatarFaceID}. */ displayFaceID: string | undefined; } @@ -108,16 +117,16 @@ export interface CGroup { * * [Note: Face clustering algorithm] * - * A (cluster) group consists of clusters, each of which itself is a set of - * faces. + * A cgroup (cluster group) consists of clusters, each of which itself is a set + * of faces. * - * The clusters are generated using locally by clients using the following - * (pseudo-) algorithm: + * cgroup << cluster << face + * + * The clusters are generated locally by clients using the following algorithm: * * 1. clusters = [] initially, or fetched from remote. * - * 2. For each face, find its nearest neighbour in the embedding space from - * amongst the faces that have already been clustered. + * 2. For each face, find its nearest neighbour in the embedding space. * * 3. If no such neighbour is found within our threshold, create a new cluster. * @@ -126,12 +135,13 @@ export interface CGroup { * This user can then tweak the output of the algorithm by performing the * following actions to the list of clusters that they can see: * - * - They can provide a name for a cluster. This upgrades a cluster into a - * "cgroup", which then gets synced via remote to all their devices. + * - They can provide a name for a cluster ("name a person"). This upgrades a + * cluster into a "cgroup", which is an entity that gets synced via remote + * to the user's other clients. * - * - They can attach more clusters to a cgroup. + * - They can attach more clusters to a cgroup ("merge clusters") * - * - They can remove a cluster from a cgroup. + * - They can remove a cluster from a cgroup ("break clusters"). * * After clustering, we also do some routine cleanup. Faces belonging to files * that have been deleted (including those in Trash) should be pruned off. @@ -140,8 +150,8 @@ export interface CGroup { * In particular, the same face ID can be in different clusters. In such cases * we should assign it arbitrarily assign it to the last cluster we find it in. * Such leeway is intentionally provided to allow clients some slack in how they - * implement the sync without making an blocking API request for every user - * interaction. + * implement the sync without needing to make an blocking API request for every + * user interaction. */ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { const t = Date.now(); @@ -278,7 +288,7 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { /** * A generator function that returns a stream of {faceID, embedding} values, - * flattening all the all the faces present in the given {@link faceIndices}. + * flattening all the the faces present in the given {@link faceIndices}. */ function* enumerateFaces(faceIndices: FaceIndex[]) { for (const fi of faceIndices) { From 8397ed52ce8ae41a7730b1b2eb1a2fdad83ac76a Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 19:14:34 +0530 Subject: [PATCH 051/275] Tweaks --- .../new/photos/services/ml/cluster-new.ts | 63 ++++++++++--------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index fdd83809de..a64ce4a43d 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -163,19 +163,17 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { // or fetched from remote). const clusters = await faceClusters(); - // For fast reverse lookup - map from cluster ids to the index in the + // For fast reverse lookup - map from cluster ids to their index in the // clusters array. const clusterIndexForClusterID = new Map(clusters.map((c, i) => [c.id, i])); // For fast reverse lookup - map from face ids to the id of the cluster to // which they belong. const clusterIDForFaceID = new Map( - clusters.flatMap((c) => - c.faceIDs.map((faceID) => [faceID, c.id] as const), - ), + clusters.flatMap((c) => c.faceIDs.map((id) => [id, c.id] as const)), ); - // New cluster ID generator function. + // A function to generate new cluster IDs. const newClusterID = () => newNonSecureID("cluster_"); // For each face, @@ -247,40 +245,45 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { // Prune too small clusters. const validClusters = clusters.filter(({ faceIDs }) => faceIDs.length > 1); + let cgroups = await clusterGroups(); + + // TODO-Cluster - Currently we're not syncing with remote or saving anything + // locally, so cgroups will be empty. Create a temporary (unsaved, unsynced) + // cgroup, one per cluster. + cgroups = cgroups.concat( + validClusters.map((c) => ({ + id: c.id, + name: undefined, + clusterIDs: [c.id], + isHidden: false, + avatarFaceID: undefined, + displayFaceID: undefined, + })), + ); + // For each cluster group, use the highest scoring face in any of its // clusters as its display face. - const faceForFaceID = new Map(faces.map((f) => [f.faceID, f])); - const cgroups = await clusterGroups(); - for (const cgroup of cgroups) { - cgroup.avatarFaceID = cgroup.clusterIDs + cgroup.displayFaceID = cgroup.clusterIDs .map((clusterID) => clusterIndexForClusterID.get(clusterID)) - .map((clusterIndex) => - clusterIndex ? clusters[clusterIndex] : undefined, - ) - .filter((cluster) => !!cluster) - .flatMap((cluster) => cluster.faceIDs) - .map((id) => faceForFaceID.get(id)) + .flatMap((i) => (i ? clusters[i]?.faceIDs : undefined) ?? []) + .map((faceID) => faceForFaceID.get(faceID)) .filter((face) => !!face) - .reduce((topFace, face) => - topFace.score > face.score ? topFace : face, + .reduce((max, face) => + max.score > face.score ? max : face, ).faceID; } - log.debug(() => [ - "ml/cluster", - { - faces, - validClusters, - clusterIndexForClusterID, - clusterIDForFaceID, - cgroups, - }, - ]); - log.debug( - () => - `Clustered ${faces.length} faces into ${validClusters.length} clusters (${Date.now() - t} ms)`, + log.info("ml/cluster", { + faces, + validClusters, + clusterIndexForClusterID, + clusterIDForFaceID, + cgroups, + }); + log.info( + `Clustered ${faces.length} faces into ${validClusters.length} clusters (${Date.now() - t} ms)`, ); return { clusters: validClusters, cgroups }; From c4f81f55d1dc6a14697106f4cfecabb82d607e86 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 19:18:30 +0530 Subject: [PATCH 052/275] Fix --- web/packages/new/photos/services/ml/cluster-new.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index a64ce4a43d..2185745a2a 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -226,19 +226,19 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { id: newClusterID(), faceIDs: [faceID, nn.faceID], }; - clusters.push(cluster); clusterIndexForClusterID.set(cluster.id, clusters.length); clusterIDForFaceID.set(faceID, cluster.id); clusterIDForFaceID.set(nn.faceID, cluster.id); + clusters.push(cluster); } } else { // We didn't find a neighbour within the threshold. Create a new // cluster with only this face. const cluster = { id: newClusterID(), faceIDs: [faceID] }; - clusters.push(cluster); clusterIndexForClusterID.set(cluster.id, clusters.length); clusterIDForFaceID.set(faceID, cluster.id); + clusters.push(cluster); } } From ca9c244182c01d0f66faaffa051c5f0d0f8a6584 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 19:27:31 +0530 Subject: [PATCH 053/275] Split --- web/packages/new/photos/services/ml/index.ts | 67 ++++++++++---------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 6ad354a25a..846b48c62f 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -13,14 +13,14 @@ import { ComlinkWorker } from "@/base/worker/comlink-worker"; import { FileType } from "@/media/file-type"; import type { EnteFile } from "@/new/photos/types/file"; import { ensure } from "@/utils/ensure"; -import { throttled, wait } from "@/utils/promise"; +import { throttled } from "@/utils/promise"; import { proxy, transfer } from "comlink"; import { isInternalUser } from "../feature-flags"; import { getAllLocalFiles } from "../files"; import { getRemoteFlag, updateRemoteFlag } from "../remote-store"; import type { SearchPerson } from "../search/types"; import type { UploadItem } from "../upload/types"; -import { clusterFaces } from "./cluster-new"; +import { clusterFaces, type CGroup, type FaceCluster } from "./cluster-new"; import { regenerateFaceCrops } from "./crop"; import { clearMLDB, @@ -347,12 +347,21 @@ export const wipCluster = async () => { log.info("clustering"); _wip_isClustering = true; + _wip_searchPersons = undefined; triggerStatusUpdate(); - await wait(2000); - _wip_searchPersons = undefined; - const { clusters, cgroups } = await clusterFaces(await faceIndexes()); + const searchPersons = await convertToSearchPersons(clusters, cgroups); + + _wip_isClustering = false; + _wip_searchPersons = searchPersons; + triggerStatusUpdate(); +}; + +const convertToSearchPersons = async ( + clusters: FaceCluster[], + cgroups: CGroup[], +) => { const clusterByID = new Map(clusters.map((c) => [c.id, c])); const localFiles = await getAllLocalFiles(); @@ -360,43 +369,38 @@ export const wipCluster = async () => { const result: SearchPerson[] = []; for (const cgroup of cgroups) { - let avatarFaceID = cgroup.avatarFaceID; - // TODO-Cluster - // Temp - if (!avatarFaceID) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - avatarFaceID = cgroup.clusterIDs - .map((id) => clusterByID.get(id)) - .flatMap((cluster) => cluster?.faceIDs ?? [])[0]!; - } - cgroup.clusterIDs; - const avatarFaceFileID = fileIDFromFaceID(avatarFaceID); - const avatarFaceFile = localFileByID.get(avatarFaceFileID ?? 0); - if (!avatarFaceFileID || !avatarFaceFile) { - assertionFailed(`Face ID ${avatarFaceID} without local file`); + const displayFaceID = cgroup.displayFaceID; + if (!displayFaceID) { + // TODO-Cluster + assertionFailed(`cgroup ${cgroup.id} without displayFaceID`); continue; } - const files = cgroup.clusterIDs + + const displayFaceFileID = fileIDFromFaceID(displayFaceID); + if (!displayFaceFileID) continue; + + const displayFaceFile = localFileByID.get(displayFaceFileID); + if (!displayFaceFile) { + assertionFailed(`Face ID ${displayFaceFileID} without local file`); + continue; + } + + const fileIDs = cgroup.clusterIDs .map((id) => clusterByID.get(id)) .flatMap((cluster) => cluster?.faceIDs ?? []) .map((faceID) => fileIDFromFaceID(faceID)) .filter((fileID) => fileID !== undefined); + result.push({ id: cgroup.id, name: cgroup.name, - files, - displayFaceID: avatarFaceID, - displayFaceFile: avatarFaceFile, + files: [...new Set(fileIDs)], + displayFaceID, + displayFaceFile, }); } - const searchPersons = result.sort( - (a, b) => b.files.length - a.files.length, - ); - - _wip_isClustering = false; - _wip_searchPersons = searchPersons; - triggerStatusUpdate(); + return result.sort((a, b) => b.files.length - a.files.length); }; export type MLStatus = @@ -568,8 +572,7 @@ export const unidentifiedFaceIDs = async ( * Extract the fileID of the {@link EnteFile} to which the face belongs from its * faceID. */ -// TODO-Cluster: temporary export to supress linter -export const fileIDFromFaceID = (faceID: string) => { +const fileIDFromFaceID = (faceID: string) => { const fileID = parseInt(faceID.split("_")[0] ?? ""); if (isNaN(fileID)) { assertionFailed(`Ignoring attempt to parse invalid faceID ${faceID}`); From 8aac4bf55fc10b65de8ee1776f4fd9186dcf6148 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 19:50:39 +0530 Subject: [PATCH 054/275] Fix --- web/packages/new/photos/services/ml/cluster-new.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index 2185745a2a..ecd520c436 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -267,7 +267,8 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { for (const cgroup of cgroups) { cgroup.displayFaceID = cgroup.clusterIDs .map((clusterID) => clusterIndexForClusterID.get(clusterID)) - .flatMap((i) => (i ? clusters[i]?.faceIDs : undefined) ?? []) + .filter((i) => i !== undefined) /* 0 is a valid index */ + .flatMap((i) => clusters[i]?.faceIDs ?? []) .map((faceID) => faceForFaceID.get(faceID)) .filter((face) => !!face) .reduce((max, face) => @@ -278,8 +279,8 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { log.info("ml/cluster", { faces, validClusters, - clusterIndexForClusterID, - clusterIDForFaceID, + clusterIndexForClusterID: Object.fromEntries(clusterIndexForClusterID), + clusterIDForFaceID: Object.fromEntries(clusterIDForFaceID), cgroups, }); log.info( From b3d94e9bcfdddaa2a253b9e5bd03100f16939fa0 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Tue, 27 Aug 2024 19:51:28 +0530 Subject: [PATCH 055/275] [server] Minor copy change --- server/ente/admin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/ente/admin.go b/server/ente/admin.go index edff1f6a2a..6221ea8dc1 100644 --- a/server/ente/admin.go +++ b/server/ente/admin.go @@ -101,7 +101,7 @@ func (u SupportUpdateBonus) UpdateLog() string { if u.Testing { return fmt.Sprintf("SupportUpdateBonus: %s, storageInMB: %d, minute: %d", u.Action, u.StorageInMB, u.Minute) } else { - return fmt.Sprintf("BF_UPDATE: %s, storageInGB: %d, year: %d", u.Action, u.StorageInGB, u.Year) + return fmt.Sprintf("%s: %s, storageInGB: %d, year: %d", u.BonusType, u.Action, u.StorageInGB, u.Year) } } From cfe9178301c7f9603f380c0d86c1e2aa41924aa8 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 27 Aug 2024 20:00:38 +0530 Subject: [PATCH 056/275] Experiment to try and reduce the latency --- .github/workflows/web-lint.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/web-lint.yml b/.github/workflows/web-lint.yml index c64463384c..6655587175 100644 --- a/.github/workflows/web-lint.yml +++ b/.github/workflows/web-lint.yml @@ -2,10 +2,21 @@ name: "Lint (web)" on: # Run on every pull request (open or push to it) that changes web/ + # + # This is for running lints on pull requests from external contributors. pull_request: paths: - "web/**" - ".github/workflows/web-lint.yml" + # Run on every push (to a non-main branch) that changes web/ + # + # This reduces the delay in waiting for the pull_request to kick in for the + # PRs from existing contributors. + push: + branches-ignore: [main] + paths: + - "web/**" + - ".github/workflows/web-lint.yml" jobs: lint: From 0657b1600215422c3795873c55aaf3cf78310c59 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 09:19:31 +0530 Subject: [PATCH 057/275] Debugging page --- web/apps/photos/src/pages/cluster-debug.tsx | 254 ++++++++++++++++++ .../new/photos/components/MLSettings.tsx | 17 +- .../new/photos/services/ml/cluster-new.ts | 2 +- web/packages/new/photos/services/ml/index.ts | 33 +++ 4 files changed, 299 insertions(+), 7 deletions(-) create mode 100644 web/apps/photos/src/pages/cluster-debug.tsx diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx new file mode 100644 index 0000000000..d71b300647 --- /dev/null +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -0,0 +1,254 @@ +import { SelectionBar } from "@/base/components/Navbar"; +import { pt } from "@/base/i18n"; +import log from "@/base/log"; +import { wipClusterPageContents } from "@/new/photos/services/ml"; +import { EnteFile } from "@/new/photos/types/file"; +import { + FluidContainer, + VerticallyCentered, +} from "@ente/shared/components/Container"; +import EnteSpinner from "@ente/shared/components/EnteSpinner"; +import { PHOTOS_PAGES as PAGES } from "@ente/shared/constants/pages"; +import { CustomError } from "@ente/shared/error"; +import useMemoSingleThreaded from "@ente/shared/hooks/useMemoSingleThreaded"; +import BackButton from "@mui/icons-material/ArrowBackOutlined"; +import { Box, IconButton, styled } from "@mui/material"; +import Typography from "@mui/material/Typography"; +import { DedupePhotoList } from "components/PhotoList/dedupe"; +import PreviewCard from "components/pages/gallery/PreviewCard"; +import { ALL_SECTION } from "constants/collection"; +import { t } from "i18next"; +import { useRouter } from "next/router"; +import { AppContext } from "pages/_app"; +import { createContext, useContext, useEffect, useState } from "react"; +import AutoSizer from "react-virtualized-auto-sizer"; +import { getLocalCollections } from "services/collectionService"; +import { Duplicate } from "services/deduplicationService"; +import { + DeduplicateContextType, + DefaultDeduplicateContext, +} from "types/deduplicate"; +import { updateFileMsrcProps } from "utils/photoFrame"; + +const DeduplicateContext = createContext( + DefaultDeduplicateContext, +); + +const Info = styled("div")` + padding: 24px; + font-size: 18px; +`; + +// TODO-Cluster Temporary component for debugging +export default function Deduplicate() { + const { startLoading, finishLoading, showNavBar } = useContext(AppContext); + const [duplicates, setDuplicates] = useState(null); + const [collectionNameMap, setCollectionNameMap] = useState( + new Map(), + ); + + useEffect(() => { + showNavBar(true); + }, []); + + useEffect(() => { + syncWithRemote(); + }, []); + + const syncWithRemote = async () => { + startLoading(); + const collections = await getLocalCollections(); + const collectionNameMap = new Map(); + for (const collection of collections) { + collectionNameMap.set(collection.id, collection.name); + } + setCollectionNameMap(collectionNameMap); + const faceAndFiles = await wipClusterPageContents(); + // const files = await getLocalFiles(); + // const duplicateFiles = await getDuplicates(files, collectionNameMap); + const duplicateFiles = faceAndFiles.map(({ face, file }) => ({ + files: [file], + size: face.score, + })); + const currFileSizeMap = new Map(); + let toSelectFileIDs: number[] = []; + let count = 0; + for (const dupe of duplicateFiles) { + // select all except first file + toSelectFileIDs = [ + ...toSelectFileIDs, + ...dupe.files.slice(1).map((f) => f.id), + ]; + count += dupe.files.length - 1; + + for (const file of dupe.files) { + currFileSizeMap.set(file.id, dupe.size); + } + } + setDuplicates(duplicateFiles); + const selectedFiles = { + count: count, + ownCount: count, + collectionID: ALL_SECTION, + }; + for (const fileID of toSelectFileIDs) { + selectedFiles[fileID] = true; + } + + finishLoading(); + }; + + const duplicateFiles = useMemoSingleThreaded(() => { + return (duplicates ?? []).reduce((acc, dupe) => { + return [...acc, ...dupe.files]; + }, []); + }, [duplicates]); + + if (!duplicates) { + return ( + + + + ); + } + + return ( + + {duplicateFiles.length > 0 && ( + {t("DEDUPLICATE_BASED_ON_SIZE")} + )} + {duplicateFiles.length === 0 ? ( + + + {t("NO_DUPLICATES_FOUND")} + + + ) : ( + + )} + + + ); +} + +const Options: React.FC = () => { + const router = useRouter(); + + const close = () => { + router.push(PAGES.GALLERY); + }; + + return ( + + + + + + {pt("Faces")} + + + ); +}; + +interface ClusterDebugPhotoFrameProps { + files: EnteFile[]; + duplicates?: Duplicate[]; + activeCollectionID: number; +} + +const ClusterDebugPhotoFrame: React.FC = ({ + duplicates, + files, + activeCollectionID, +}) => { + const displayFiles = useMemoSingleThreaded(() => { + return files.map((item) => { + const filteredItem = { + ...item, + w: window.innerWidth, + h: window.innerHeight, + title: item.pubMagicMetadata?.data.caption, + }; + return filteredItem; + }); + }, [files]); + + const updateURL = + (index: number) => (id: number, url: string, forceUpdate?: boolean) => { + const file = displayFiles[index]; + // this is to prevent outdated updateURL call from updating the wrong file + if (file.id !== id) { + log.info( + `[${id}]PhotoSwipe: updateURL: file id mismatch: ${file.id} !== ${id}`, + ); + throw Error(CustomError.UPDATE_URL_FILE_ID_MISMATCH); + } + if (file.msrc && !forceUpdate) { + throw Error(CustomError.URL_ALREADY_SET); + } + updateFileMsrcProps(file, url); + }; + + const getThumbnail = ( + item: EnteFile, + index: number, + isScrolling: boolean, + ) => ( + {}} + selectable={false} + onSelect={() => {}} + selected={false} + selectOnClick={false} + onHover={() => {}} + onRangeSelect={() => {}} + isRangeSelectActive={false} + isInsSelectRange={false} + activeCollectionID={activeCollectionID} + showPlaceholder={isScrolling} + /> + ); + + return ( + + + {({ height, width }) => ( + + )} + + + ); +}; + +const Container = styled("div")` + display: block; + flex: 1; + width: 100%; + flex-wrap: wrap; + margin: 0 auto; + overflow: hidden; + .pswp-thumbnail { + display: inline-block; + cursor: pointer; + } +`; diff --git a/web/packages/new/photos/components/MLSettings.tsx b/web/packages/new/photos/components/MLSettings.tsx index 43dc1231e3..fb3e6ea008 100644 --- a/web/packages/new/photos/components/MLSettings.tsx +++ b/web/packages/new/photos/components/MLSettings.tsx @@ -1,5 +1,5 @@ import { EnteDrawer } from "@/base/components/EnteDrawer"; -import { MenuItemGroup, MenuSectionTitle } from "@/base/components/Menu"; +import { MenuItemGroup } from "@/base/components/Menu"; import { Titlebar } from "@/base/components/Titlebar"; import { pt, ut } from "@/base/i18n"; import log from "@/base/log"; @@ -8,7 +8,6 @@ import { enableML, mlStatusSnapshot, mlStatusSubscribe, - wipCluster, wipClusterEnable, type MLStatus, } from "@/new/photos/services/ml"; @@ -28,6 +27,7 @@ import { type DialogProps, } from "@mui/material"; import { t } from "i18next"; +import { useRouter } from "next/router"; import React, { useEffect, useState, useSyncExternalStore } from "react"; import { Trans } from "react-i18next"; import type { NewAppContextPhotos } from "../types/context"; @@ -338,7 +338,10 @@ const ManageML: React.FC = ({ }); }; - const wipClusterNow = () => void wipCluster(); + // TODO-Cluster + // const wipClusterNow = () => void wipCluster(); + const router = useRouter(); + const wipClusterNow = () => router.push("/cluster-debug"); return ( @@ -387,15 +390,17 @@ const ManageML: React.FC = ({ - + /> */} )} diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index ecd520c436..3c6b4e01e3 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -287,7 +287,7 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { `Clustered ${faces.length} faces into ${validClusters.length} clusters (${Date.now() - t} ms)`, ); - return { clusters: validClusters, cgroups }; + return { faces, clusters: validClusters, cgroups }; }; /** diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 846b48c62f..aeb10c5d35 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -28,6 +28,7 @@ import { faceIndexes, indexableAndIndexedCounts, } from "./db"; +import type { Face } from "./face"; import { MLWorker } from "./worker"; import type { CLIPMatches } from "./worker-types"; @@ -342,6 +343,38 @@ export const wipSearchPersons = async () => { return _wip_searchPersons ?? []; }; +export const wipClusterPageContents = async () => { + if (!(await wipClusterEnable())) return []; + + log.info("clustering"); + _wip_isClustering = true; + _wip_searchPersons = undefined; + triggerStatusUpdate(); + + const { faces } = await clusterFaces(await faceIndexes()); + // const searchPersons = await convertToSearchPersons(clusters, cgroups); + + const localFiles = await getAllLocalFiles(); + const localFileByID = new Map(localFiles.map((f) => [f.id, f])); + + const result1: { file: EnteFile; face: Face }[] = []; + for (const face of faces) { + const file = ensure( + localFileByID.get(ensure(fileIDFromFaceID(face.faceID))), + ); + result1.push({ file, face }); + } + + const result = result1.sort((a, b) => b.face.score - a.face.score); + + _wip_isClustering = false; + // _wip_searchPersons = searchPersons; + triggerStatusUpdate(); + + // return { faces, clusters, cgroups }; + return result; +}; + export const wipCluster = async () => { if (!(await wipClusterEnable())) return; From 9908cf5a29b64d93240ae0e96dfbbce776fb8f7e Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 10:48:10 +0530 Subject: [PATCH 058/275] Debug code --- web/apps/photos/src/pages/gallery/index.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/web/apps/photos/src/pages/gallery/index.tsx b/web/apps/photos/src/pages/gallery/index.tsx index 9bd21abecd..04b4e611e7 100644 --- a/web/apps/photos/src/pages/gallery/index.tsx +++ b/web/apps/photos/src/pages/gallery/index.tsx @@ -6,6 +6,7 @@ import { getLocalFiles, getLocalTrashedFiles, } from "@/new/photos/services/files"; +import { wipClusterEnable } from "@/new/photos/services/ml"; import { EnteFile } from "@/new/photos/types/file"; import { mergeMetadata } from "@/new/photos/utils/file"; import { CenteredFlex } from "@ente/shared/components/Container"; @@ -669,6 +670,17 @@ export default function Gallery() { }; }, [selectAll, clearSelection]); + useEffect(() => { + // TODO-Cluster + if (process.env.NEXT_PUBLIC_ENTE_WIP_CL) { + setTimeout(() => { + void wipClusterEnable().then( + (y) => y && router.push("cluster-debug"), + ); + }, 2000); + } + }, []); + const fileToCollectionsMap = useMemoSingleThreaded(() => { return constructFileToCollectionMap(files); }, [files]); From 87750805aecec20efa58d167550055aaa766c8d6 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 10:50:25 +0530 Subject: [PATCH 059/275] Inline --- web/apps/photos/src/pages/cluster-debug.tsx | 420 +++++++++++--------- 1 file changed, 235 insertions(+), 185 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index d71b300647..4f2e41a9e9 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -1,143 +1,81 @@ import { SelectionBar } from "@/base/components/Navbar"; import { pt } from "@/base/i18n"; -import log from "@/base/log"; import { wipClusterPageContents } from "@/new/photos/services/ml"; +import type { Face } from "@/new/photos/services/ml/face"; import { EnteFile } from "@/new/photos/types/file"; import { + FlexWrapper, FluidContainer, VerticallyCentered, } from "@ente/shared/components/Container"; import EnteSpinner from "@ente/shared/components/EnteSpinner"; import { PHOTOS_PAGES as PAGES } from "@ente/shared/constants/pages"; -import { CustomError } from "@ente/shared/error"; -import useMemoSingleThreaded from "@ente/shared/hooks/useMemoSingleThreaded"; import BackButton from "@mui/icons-material/ArrowBackOutlined"; import { Box, IconButton, styled } from "@mui/material"; -import Typography from "@mui/material/Typography"; -import { DedupePhotoList } from "components/PhotoList/dedupe"; import PreviewCard from "components/pages/gallery/PreviewCard"; -import { ALL_SECTION } from "constants/collection"; +import { + DATE_CONTAINER_HEIGHT, + GAP_BTW_TILES, + IMAGE_CONTAINER_MAX_HEIGHT, + IMAGE_CONTAINER_MAX_WIDTH, + MIN_COLUMNS, + SIZE_AND_COUNT_CONTAINER_HEIGHT, +} from "constants/gallery"; import { t } from "i18next"; import { useRouter } from "next/router"; import { AppContext } from "pages/_app"; -import { createContext, useContext, useEffect, useState } from "react"; +import React, { useContext, useEffect, useMemo, useRef, useState } from "react"; import AutoSizer from "react-virtualized-auto-sizer"; -import { getLocalCollections } from "services/collectionService"; -import { Duplicate } from "services/deduplicationService"; -import { - DeduplicateContextType, - DefaultDeduplicateContext, -} from "types/deduplicate"; -import { updateFileMsrcProps } from "utils/photoFrame"; +import { VariableSizeList as List } from "react-window"; -const DeduplicateContext = createContext( - DefaultDeduplicateContext, -); - -const Info = styled("div")` - padding: 24px; - font-size: 18px; -`; +export interface UICluster { + files: EnteFile[]; + face: Face; +} // TODO-Cluster Temporary component for debugging export default function Deduplicate() { const { startLoading, finishLoading, showNavBar } = useContext(AppContext); - const [duplicates, setDuplicates] = useState(null); - const [collectionNameMap, setCollectionNameMap] = useState( - new Map(), - ); + const [clusters, setClusters] = useState(null); useEffect(() => { showNavBar(true); + cluster(); }, []); - useEffect(() => { - syncWithRemote(); - }, []); - - const syncWithRemote = async () => { + const cluster = async () => { startLoading(); - const collections = await getLocalCollections(); - const collectionNameMap = new Map(); - for (const collection of collections) { - collectionNameMap.set(collection.id, collection.name); - } - setCollectionNameMap(collectionNameMap); const faceAndFiles = await wipClusterPageContents(); - // const files = await getLocalFiles(); - // const duplicateFiles = await getDuplicates(files, collectionNameMap); - const duplicateFiles = faceAndFiles.map(({ face, file }) => ({ - files: [file], - size: face.score, - })); - const currFileSizeMap = new Map(); - let toSelectFileIDs: number[] = []; - let count = 0; - for (const dupe of duplicateFiles) { - // select all except first file - toSelectFileIDs = [ - ...toSelectFileIDs, - ...dupe.files.slice(1).map((f) => f.id), - ]; - count += dupe.files.length - 1; - - for (const file of dupe.files) { - currFileSizeMap.set(file.id, dupe.size); - } - } - setDuplicates(duplicateFiles); - const selectedFiles = { - count: count, - ownCount: count, - collectionID: ALL_SECTION, - }; - for (const fileID of toSelectFileIDs) { - selectedFiles[fileID] = true; - } - + setClusters( + faceAndFiles.map(({ face, file }) => ({ + files: [file], + face, + })), + ); finishLoading(); }; - const duplicateFiles = useMemoSingleThreaded(() => { - return (duplicates ?? []).reduce((acc, dupe) => { - return [...acc, ...dupe.files]; - }, []); - }, [duplicates]); - - if (!duplicates) { - return ( - - - - ); - } - return ( - - {duplicateFiles.length > 0 && ( - {t("DEDUPLICATE_BASED_ON_SIZE")} - )} - {duplicateFiles.length === 0 ? ( - - - {t("NO_DUPLICATES_FOUND")} - - + <> + {clusters ? ( + + + {({ height, width }) => ( + + )} + + ) : ( - + + + )} - + ); } @@ -160,86 +98,6 @@ const Options: React.FC = () => { ); }; -interface ClusterDebugPhotoFrameProps { - files: EnteFile[]; - duplicates?: Duplicate[]; - activeCollectionID: number; -} - -const ClusterDebugPhotoFrame: React.FC = ({ - duplicates, - files, - activeCollectionID, -}) => { - const displayFiles = useMemoSingleThreaded(() => { - return files.map((item) => { - const filteredItem = { - ...item, - w: window.innerWidth, - h: window.innerHeight, - title: item.pubMagicMetadata?.data.caption, - }; - return filteredItem; - }); - }, [files]); - - const updateURL = - (index: number) => (id: number, url: string, forceUpdate?: boolean) => { - const file = displayFiles[index]; - // this is to prevent outdated updateURL call from updating the wrong file - if (file.id !== id) { - log.info( - `[${id}]PhotoSwipe: updateURL: file id mismatch: ${file.id} !== ${id}`, - ); - throw Error(CustomError.UPDATE_URL_FILE_ID_MISMATCH); - } - if (file.msrc && !forceUpdate) { - throw Error(CustomError.URL_ALREADY_SET); - } - updateFileMsrcProps(file, url); - }; - - const getThumbnail = ( - item: EnteFile, - index: number, - isScrolling: boolean, - ) => ( - {}} - selectable={false} - onSelect={() => {}} - selected={false} - selectOnClick={false} - onHover={() => {}} - onRangeSelect={() => {}} - isRangeSelectActive={false} - isInsSelectRange={false} - activeCollectionID={activeCollectionID} - showPlaceholder={isScrolling} - /> - ); - - return ( - - - {({ height, width }) => ( - - )} - - - ); -}; - const Container = styled("div")` display: block; flex: 1; @@ -249,6 +107,198 @@ const Container = styled("div")` overflow: hidden; .pswp-thumbnail { display: inline-block; - cursor: pointer; } `; + +interface ClusterPhotoListProps { + height: number; + width: number; + clusters: UICluster[]; +} + +const ClusterPhotoList: React.FC = ({ + height, + width, + clusters, +}) => { + const [itemList, setItemList] = useState([]); + const listRef = useRef(null); + + const getThumbnail = ( + item: EnteFile, + index: number, + isScrolling: boolean, + ) => ( + {}} + onClick={() => {}} + selectable={false} + onSelect={() => {}} + selected={false} + selectOnClick={false} + onHover={() => {}} + onRangeSelect={() => {}} + isRangeSelectActive={false} + isInsSelectRange={false} + activeCollectionID={0} + showPlaceholder={isScrolling} + /> + ); + + const columns = useMemo(() => { + const fittableColumns = getFractionFittableColumns(width); + let columns = Math.floor(fittableColumns); + if (columns < MIN_COLUMNS) { + columns = MIN_COLUMNS; + } + return columns; + }, [width]); + + const shrinkRatio = getShrinkRatio(width, columns); + const listItemHeight = + IMAGE_CONTAINER_MAX_HEIGHT * shrinkRatio + GAP_BTW_TILES; + + useEffect(() => { + setItemList(itemListFromClusters(clusters, columns)); + }, [columns, clusters]); + + useEffect(() => { + listRef.current?.resetAfterIndex(0); + }, [itemList]); + + const getItemSize = (i: number) => + itemList[i].score !== undefined + ? SIZE_AND_COUNT_CONTAINER_HEIGHT + : listItemHeight; + + const generateKey = (i: number) => + itemList[i].score !== undefined + ? `${itemList[i].score}-${i}` + : `${itemList[i].files[0].id}-${itemList[i].files.slice(-1)[0].id}`; + + const renderListItem = (listItem: ItemListItem, isScrolling: boolean) => + listItem.score !== undefined ? ( + + {listItem.fileCount} {t("FILES")},{" score "} + {listItem.score.toFixed(2)} + + ) : ( + listItem.files.map((item, idx) => + getThumbnail(item, listItem.itemStartIndex + idx, isScrolling), + ) + ); + + return ( + + {({ index, style, isScrolling, data }) => { + const { itemList, columns, shrinkRatio, renderListItem } = data; + return ( + + + {renderListItem(itemList[index], isScrolling)} + + + ); + }} + + ); +}; + +const ListContainer = styled(Box)<{ + columns: number; + shrinkRatio: number; +}>` + display: grid; + grid-template-columns: ${({ columns, shrinkRatio }) => + `repeat(${columns},${IMAGE_CONTAINER_MAX_WIDTH * shrinkRatio}px)`}; + grid-column-gap: ${GAP_BTW_TILES}px; + width: 100%; + color: #fff; + padding: 0 24px; + @media (max-width: ${IMAGE_CONTAINER_MAX_WIDTH * MIN_COLUMNS}px) { + padding: 0 4px; + } +`; + +const ListItemContainer = styled(FlexWrapper)<{ span: number }>` + grid-column: span ${(props) => props.span}; +`; + +const SizeAndCountContainer = styled(ListItemContainer)` + height: ${DATE_CONTAINER_HEIGHT}px; + color: ${({ theme }) => theme.colors.text.muted}; + margin-top: 1rem; + height: ${SIZE_AND_COUNT_CONTAINER_HEIGHT}px; +`; + +interface ItemListItem { + score?: number; + files?: EnteFile[]; + itemStartIndex?: number; + fileCount?: number; +} + +const ListItem = styled("div")` + display: flex; + justify-content: center; +`; + +function getFractionFittableColumns(width: number): number { + return ( + (width - 2 * getGapFromScreenEdge(width) + GAP_BTW_TILES) / + (IMAGE_CONTAINER_MAX_WIDTH + GAP_BTW_TILES) + ); +} + +function getGapFromScreenEdge(width: number) { + if (width > MIN_COLUMNS * IMAGE_CONTAINER_MAX_WIDTH) { + return 24; + } else { + return 4; + } +} + +function getShrinkRatio(width: number, columns: number) { + return ( + (width - + 2 * getGapFromScreenEdge(width) - + (columns - 1) * GAP_BTW_TILES) / + (columns * IMAGE_CONTAINER_MAX_WIDTH) + ); +} + +const itemListFromClusters = (clusters: UICluster[], columns: number) => { + const result: ItemListItem[] = []; + for (let index = 0; index < clusters.length; index++) { + const dupes = clusters[index]; + result.push({ + score: dupes.face.score, + fileCount: dupes.files.length, + }); + let lastIndex = 0; + while (lastIndex < dupes.files.length) { + result.push({ + files: dupes.files.slice(lastIndex, lastIndex + columns), + itemStartIndex: index, + }); + lastIndex += columns; + } + } + return result; +}; From 8e87ebd50bb49aed922d4838e91c39084811a72d Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 12:06:55 +0530 Subject: [PATCH 060/275] Inline --- web/apps/photos/src/pages/cluster-debug.tsx | 176 +++++++++----------- 1 file changed, 80 insertions(+), 96 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 4f2e41a9e9..9d45ada7ab 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -1,6 +1,6 @@ import { SelectionBar } from "@/base/components/Navbar"; import { pt } from "@/base/i18n"; -import { wipClusterPageContents } from "@/new/photos/services/ml"; +import { faceCrop, wipClusterPageContents } from "@/new/photos/services/ml"; import type { Face } from "@/new/photos/services/ml/face"; import { EnteFile } from "@/new/photos/types/file"; import { @@ -9,24 +9,13 @@ import { VerticallyCentered, } from "@ente/shared/components/Container"; import EnteSpinner from "@ente/shared/components/EnteSpinner"; -import { PHOTOS_PAGES as PAGES } from "@ente/shared/constants/pages"; import BackButton from "@mui/icons-material/ArrowBackOutlined"; import { Box, IconButton, styled } from "@mui/material"; -import PreviewCard from "components/pages/gallery/PreviewCard"; -import { - DATE_CONTAINER_HEIGHT, - GAP_BTW_TILES, - IMAGE_CONTAINER_MAX_HEIGHT, - IMAGE_CONTAINER_MAX_WIDTH, - MIN_COLUMNS, - SIZE_AND_COUNT_CONTAINER_HEIGHT, -} from "constants/gallery"; -import { t } from "i18next"; import { useRouter } from "next/router"; import { AppContext } from "pages/_app"; import React, { useContext, useEffect, useMemo, useRef, useState } from "react"; import AutoSizer from "react-virtualized-auto-sizer"; -import { VariableSizeList as List } from "react-window"; +import { VariableSizeList } from "react-window"; export interface UICluster { files: EnteFile[]; @@ -82,9 +71,7 @@ export default function Deduplicate() { const Options: React.FC = () => { const router = useRouter(); - const close = () => { - router.push(PAGES.GALLERY); - }; + const close = () => router.push("/gallery"); return ( @@ -103,7 +90,6 @@ const Container = styled("div")` flex: 1; width: 100%; flex-wrap: wrap; - margin: 0 auto; overflow: hidden; .pswp-thumbnail { display: inline-block; @@ -124,41 +110,13 @@ const ClusterPhotoList: React.FC = ({ const [itemList, setItemList] = useState([]); const listRef = useRef(null); - const getThumbnail = ( - item: EnteFile, - index: number, - isScrolling: boolean, - ) => ( - {}} - onClick={() => {}} - selectable={false} - onSelect={() => {}} - selected={false} - selectOnClick={false} - onHover={() => {}} - onRangeSelect={() => {}} - isRangeSelectActive={false} - isInsSelectRange={false} - activeCollectionID={0} - showPlaceholder={isScrolling} - /> + const columns = useMemo( + () => Math.max(Math.floor(getFractionFittableColumns(width)), 4), + [width], ); - const columns = useMemo(() => { - const fittableColumns = getFractionFittableColumns(width); - let columns = Math.floor(fittableColumns); - if (columns < MIN_COLUMNS) { - columns = MIN_COLUMNS; - } - return columns; - }, [width]); - const shrinkRatio = getShrinkRatio(width, columns); - const listItemHeight = - IMAGE_CONTAINER_MAX_HEIGHT * shrinkRatio + GAP_BTW_TILES; + const listItemHeight = 120 * shrinkRatio + 4; useEffect(() => { setItemList(itemListFromClusters(clusters, columns)); @@ -169,31 +127,17 @@ const ClusterPhotoList: React.FC = ({ }, [itemList]); const getItemSize = (i: number) => - itemList[i].score !== undefined - ? SIZE_AND_COUNT_CONTAINER_HEIGHT - : listItemHeight; + itemList[i].score !== undefined ? 36 : listItemHeight; const generateKey = (i: number) => itemList[i].score !== undefined ? `${itemList[i].score}-${i}` : `${itemList[i].files[0].id}-${itemList[i].files.slice(-1)[0].id}`; - const renderListItem = (listItem: ItemListItem, isScrolling: boolean) => - listItem.score !== undefined ? ( - - {listItem.fileCount} {t("FILES")},{" score "} - {listItem.score.toFixed(2)} - - ) : ( - listItem.files.map((item, idx) => - getThumbnail(item, listItem.itemStartIndex + idx, isScrolling), - ) - ); - return ( - = ({ overscanCount={3} useIsScrolling > - {({ index, style, isScrolling, data }) => { - const { itemList, columns, shrinkRatio, renderListItem } = data; + {({ index, style, data }) => { + const { itemList, columns, shrinkRatio } = data; + const item = itemList[index]; return ( - {renderListItem(itemList[index], isScrolling)} + {item.score !== undefined ? ( + + {`${item.fileCount} files, score ${item.score.toFixed(2)}`} + + ) : ( + item.files.map((enteFile) => ( + + + + )) + )} ); }} - + + ); +}; + +const FaceChip = styled(Box)` + width: 120px; + height: 120px; +`; + +interface FaceCropImageViewProps { + faceID: string; + enteFile: EnteFile; +} + +const FaceCropImageView: React.FC = ({ + faceID, + enteFile, +}) => { + const [objectURL, setObjectURL] = useState(); + + useEffect(() => { + let didCancel = false; + let thisObjectURL: string | undefined; + + void faceCrop(faceID, enteFile).then((blob) => { + if (blob && !didCancel) + setObjectURL((thisObjectURL = URL.createObjectURL(blob))); + }); + + return () => { + didCancel = true; + if (thisObjectURL) URL.revokeObjectURL(thisObjectURL); + }; + }, [faceID, enteFile]); + + return objectURL ? ( + + ) : ( +
); }; @@ -226,29 +225,24 @@ const ListContainer = styled(Box)<{ }>` display: grid; grid-template-columns: ${({ columns, shrinkRatio }) => - `repeat(${columns},${IMAGE_CONTAINER_MAX_WIDTH * shrinkRatio}px)`}; - grid-column-gap: ${GAP_BTW_TILES}px; + `repeat(${columns},${120 * shrinkRatio}px)`}; + grid-column-gap: 4px; width: 100%; - color: #fff; - padding: 0 24px; - @media (max-width: ${IMAGE_CONTAINER_MAX_WIDTH * MIN_COLUMNS}px) { - padding: 0 4px; - } + padding: 4px; `; const ListItemContainer = styled(FlexWrapper)<{ span: number }>` grid-column: span ${(props) => props.span}; `; -const SizeAndCountContainer = styled(ListItemContainer)` - height: ${DATE_CONTAINER_HEIGHT}px; +const LabelContainer = styled(ListItemContainer)` color: ${({ theme }) => theme.colors.text.muted}; - margin-top: 1rem; - height: ${SIZE_AND_COUNT_CONTAINER_HEIGHT}px; + height: 32px; `; interface ItemListItem { score?: number; + face?: Face; files?: EnteFile[]; itemStartIndex?: number; fileCount?: number; @@ -260,26 +254,15 @@ const ListItem = styled("div")` `; function getFractionFittableColumns(width: number): number { - return ( - (width - 2 * getGapFromScreenEdge(width) + GAP_BTW_TILES) / - (IMAGE_CONTAINER_MAX_WIDTH + GAP_BTW_TILES) - ); + return (width - 2 * getGapFromScreenEdge(width) + 4) / (120 + 4); } -function getGapFromScreenEdge(width: number) { - if (width > MIN_COLUMNS * IMAGE_CONTAINER_MAX_WIDTH) { - return 24; - } else { - return 4; - } -} +const getGapFromScreenEdge = (width: number) => (width > 4 * 120 ? 24 : 4); function getShrinkRatio(width: number, columns: number) { return ( - (width - - 2 * getGapFromScreenEdge(width) - - (columns - 1) * GAP_BTW_TILES) / - (columns * IMAGE_CONTAINER_MAX_WIDTH) + (width - 2 * getGapFromScreenEdge(width) - (columns - 1) * 4) / + (columns * 120) ); } @@ -295,6 +278,7 @@ const itemListFromClusters = (clusters: UICluster[], columns: number) => { while (lastIndex < dupes.files.length) { result.push({ files: dupes.files.slice(lastIndex, lastIndex + columns), + face: dupes.face, itemStartIndex: index, }); lastIndex += columns; From 74377a93d8e20e969d9a2531f32f577b5f0ef090 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Tue, 27 Aug 2024 15:31:20 +0200 Subject: [PATCH 061/275] Fix #2018 --- auth/assets/custom-icons/icons/runemate.svg | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/auth/assets/custom-icons/icons/runemate.svg b/auth/assets/custom-icons/icons/runemate.svg index 1855afb8d2..43523d438c 100644 --- a/auth/assets/custom-icons/icons/runemate.svg +++ b/auth/assets/custom-icons/icons/runemate.svg @@ -1,8 +1,3 @@ - - - - - - - + + From e605d4c0dfed43b32c53540cb37743ca53d7d0b8 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 13:28:45 +0530 Subject: [PATCH 062/275] [docs] Add a intro to backup FAQ since this question keeps coming up e.g. https://github.com/ente-io/ente/discussions/3009 --- docs/docs/.vitepress/sidebar.ts | 4 ++ docs/docs/self-hosting/faq/backup.md | 65 ++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 docs/docs/self-hosting/faq/backup.md diff --git a/docs/docs/.vitepress/sidebar.ts b/docs/docs/.vitepress/sidebar.ts index 6aff8e3319..62b3cedf87 100644 --- a/docs/docs/.vitepress/sidebar.ts +++ b/docs/docs/.vitepress/sidebar.ts @@ -259,6 +259,10 @@ export const sidebar = [ text: "Shared albums", link: "/self-hosting/faq/sharing", }, + { + text: "Backups", + link: "/self-hosting/faq/backup", + }, ], }, { diff --git a/docs/docs/self-hosting/faq/backup.md b/docs/docs/self-hosting/faq/backup.md new file mode 100644 index 0000000000..3a9dc00d52 --- /dev/null +++ b/docs/docs/self-hosting/faq/backup.md @@ -0,0 +1,65 @@ +--- +title: Backups +description: General introduction to backing up your self hosted Ente instance +--- + +# Backing up your Ente instance + +> [!WARNING] +> +> This is not meant to be a comprehensive and bullet proof guide. There are many +> moving parts, and if small mistakes might make your backups unusable. +> +> Please treat this only as a general introduction. And remember to test your +> restores. + +At the minimum, a functional Ente backend needs three things: + +1. Museum (the API server) +2. Postgres (the database) +3. Object storage (any S3-compatible object storage) + +When thinking about backups, this translates into backing up the relevant state +from each of these: + +1. For museum, you'd want to backup your `museum.yaml`, `credentials.yaml` or + any other custom configuration that you created. In particular, you should + backup the [secrets that are specific to your + instance](https://github.com/ente-io/ente/blob/74377a93d8e20e969d9a2531f32f577b5f0ef090/server/configurations/local.yaml#L188) + (`key.encryption`, `key.hash` and `jwt.secret`). + +2. For postgres, the entire data volume needs to be backed up. + +3. For object storage, the entire data volume needs to be backed up. + +A common oversight is taking a lot of care for backing up the object storage, +even going as far as enabling replication and backing up the the multiple object +storage volumes, but not applying the same care to the database backup. + +While the actual encrypted photos are indeed stored in the object storage, +**this encrypted data will not be usable without the database** since the +database contains information like a file specific encryption key. + +Viewed differently, to decrypt your data you need three pieces of information: + +1. The encrypted file data (which comes from the object storage backup). + +2. The ([encrypted](https://ente.io/architecture/)) file and collection specific + encryption keys (which come from the database backup). + +3. The master key (which comes from your password). + +--- + +If you're starting out with self hosting, our recommendation is to start by +keeping a plaintext backup of your photos. +[You can use the CLI or the desktop app to automate this](/photos/faq/export). + +Once you get more comfortable with the various parts, you can try backing up +your instance. As a reference, +[this document outlines how Ente itself treats backups](https://ente.io/reliability). + +If you stop doing plaintext backups and instead rely on your instance backup, +ensure that you do the full restore process also to verify you can get back your +data. As the industry saying goes, a backup without a restore is no backup at +all. From ca3ec5e94cff6847346deaf9a52a03825752a8a0 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 13:30:02 +0530 Subject: [PATCH 063/275] pretty --- docs/docs/photos/faq/subscription.md | 2 +- docs/docs/self-hosting/faq/backup.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/docs/photos/faq/subscription.md b/docs/docs/photos/faq/subscription.md index 99302437aa..88946920ce 100644 --- a/docs/docs/photos/faq/subscription.md +++ b/docs/docs/photos/faq/subscription.md @@ -154,7 +154,7 @@ downgrade to the 50 GB yearly plan, then - This credited amount will be discounted from your next invoice, which will be due in half a year. - + The same applies to monthly plans. If you prefer to have this credit refunded to your original payment method, diff --git a/docs/docs/self-hosting/faq/backup.md b/docs/docs/self-hosting/faq/backup.md index 3a9dc00d52..08e140604e 100644 --- a/docs/docs/self-hosting/faq/backup.md +++ b/docs/docs/self-hosting/faq/backup.md @@ -24,8 +24,8 @@ from each of these: 1. For museum, you'd want to backup your `museum.yaml`, `credentials.yaml` or any other custom configuration that you created. In particular, you should - backup the [secrets that are specific to your - instance](https://github.com/ente-io/ente/blob/74377a93d8e20e969d9a2531f32f577b5f0ef090/server/configurations/local.yaml#L188) + backup the + [secrets that are specific to your instance](https://github.com/ente-io/ente/blob/74377a93d8e20e969d9a2531f32f577b5f0ef090/server/configurations/local.yaml#L188) (`key.encryption`, `key.hash` and `jwt.secret`). 2. For postgres, the entire data volume needs to be backed up. From aedf659144ff4a08d72dee6fbeb472a6865c8e9e Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 13:31:50 +0530 Subject: [PATCH 064/275] Link --- docs/docs/self-hosting/guides/admin.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/docs/self-hosting/guides/admin.md b/docs/docs/self-hosting/guides/admin.md index c138eb4c33..6377fe39c5 100644 --- a/docs/docs/self-hosting/guides/admin.md +++ b/docs/docs/self-hosting/guides/admin.md @@ -78,3 +78,7 @@ internal: You can use [account list](https://github.com/ente-io/ente/blob/main/cli/docs/generated/ente_account_list.md) command to find the user id of any account. + +## Backups + +See this [FAQ](/self-hosting/faq/backup). From 61c1847d75d9a106dd90f567a72a6400ab9003b8 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Wed, 28 Aug 2024 10:19:39 +0200 Subject: [PATCH 065/275] [mob][photos] Move --- mobile/lib/services/machine_learning/ml_indexing_isolate.dart | 3 +-- mobile/lib/services/machine_learning/ml_service.dart | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mobile/lib/services/machine_learning/ml_indexing_isolate.dart b/mobile/lib/services/machine_learning/ml_indexing_isolate.dart index b01037dc83..fec1cbf410 100644 --- a/mobile/lib/services/machine_learning/ml_indexing_isolate.dart +++ b/mobile/lib/services/machine_learning/ml_indexing_isolate.dart @@ -189,9 +189,8 @@ class MLIndexingIsolate { /// Analyzes the given image data by running the full pipeline for faces, using [_analyzeImageSync] in the isolate. Future analyzeImage( FileMLInstruction instruction, + String filePath, ) async { - final String filePath = await getImagePathForML(instruction.file); - final Stopwatch stopwatch = Stopwatch()..start(); late MLResult result; diff --git a/mobile/lib/services/machine_learning/ml_service.dart b/mobile/lib/services/machine_learning/ml_service.dart index e3e41c73d2..b048301ad1 100644 --- a/mobile/lib/services/machine_learning/ml_service.dart +++ b/mobile/lib/services/machine_learning/ml_service.dart @@ -391,8 +391,11 @@ class MLService { bool actuallyRanML = false; try { + final String filePath = await getImagePathForML(instruction.file); + final MLResult? result = await MLIndexingIsolate.instance.analyzeImage( instruction, + filePath, ); // Check if there's no result simply because MLController paused indexing if (result == null) { From 584ce6d416d90b435aa346eb440de44c640a3296 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 13:57:22 +0530 Subject: [PATCH 066/275] [docs] Tweaks to the Google import steps --- .../migration/from-google-photos/index.md | 17 ++++++++++++++--- docs/docs/self-hosting/faq/backup.md | 4 ++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/docs/docs/photos/migration/from-google-photos/index.md b/docs/docs/photos/migration/from-google-photos/index.md index e334ca5f88..0623f157d2 100644 --- a/docs/docs/photos/migration/from-google-photos/index.md +++ b/docs/docs/photos/migration/from-google-photos/index.md @@ -39,10 +39,21 @@ it with Ente. 8. Wait for Google to send you your data. 9. Open [our desktop app](https://ente.io/download/desktop), click on "Upload", - select "Google takeout" and pick the ZIP file you just downloaded. + select "Google takeout" and pick the ZIP file you just downloaded. If you + were provided with multiple ZIP files, please extract **all** the ZIP files + into one folder and select that folder instead. -> If you were provided with multiple ZIP files, please extract **all** the files -> into one folder and select that folder instead. +> While the app supports uploading multiple ZIPs too, we recommend unzipping +> them all into a single folder and uploading that folder instead so that your +> photo dates are imported properly +> ([details](/photos/faq/photo-dates#importing-from-google-takeout)). +> +>
+> +> Note that you can still preserve your albums even when uploading a single +> folder - select the create new album option and the app will ask you if you +> want to put each leaf folder into a separate album +> ([details](/photos/features/albums#uploading-a-nested-folder)). ![Importing Google Takeout into Ente](google-takeout.png){width=400px} diff --git a/docs/docs/self-hosting/faq/backup.md b/docs/docs/self-hosting/faq/backup.md index 08e140604e..455468bbf5 100644 --- a/docs/docs/self-hosting/faq/backup.md +++ b/docs/docs/self-hosting/faq/backup.md @@ -8,7 +8,7 @@ description: General introduction to backing up your self hosted Ente instance > [!WARNING] > > This is not meant to be a comprehensive and bullet proof guide. There are many -> moving parts, and if small mistakes might make your backups unusable. +> moving parts, and small mistakes might make your backups unusable. > > Please treat this only as a general introduction. And remember to test your > restores. @@ -42,7 +42,7 @@ database contains information like a file specific encryption key. Viewed differently, to decrypt your data you need three pieces of information: -1. The encrypted file data (which comes from the object storage backup). +1. The encrypted file data itself (which comes from the object storage backup). 2. The ([encrypted](https://ente.io/architecture/)) file and collection specific encryption keys (which come from the database backup). From e1ce353069562df4f73f8311e87369e8bb217622 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Wed, 28 Aug 2024 11:08:18 +0200 Subject: [PATCH 067/275] [mob][photos] Don't process large files on mobile --- mobile/lib/models/ml/ml_versions.dart | 1 + mobile/lib/services/machine_learning/ml_service.dart | 8 ++++++++ mobile/lib/utils/ml_util.dart | 9 ++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/mobile/lib/models/ml/ml_versions.dart b/mobile/lib/models/ml/ml_versions.dart index 2d382209dc..35d089178a 100644 --- a/mobile/lib/models/ml/ml_versions.dart +++ b/mobile/lib/models/ml/ml_versions.dart @@ -7,3 +7,4 @@ const minimumClusterSize = 2; const embeddingFetchLimit = 200; final fileDownloadMlLimit = Platform.isIOS ? 5 : 10; +const maxFileDownloadSize = 100000000; diff --git a/mobile/lib/services/machine_learning/ml_service.dart b/mobile/lib/services/machine_learning/ml_service.dart index b048301ad1..616e2bb2a1 100644 --- a/mobile/lib/services/machine_learning/ml_service.dart +++ b/mobile/lib/services/machine_learning/ml_service.dart @@ -488,6 +488,14 @@ class MLService { ); acceptedIssue = true; } + if (errorString.contains('FileSizeTooLargeForMobileIndexing')) { + _logger.severe( + '$errorString with ID ${instruction.file.uploadedFileID}, storing empty results so indexing does not get stuck', + e, + s, + ); + acceptedIssue = true; + } if (acceptedIssue) { await MLDataDB.instance.bulkInsertFaces( [Face.empty(instruction.file.uploadedFileID!, error: true)], diff --git a/mobile/lib/utils/ml_util.dart b/mobile/lib/utils/ml_util.dart index e07740acba..01ddd353a9 100644 --- a/mobile/lib/utils/ml_util.dart +++ b/mobile/lib/utils/ml_util.dart @@ -153,7 +153,8 @@ Future> getFilesForMlIndexing() async { } Stream> fetchEmbeddingsAndInstructions( - int yieldSize,) async* { + int yieldSize, +) async* { final List filesToIndex = await getFilesForMlIndexing(); final List> chunks = filesToIndex.chunks(embeddingFetchLimit); @@ -312,6 +313,12 @@ Future getImagePathForML(EnteFile enteFile) async { throw ThumbnailRetrievalException(e.toString(), s); } } else { + // Don't process the file if it's too large (more than 100MB) + if (enteFile.fileSize != null && enteFile.fileSize! > maxFileDownloadSize) { + throw Exception( + "FileSizeTooLargeForMobileIndexing: size is ${enteFile.fileSize}", + ); + } try { file = await getFile(enteFile, isOrigin: true); } catch (e, s) { From 1e9a014ce76f53d11a40535483d86f613cc19d88 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Wed, 28 Aug 2024 11:12:22 +0200 Subject: [PATCH 068/275] [mob][photos] Minor cleanup --- .../services/machine_learning/ml_service.dart | 34 +++++-------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/mobile/lib/services/machine_learning/ml_service.dart b/mobile/lib/services/machine_learning/ml_service.dart index 616e2bb2a1..0fee0af261 100644 --- a/mobile/lib/services/machine_learning/ml_service.dart +++ b/mobile/lib/services/machine_learning/ml_service.dart @@ -470,33 +470,17 @@ class MLService { _logger.info("Results for file ${result.fileId} stored locally"); return actuallyRanML; } catch (e, s) { - bool acceptedIssue = false; final String errorString = e.toString(); - if (errorString.contains('ThumbnailRetrievalException')) { - _logger.severe( - 'ThumbnailRetrievalException while processing image with ID ${instruction.file.uploadedFileID}, storing empty results so indexing does not get stuck', - e, - s, - ); - acceptedIssue = true; - } - if (errorString.contains('InvalidImageFormatException')) { - _logger.severe( - '$errorString with ID ${instruction.file.uploadedFileID}, storing empty results so indexing does not get stuck', - e, - s, - ); - acceptedIssue = true; - } - if (errorString.contains('FileSizeTooLargeForMobileIndexing')) { - _logger.severe( - '$errorString with ID ${instruction.file.uploadedFileID}, storing empty results so indexing does not get stuck', - e, - s, - ); - acceptedIssue = true; - } + final bool acceptedIssue = + errorString.contains('ThumbnailRetrievalException') || + errorString.contains('InvalidImageFormatException') || + errorString.contains('FileSizeTooLargeForMobileIndexing'); if (acceptedIssue) { + _logger.severe( + '$errorString with ID ${instruction.file.uploadedFileID}, storing empty results so indexing does not get stuck', + e, + s, + ); await MLDataDB.instance.bulkInsertFaces( [Face.empty(instruction.file.uploadedFileID!, error: true)], ); From db8e203c367c70d7e0057a7cda6e551ed1105a55 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Wed, 28 Aug 2024 11:21:50 +0200 Subject: [PATCH 069/275] [mob][photos] Always log basic info on empty result --- mobile/lib/services/machine_learning/ml_service.dart | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mobile/lib/services/machine_learning/ml_service.dart b/mobile/lib/services/machine_learning/ml_service.dart index 0fee0af261..19ef46f2be 100644 --- a/mobile/lib/services/machine_learning/ml_service.dart +++ b/mobile/lib/services/machine_learning/ml_service.dart @@ -471,13 +471,16 @@ class MLService { return actuallyRanML; } catch (e, s) { final String errorString = e.toString(); + final String format = instruction.file.displayName.split('.').last; + final int? size = instruction.file.fileSize; + final fileType = instruction.file.fileType; final bool acceptedIssue = errorString.contains('ThumbnailRetrievalException') || errorString.contains('InvalidImageFormatException') || errorString.contains('FileSizeTooLargeForMobileIndexing'); if (acceptedIssue) { _logger.severe( - '$errorString with ID ${instruction.file.uploadedFileID}, storing empty results so indexing does not get stuck', + '$errorString with ID ${instruction.file.uploadedFileID} (format $format, type $fileType, size $size), storing empty results so indexing does not get stuck', e, s, ); @@ -490,7 +493,7 @@ class MLService { return true; } _logger.severe( - "Failed to analyze using FaceML for image with ID: ${instruction.file.uploadedFileID} and format ${instruction.file.displayName.split('.').last} (${instruction.file.fileType}). Not storing any results locally, which means it will be automatically retried later.", + "Failed to index file with ID: ${instruction.file.uploadedFileID} (format $format, type $fileType, size $size). Not storing any results locally, which means it will be automatically retried later.", e, s, ); From 760b1f3f857ade5ceacc1830a6cb3377a61e90df Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 15:06:27 +0530 Subject: [PATCH 070/275] Neighbours --- web/apps/photos/src/pages/cluster-debug.tsx | 177 ++++++++---------- .../new/photos/services/ml/cluster-new.ts | 36 +++- web/packages/new/photos/services/ml/index.ts | 34 +++- 3 files changed, 136 insertions(+), 111 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 9d45ada7ab..25f9b36031 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -1,8 +1,11 @@ import { SelectionBar } from "@/base/components/Navbar"; import { pt } from "@/base/i18n"; -import { faceCrop, wipClusterPageContents } from "@/new/photos/services/ml"; -import type { Face } from "@/new/photos/services/ml/face"; -import { EnteFile } from "@/new/photos/types/file"; +import { + faceCrop, + wipClusterPageContents, + type FaceFileNeighbour, + type FaceFileNeighbours, +} from "@/new/photos/services/ml"; import { FlexWrapper, FluidContainer, @@ -10,22 +13,17 @@ import { } from "@ente/shared/components/Container"; import EnteSpinner from "@ente/shared/components/EnteSpinner"; import BackButton from "@mui/icons-material/ArrowBackOutlined"; -import { Box, IconButton, styled } from "@mui/material"; +import { Box, IconButton, styled, Typography } from "@mui/material"; import { useRouter } from "next/router"; import { AppContext } from "pages/_app"; import React, { useContext, useEffect, useMemo, useRef, useState } from "react"; import AutoSizer from "react-virtualized-auto-sizer"; import { VariableSizeList } from "react-window"; -export interface UICluster { - files: EnteFile[]; - face: Face; -} - // TODO-Cluster Temporary component for debugging -export default function Deduplicate() { +export default function ClusterDebug() { const { startLoading, finishLoading, showNavBar } = useContext(AppContext); - const [clusters, setClusters] = useState(null); + const [faceFNs, setFaceFNs] = useState(null); useEffect(() => { showNavBar(true); @@ -34,26 +32,20 @@ export default function Deduplicate() { const cluster = async () => { startLoading(); - const faceAndFiles = await wipClusterPageContents(); - setClusters( - faceAndFiles.map(({ face, file }) => ({ - files: [file], - face, - })), - ); + setFaceFNs(await wipClusterPageContents()); finishLoading(); }; return ( <> - {clusters ? ( + {faceFNs ? ( {({ height, width }) => ( )} @@ -99,13 +91,13 @@ const Container = styled("div")` interface ClusterPhotoListProps { height: number; width: number; - clusters: UICluster[]; + faceFNs: FaceFileNeighbours[]; } const ClusterPhotoList: React.FC = ({ height, width, - clusters, + faceFNs, }) => { const [itemList, setItemList] = useState([]); const listRef = useRef(null); @@ -119,24 +111,23 @@ const ClusterPhotoList: React.FC = ({ const listItemHeight = 120 * shrinkRatio + 4; useEffect(() => { - setItemList(itemListFromClusters(clusters, columns)); - }, [columns, clusters]); + setItemList(itemListFromFaceFNs(faceFNs, columns)); + }, [columns, faceFNs]); useEffect(() => { listRef.current?.resetAfterIndex(0); }, [itemList]); const getItemSize = (i: number) => - itemList[i].score !== undefined ? 36 : listItemHeight; + typeof itemList[i] == "number" ? 36 : listItemHeight; const generateKey = (i: number) => - itemList[i].score !== undefined - ? `${itemList[i].score}-${i}` - : `${itemList[i].files[0].id}-${itemList[i].files.slice(-1)[0].id}`; + typeof itemList[i] == "number" + ? `${itemList[i]}-${i}` + : `${itemList[i][0].enteFile.id}/${itemList[i][0].face.faceID}-${itemList[i].slice(-1)[0].enteFile.id}/${itemList[i].slice(-1)[0].face.faceID}-${i}`; return ( = ({ columns={columns} shrinkRatio={shrinkRatio} > - {item.score !== undefined ? ( + {typeof item == "number" ? ( - {`${item.fileCount} files, score ${item.score.toFixed(2)}`} + {`score ${item.toFixed(2)}`} ) : ( - item.files.map((enteFile) => ( - - - + item.map((ffn, i) => ( + )) )} @@ -178,20 +164,41 @@ const ClusterPhotoList: React.FC = ({ ); }; -const FaceChip = styled(Box)` - width: 120px; - height: 120px; -`; +type ItemListItem = number | FaceFileNeighbour[]; -interface FaceCropImageViewProps { - faceID: string; - enteFile: EnteFile; -} +const itemListFromFaceFNs = ( + faceFNs: FaceFileNeighbours[], + columns: number, +) => { + const result: ItemListItem[] = []; + for (let index = 0; index < faceFNs.length; index++) { + const { face, neighbours } = faceFNs[index]; + result.push(face.score); + let lastIndex = 0; + while (lastIndex < neighbours.length) { + result.push(neighbours.slice(lastIndex, lastIndex + columns)); + lastIndex += columns; + } + } + return result; +}; -const FaceCropImageView: React.FC = ({ - faceID, +const getFractionFittableColumns = (width: number) => + (width - 2 * getGapFromScreenEdge(width) + 4) / (120 + 4); + +const getGapFromScreenEdge = (width: number) => (width > 4 * 120 ? 24 : 4); + +const getShrinkRatio = (width: number, columns: number) => + (width - 2 * getGapFromScreenEdge(width) - (columns - 1) * 4) / + (columns * 120); + +const FaceItem: React.FC = ({ + face, enteFile, + cosineSimilarity, }) => { + const { faceID } = face; + const [objectURL, setObjectURL] = useState(); useEffect(() => { @@ -209,17 +216,33 @@ const FaceCropImageView: React.FC = ({ }; }, [faceID, enteFile]); - return objectURL ? ( - - ) : ( -
+ return ( + + {objectURL && ( + + )} + + {cosineSimilarity.toFixed(2)} + + ); }; -const ListContainer = styled(Box)<{ +const FaceChip = styled(Box)` + width: 120px; + height: 120px; +`; + +const ListContainer = styled(Box, { + shouldForwardProp: (propName) => propName != "shrinkRatio", +})<{ columns: number; shrinkRatio: number; }>` @@ -240,49 +263,7 @@ const LabelContainer = styled(ListItemContainer)` height: 32px; `; -interface ItemListItem { - score?: number; - face?: Face; - files?: EnteFile[]; - itemStartIndex?: number; - fileCount?: number; -} - const ListItem = styled("div")` display: flex; justify-content: center; `; - -function getFractionFittableColumns(width: number): number { - return (width - 2 * getGapFromScreenEdge(width) + 4) / (120 + 4); -} - -const getGapFromScreenEdge = (width: number) => (width > 4 * 120 ? 24 : 4); - -function getShrinkRatio(width: number, columns: number) { - return ( - (width - 2 * getGapFromScreenEdge(width) - (columns - 1) * 4) / - (columns * 120) - ); -} - -const itemListFromClusters = (clusters: UICluster[], columns: number) => { - const result: ItemListItem[] = []; - for (let index = 0; index < clusters.length; index++) { - const dupes = clusters[index]; - result.push({ - score: dupes.face.score, - fileCount: dupes.files.length, - }); - let lastIndex = 0; - while (lastIndex < dupes.files.length) { - result.push({ - files: dupes.files.slice(lastIndex, lastIndex + columns), - face: dupes.face, - itemStartIndex: index, - }); - lastIndex += columns; - } - } - return result; -}; diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index 3c6b4e01e3..e67688abc0 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -112,6 +112,17 @@ export interface CGroup { displayFaceID: string | undefined; } +// TODO-Cluster +export interface FaceNeighbours { + face: Face; + neighbours: FaceNeighbour[]; +} + +interface FaceNeighbour { + face: Face; + cosineSimilarity: number; +} + /** * Cluster faces into groups. * @@ -176,6 +187,8 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { // A function to generate new cluster IDs. const newClusterID = () => newNonSecureID("cluster_"); + const faceAndNeigbours: FaceNeighbours[] = []; + // For each face, for (const [i, { faceID, embedding }] of faces.entries()) { // If the face is already part of a cluster, then skip it. @@ -184,11 +197,13 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { // Find the nearest neighbour from among all the other faces. let nn: Face | undefined; let nnCosineSimilarity = 0; + let neighbours: FaceNeighbour[] = []; for (let j = 0; j < faces.length; j++) { // ! This is an O(n^2) loop, be careful when adding more code here. - // Skip ourselves. - if (i == j) continue; + // TODO-Cluster + // // Skip ourselves. + // if (i == j) continue; // Can't find a way of avoiding the null assertion here. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion @@ -197,12 +212,27 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { // The vectors are already normalized, so we can directly use their // dot product as their cosine similarity. const csim = dotProduct(embedding, n.embedding); + + // Skip ourselves. + if (i == j) { + neighbours.push({ face: n, cosineSimilarity: csim }); + continue; + } + if (csim > 0.76 && csim > nnCosineSimilarity) { nn = n; nnCosineSimilarity = csim; } + + neighbours.push({ face: n, cosineSimilarity: csim }); } + neighbours = neighbours.sort( + (a, b) => b.cosineSimilarity - a.cosineSimilarity, + ); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + faceAndNeigbours.push({ face: faces[i]!, neighbours }); + if (nn) { // Found a neighbour near enough. @@ -287,7 +317,7 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { `Clustered ${faces.length} faces into ${validClusters.length} clusters (${Date.now() - t} ms)`, ); - return { faces, clusters: validClusters, cgroups }; + return { faces, clusters: validClusters, cgroups, faceAndNeigbours }; }; /** diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index aeb10c5d35..0d1b2f105e 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -343,6 +343,17 @@ export const wipSearchPersons = async () => { return _wip_searchPersons ?? []; }; +export interface FaceFileNeighbours { + face: Face; + neighbours: FaceFileNeighbour[]; +} + +export interface FaceFileNeighbour { + face: Face; + enteFile: EnteFile; + cosineSimilarity: number; +} + export const wipClusterPageContents = async () => { if (!(await wipClusterEnable())) return []; @@ -351,21 +362,24 @@ export const wipClusterPageContents = async () => { _wip_searchPersons = undefined; triggerStatusUpdate(); - const { faces } = await clusterFaces(await faceIndexes()); + const { faceAndNeigbours } = await clusterFaces(await faceIndexes()); // const searchPersons = await convertToSearchPersons(clusters, cgroups); const localFiles = await getAllLocalFiles(); const localFileByID = new Map(localFiles.map((f) => [f.id, f])); + const fileForFace = ({ faceID }: Face) => + localFileByID.get(ensure(fileIDFromFaceID(faceID))); - const result1: { file: EnteFile; face: Face }[] = []; - for (const face of faces) { - const file = ensure( - localFileByID.get(ensure(fileIDFromFaceID(face.faceID))), - ); - result1.push({ file, face }); - } - - const result = result1.sort((a, b) => b.face.score - a.face.score); + const result = faceAndNeigbours + .map(({ face, neighbours }) => ({ + face, + neighbours: neighbours.map(({ face, cosineSimilarity }) => ({ + face, + enteFile: fileForFace(face), + cosineSimilarity, + })), + })) + .sort((a, b) => b.face.score - a.face.score); _wip_isClustering = false; // _wip_searchPersons = searchPersons; From 77cf819ab4d53edc136540ef1953e2941007ad26 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 16:07:38 +0530 Subject: [PATCH 071/275] Indicate cluster --- web/apps/photos/src/pages/cluster-debug.tsx | 54 ++++++++++++++------ web/packages/new/photos/services/ml/index.ts | 28 +++++++--- 2 files changed, 59 insertions(+), 23 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 25f9b36031..ad2a16fb96 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -2,7 +2,8 @@ import { SelectionBar } from "@/base/components/Navbar"; import { pt } from "@/base/i18n"; import { faceCrop, - wipClusterPageContents, + wipClusterDebugPageContents, + type ClusterDebugPageContents, type FaceFileNeighbour, type FaceFileNeighbours, } from "@/new/photos/services/ml"; @@ -23,7 +24,9 @@ import { VariableSizeList } from "react-window"; // TODO-Cluster Temporary component for debugging export default function ClusterDebug() { const { startLoading, finishLoading, showNavBar } = useContext(AppContext); - const [faceFNs, setFaceFNs] = useState(null); + const [clusterRes, setClusterRes] = useState< + ClusterDebugPageContents | undefined + >(); useEffect(() => { showNavBar(true); @@ -32,20 +35,20 @@ export default function ClusterDebug() { const cluster = async () => { startLoading(); - setFaceFNs(await wipClusterPageContents()); + setClusterRes(await wipClusterDebugPageContents()); finishLoading(); }; return ( <> - {faceFNs ? ( + {clusterRes ? ( {({ height, width }) => ( )} @@ -91,14 +94,15 @@ const Container = styled("div")` interface ClusterPhotoListProps { height: number; width: number; - faceFNs: FaceFileNeighbours[]; + clusterRes: ClusterDebugPageContents; } const ClusterPhotoList: React.FC = ({ height, width, - faceFNs, + clusterRes, }) => { + const { faceFNs, clusterIDForFaceID } = clusterRes; const [itemList, setItemList] = useState([]); const listRef = useRef(null); @@ -108,7 +112,7 @@ const ClusterPhotoList: React.FC = ({ ); const shrinkRatio = getShrinkRatio(width, columns); - const listItemHeight = 120 * shrinkRatio + 4; + const listItemHeight = 120 * shrinkRatio + 24 + 4; useEffect(() => { setItemList(itemListFromFaceFNs(faceFNs, columns)); @@ -152,8 +156,11 @@ const ClusterPhotoList: React.FC = ({ {`score ${item.toFixed(2)}`} ) : ( - item.map((ffn, i) => ( - + item.map((faceFN, i) => ( + )) )} @@ -192,11 +199,13 @@ const getShrinkRatio = (width: number, columns: number) => (width - 2 * getGapFromScreenEdge(width) - (columns - 1) * 4) / (columns * 120); -const FaceItem: React.FC = ({ - face, - enteFile, - cosineSimilarity, -}) => { +interface FaceItemProps { + faceFN: FaceFileNeighbour; + clusterIDForFaceID: Map; +} + +const FaceItem: React.FC = ({ faceFN, clusterIDForFaceID }) => { + const { face, enteFile, cosineSimilarity } = faceFN; const { faceID } = face; const [objectURL, setObjectURL] = useState(); @@ -217,7 +226,12 @@ const FaceItem: React.FC = ({ }, [faceID, enteFile]); return ( - + {objectURL && ( = ({ src={objectURL} /> )} - + {cosineSimilarity.toFixed(2)} @@ -240,6 +254,12 @@ const FaceChip = styled(Box)` height: 120px; `; +const outlineForCluster = (clusterID: string | undefined) => + clusterID ? `1px solid oklch(0.7 0.1 ${hForID(clusterID)})` : undefined; + +const hForID = (id: string) => + ([...id].reduce((s, c) => s + c.charCodeAt(0), 0) % 10) * 36; + const ListContainer = styled(Box, { shouldForwardProp: (propName) => propName != "shrinkRatio", })<{ diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 0d1b2f105e..6b0a72be69 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -354,23 +354,33 @@ export interface FaceFileNeighbour { cosineSimilarity: number; } -export const wipClusterPageContents = async () => { - if (!(await wipClusterEnable())) return []; +export interface ClusterDebugPageContents { + faceFNs: FaceFileNeighbours[]; + clusters: FaceCluster[]; + clusterIDForFaceID: Map; +} + +export const wipClusterDebugPageContents = async (): Promise< + ClusterDebugPageContents | undefined +> => { + if (!(await wipClusterEnable())) return undefined; log.info("clustering"); _wip_isClustering = true; _wip_searchPersons = undefined; triggerStatusUpdate(); - const { faceAndNeigbours } = await clusterFaces(await faceIndexes()); + const { faceAndNeigbours, clusters } = await clusterFaces( + await faceIndexes(), + ); // const searchPersons = await convertToSearchPersons(clusters, cgroups); const localFiles = await getAllLocalFiles(); const localFileByID = new Map(localFiles.map((f) => [f.id, f])); const fileForFace = ({ faceID }: Face) => - localFileByID.get(ensure(fileIDFromFaceID(faceID))); + ensure(localFileByID.get(ensure(fileIDFromFaceID(faceID)))); - const result = faceAndNeigbours + const faceFNs = faceAndNeigbours .map(({ face, neighbours }) => ({ face, neighbours: neighbours.map(({ face, cosineSimilarity }) => ({ @@ -381,12 +391,18 @@ export const wipClusterPageContents = async () => { })) .sort((a, b) => b.face.score - a.face.score); + const clusterIDForFaceID = new Map( + clusters.flatMap((cluster) => + cluster.faceIDs.map((id) => [id, cluster.id]), + ), + ); + _wip_isClustering = false; // _wip_searchPersons = searchPersons; triggerStatusUpdate(); // return { faces, clusters, cgroups }; - return result; + return { faceFNs, clusters, clusterIDForFaceID }; }; export const wipCluster = async () => { From dac0dfb8f97dd072a3ead3b751b057d3d8dab195 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 16:24:41 +0530 Subject: [PATCH 072/275] Set cgroups --- web/apps/photos/src/pages/gallery/index.tsx | 13 +++++++++---- web/packages/new/photos/services/ml/index.ts | 14 ++++++++++---- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/web/apps/photos/src/pages/gallery/index.tsx b/web/apps/photos/src/pages/gallery/index.tsx index 04b4e611e7..adce308172 100644 --- a/web/apps/photos/src/pages/gallery/index.tsx +++ b/web/apps/photos/src/pages/gallery/index.tsx @@ -6,7 +6,10 @@ import { getLocalFiles, getLocalTrashedFiles, } from "@/new/photos/services/files"; -import { wipClusterEnable } from "@/new/photos/services/ml"; +import { + wipClusterEnable, + wipHasSwitchedOnceCmpAndSet, +} from "@/new/photos/services/ml"; import { EnteFile } from "@/new/photos/types/file"; import { mergeMetadata } from "@/new/photos/utils/file"; import { CenteredFlex } from "@ente/shared/components/Container"; @@ -674,9 +677,11 @@ export default function Gallery() { // TODO-Cluster if (process.env.NEXT_PUBLIC_ENTE_WIP_CL) { setTimeout(() => { - void wipClusterEnable().then( - (y) => y && router.push("cluster-debug"), - ); + if (!wipHasSwitchedOnceCmpAndSet()) { + void wipClusterEnable().then( + (y) => y && router.push("cluster-debug"), + ); + } }, 2000); } }, []); diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 6b0a72be69..9b8db7cb9c 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -337,6 +337,13 @@ export const wipClusterEnable = async (): Promise => // // TODO-Cluster temporary state here let _wip_isClustering = false; let _wip_searchPersons: SearchPerson[] | undefined; +let _wip_hasSwitchedOnce = false; + +export const wipHasSwitchedOnceCmpAndSet = () => { + if (_wip_hasSwitchedOnce) return true; + _wip_hasSwitchedOnce = true; + return false; +}; export const wipSearchPersons = async () => { if (!(await wipClusterEnable())) return []; @@ -370,10 +377,10 @@ export const wipClusterDebugPageContents = async (): Promise< _wip_searchPersons = undefined; triggerStatusUpdate(); - const { faceAndNeigbours, clusters } = await clusterFaces( + const { faceAndNeigbours, clusters, cgroups } = await clusterFaces( await faceIndexes(), ); - // const searchPersons = await convertToSearchPersons(clusters, cgroups); + const searchPersons = await convertToSearchPersons(clusters, cgroups); const localFiles = await getAllLocalFiles(); const localFileByID = new Map(localFiles.map((f) => [f.id, f])); @@ -398,10 +405,9 @@ export const wipClusterDebugPageContents = async (): Promise< ); _wip_isClustering = false; - // _wip_searchPersons = searchPersons; + _wip_searchPersons = searchPersons; triggerStatusUpdate(); - // return { faces, clusters, cgroups }; return { faceFNs, clusters, clusterIDForFaceID }; }; From 3cebd975a8711b7f0bd2aff170c736480024d4ba Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Wed, 28 Aug 2024 16:38:56 +0530 Subject: [PATCH 073/275] Update string --- mobile/lib/l10n/intl_en.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/lib/l10n/intl_en.arb b/mobile/lib/l10n/intl_en.arb index 2bbf04897c..ae78fa60c3 100644 --- a/mobile/lib/l10n/intl_en.arb +++ b/mobile/lib/l10n/intl_en.arb @@ -12,7 +12,7 @@ "deleteAccountFeedbackPrompt": "We are sorry to see you go. Please share your feedback to help us improve.", "feedback": "Feedback", "kindlyHelpUsWithThisInformation": "Kindly help us with this information", - "confirmDeletePrompt": "Yes, I want to permanently delete this account and all its data.", + "confirmDeletePrompt": "Yes, I want to permanently delete this account and its data across all apps.", "confirmAccountDeletion": "Confirm Account Deletion", "deleteAccountPermanentlyButton": "Delete Account Permanently", "yourAccountHasBeenDeleted": "Your account has been deleted", From ac5d9d99f1c79bd3291db9dbfa8131635200fbae Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Wed, 28 Aug 2024 13:46:58 +0200 Subject: [PATCH 074/275] [mob][photos] ML user developer options --- mobile/lib/db/ml/db.dart | 16 +++ .../machine_learning_settings_page.dart | 29 ++++- .../ui/settings/ml/ml_user_dev_screen.dart | 103 ++++++++++++++++++ 3 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 mobile/lib/ui/settings/ml/ml_user_dev_screen.dart diff --git a/mobile/lib/db/ml/db.dart b/mobile/lib/db/ml/db.dart index 5f5cb7af35..3103e80442 100644 --- a/mobile/lib/db/ml/db.dart +++ b/mobile/lib/db/ml/db.dart @@ -668,6 +668,22 @@ class MLDataDB { return maps.first['count'] as int; } + Future> getErroredFileIDs() async { + final db = await instance.asyncDB; + final List> maps = await db.getAll( + 'SELECT DISTINCT $fileIDColumn FROM $facesTable WHERE $faceScore < 0', + ); + return maps.map((e) => e[fileIDColumn] as int).toSet(); + } + + Future deleteFaceIndexForFiles(List fileIDs) async { + final db = await instance.asyncDB; + final String sql = ''' + DELETE FROM $facesTable WHERE $fileIDColumn IN (${fileIDs.join(", ")}) + '''; + await db.execute(sql); + } + Future getClusteredOrFacelessFileCount() async { final db = await instance.asyncDB; final List> clustered = await db.getAll( diff --git a/mobile/lib/ui/settings/machine_learning_settings_page.dart b/mobile/lib/ui/settings/machine_learning_settings_page.dart index cf83d4a800..8267648ad4 100644 --- a/mobile/lib/ui/settings/machine_learning_settings_page.dart +++ b/mobile/lib/ui/settings/machine_learning_settings_page.dart @@ -26,6 +26,7 @@ import "package:photos/ui/components/title_bar_title_widget.dart"; import "package:photos/ui/components/title_bar_widget.dart"; import "package:photos/ui/components/toggle_switch_widget.dart"; import "package:photos/ui/settings/ml/enable_ml_consent.dart"; +import "package:photos/ui/settings/ml/ml_user_dev_screen.dart"; import "package:photos/utils/ml_util.dart"; import "package:photos/utils/network_util.dart"; import "package:photos/utils/wakelock_util.dart"; @@ -42,6 +43,8 @@ class _MachineLearningSettingsPageState extends State { final EnteWakeLock _wakeLock = EnteWakeLock(); Timer? _timer; + int _titleTapCount = 0; + Timer? _advancedOptionsTimer; @override void initState() { @@ -55,6 +58,9 @@ class _MachineLearningSettingsPageState } }); } + _advancedOptionsTimer = Timer.periodic(const Duration(seconds: 7), (timer) { + _titleTapCount = 0; + }); } @override @@ -63,6 +69,7 @@ class _MachineLearningSettingsPageState _wakeLock.disable(); MachineLearningController.instance.forceOverrideML(turnOn: false); _timer?.cancel(); + _advancedOptionsTimer?.cancel(); } @override @@ -73,8 +80,26 @@ class _MachineLearningSettingsPageState primary: false, slivers: [ TitleBarWidget( - flexibleSpaceTitle: TitleBarTitleWidget( - title: S.of(context).machineLearning, + flexibleSpaceTitle: GestureDetector( + child: TitleBarTitleWidget( + title: S.of(context).machineLearning, + ), + onTap: () { + setState(() { + _titleTapCount++; + if (_titleTapCount >= 7) { + _titleTapCount = 0; + // showShortToast(context, "Advanced options enabled"); + Navigator.of(context).push( + MaterialPageRoute( + builder: (BuildContext context) { + return const MLUserDeveloperOptions(); + }, + ), + ).ignore(); + } + }); + }, ), actionIcons: [ IconButtonWidget( diff --git a/mobile/lib/ui/settings/ml/ml_user_dev_screen.dart b/mobile/lib/ui/settings/ml/ml_user_dev_screen.dart new file mode 100644 index 0000000000..8d70cee21b --- /dev/null +++ b/mobile/lib/ui/settings/ml/ml_user_dev_screen.dart @@ -0,0 +1,103 @@ +import "package:flutter/material.dart"; +import "package:photos/core/event_bus.dart"; +import "package:photos/db/ml/clip_db.dart"; +import "package:photos/db/ml/db.dart"; +import "package:photos/events/people_changed_event.dart"; +import "package:photos/services/machine_learning/semantic_search/semantic_search_service.dart"; +import "package:photos/theme/ente_theme.dart"; +import "package:photos/ui/components/buttons/button_widget.dart"; +import "package:photos/ui/components/models/button_type.dart"; +import "package:photos/ui/components/title_bar_title_widget.dart"; +import "package:photos/ui/components/title_bar_widget.dart"; +import "package:photos/utils/dialog_util.dart"; +import "package:photos/utils/toast_util.dart"; + +class MLUserDeveloperOptions extends StatelessWidget { + const MLUserDeveloperOptions({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: CustomScrollView( + primary: false, + slivers: [ + const TitleBarWidget( + flexibleSpaceTitle: TitleBarTitleWidget( + title: "ML debug options", + ), + ), + SliverList( + delegate: SliverChildBuilderDelegate( + (delegateBuildContext, index) => Padding( + padding: const EdgeInsets.only(left: 16, right: 16), + child: Column( + children: [ + Text( + "Only use if you know what you're doing", + textAlign: TextAlign.left, + style: getEnteTextTheme(context).body.copyWith( + color: getEnteColorScheme(context).textMuted, + ), + ), + const SizedBox(height: 48), + ButtonWidget( + buttonType: ButtonType.neutral, + labelText: "Purge empty indices", + onTap: () async { + await deleteEmptyIndices(context); + }, + ), + const SizedBox(height: 24), + ButtonWidget( + buttonType: ButtonType.neutral, + labelText: "Reset all local ML", + onTap: () async { + await deleteAllLocalML(context); + }, + ), + const SafeArea( + child: SizedBox( + height: 12, + ), + ), + ], + ), + ), + childCount: 1, + ), + ), + ], + ), + ); + } + + Future deleteEmptyIndices(BuildContext context) async { + try { + final Set emptyFileIDs = await MLDataDB.instance.getErroredFileIDs(); + await MLDataDB.instance.deleteFaceIndexForFiles(emptyFileIDs.toList()); + await MLDataDB.instance.deleteEmbeddings(emptyFileIDs.toList()); + showShortToast(context, "Deleted ${emptyFileIDs.length} entries"); + } catch (e) { + // ignore: unawaited_futures + showGenericErrorDialog( + context: context, + error: e, + ); + } + } + + Future deleteAllLocalML(BuildContext context) async { + try { + await MLDataDB.instance.dropClustersAndPersonTable(faces: true); + await SemanticSearchService.instance.clearIndexes(); + Bus.instance.fire(PeopleChangedEvent()); + showShortToast(context, "All local ML cleared"); + } catch (e) { + // ignore: unawaited_futures + showGenericErrorDialog( + context: context, + error: e, + ); + } + } +} From dd6f88a1cd39eafcae32e39d3ce9c73ccf5b952f Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Wed, 28 Aug 2024 13:49:07 +0200 Subject: [PATCH 075/275] [mob][photos] Move --- mobile/lib/ui/settings/advanced_settings_screen.dart | 2 +- .../ui/settings/{ => ml}/machine_learning_settings_page.dart | 0 mobile/lib/ui/viewer/search_tab/people_section.dart | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename mobile/lib/ui/settings/{ => ml}/machine_learning_settings_page.dart (100%) diff --git a/mobile/lib/ui/settings/advanced_settings_screen.dart b/mobile/lib/ui/settings/advanced_settings_screen.dart index 6792f254bd..b2e5f5a488 100644 --- a/mobile/lib/ui/settings/advanced_settings_screen.dart +++ b/mobile/lib/ui/settings/advanced_settings_screen.dart @@ -13,7 +13,7 @@ import 'package:photos/ui/components/menu_item_widget/menu_item_widget.dart'; import 'package:photos/ui/components/title_bar_title_widget.dart'; import 'package:photos/ui/components/title_bar_widget.dart'; import "package:photos/ui/components/toggle_switch_widget.dart"; -import "package:photos/ui/settings/machine_learning_settings_page.dart"; +import "package:photos/ui/settings/ml/machine_learning_settings_page.dart"; import 'package:photos/ui/tools/debug/app_storage_viewer.dart'; import 'package:photos/ui/viewer/gallery/photo_grid_size_picker_page.dart'; import 'package:photos/utils/navigation_util.dart'; diff --git a/mobile/lib/ui/settings/machine_learning_settings_page.dart b/mobile/lib/ui/settings/ml/machine_learning_settings_page.dart similarity index 100% rename from mobile/lib/ui/settings/machine_learning_settings_page.dart rename to mobile/lib/ui/settings/ml/machine_learning_settings_page.dart diff --git a/mobile/lib/ui/viewer/search_tab/people_section.dart b/mobile/lib/ui/viewer/search_tab/people_section.dart index 3e1d7599e5..4ebcbbf9d6 100644 --- a/mobile/lib/ui/viewer/search_tab/people_section.dart +++ b/mobile/lib/ui/viewer/search_tab/people_section.dart @@ -13,7 +13,7 @@ import "package:photos/models/search/search_constants.dart"; import "package:photos/models/search/search_result.dart"; import "package:photos/models/search/search_types.dart"; import "package:photos/theme/ente_theme.dart"; -import "package:photos/ui/settings/machine_learning_settings_page.dart"; +import "package:photos/ui/settings/ml/machine_learning_settings_page.dart"; import "package:photos/ui/viewer/file/no_thumbnail_widget.dart"; import "package:photos/ui/viewer/file/thumbnail_widget.dart"; import "package:photos/ui/viewer/people/add_person_action_sheet.dart"; From 2d50da84c868f999c3f8efdaf2e52aa9dec36719 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 17:29:52 +0530 Subject: [PATCH 076/275] Show blur --- web/apps/photos/src/pages/cluster-debug.tsx | 17 +++++++++-------- .../new/photos/services/ml/cluster-new.ts | 3 ++- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index ad2a16fb96..9655976a21 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -7,6 +7,7 @@ import { type FaceFileNeighbour, type FaceFileNeighbours, } from "@/new/photos/services/ml"; +import type { Face } from "@/new/photos/services/ml/face"; import { FlexWrapper, FluidContainer, @@ -123,12 +124,12 @@ const ClusterPhotoList: React.FC = ({ }, [itemList]); const getItemSize = (i: number) => - typeof itemList[i] == "number" ? 36 : listItemHeight; + Array.isArray(itemList[i]) ? listItemHeight : 36; const generateKey = (i: number) => - typeof itemList[i] == "number" - ? `${itemList[i]}-${i}` - : `${itemList[i][0].enteFile.id}/${itemList[i][0].face.faceID}-${itemList[i].slice(-1)[0].enteFile.id}/${itemList[i].slice(-1)[0].face.faceID}-${i}`; + Array.isArray(itemList[i]) + ? `${itemList[i][0].enteFile.id}/${itemList[i][0].face.faceID}-${itemList[i].slice(-1)[0].enteFile.id}/${itemList[i].slice(-1)[0].face.faceID}-${i}` + : `${itemList[i].faceID}-${i}`; return ( = ({ columns={columns} shrinkRatio={shrinkRatio} > - {typeof item == "number" ? ( + {!Array.isArray(item) ? ( - {`score ${item.toFixed(2)}`} + {`score ${item.score.toFixed(2)} blur ${item.blur.toFixed(0)}`} ) : ( item.map((faceFN, i) => ( @@ -171,7 +172,7 @@ const ClusterPhotoList: React.FC = ({ ); }; -type ItemListItem = number | FaceFileNeighbour[]; +type ItemListItem = Face | FaceFileNeighbour[]; const itemListFromFaceFNs = ( faceFNs: FaceFileNeighbours[], @@ -180,7 +181,7 @@ const itemListFromFaceFNs = ( const result: ItemListItem[] = []; for (let index = 0; index < faceFNs.length; index++) { const { face, neighbours } = faceFNs[index]; - result.push(face.score); + result.push(face); let lastIndex = 0; while (lastIndex < neighbours.length) { result.push(neighbours.slice(lastIndex, lastIndex + columns)); diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index e67688abc0..4cec15a86e 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -201,7 +201,7 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { for (let j = 0; j < faces.length; j++) { // ! This is an O(n^2) loop, be careful when adding more code here. - // TODO-Cluster + // TODO-Cluster Commenting this here and moving it downward // // Skip ourselves. // if (i == j) continue; @@ -213,6 +213,7 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { // dot product as their cosine similarity. const csim = dotProduct(embedding, n.embedding); + // TODO-Cluster Delete me and uncomment the check above // Skip ourselves. if (i == j) { neighbours.push({ face: n, cosineSimilarity: csim }); From 72cc188efede85c3af235bd29f36e584acd2e74e Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 17:39:09 +0530 Subject: [PATCH 077/275] Incorporate blur --- web/apps/photos/src/pages/cluster-debug.tsx | 2 +- web/packages/new/photos/services/ml/cluster-new.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 9655976a21..683ce6bec6 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -256,7 +256,7 @@ const FaceChip = styled(Box)` `; const outlineForCluster = (clusterID: string | undefined) => - clusterID ? `1px solid oklch(0.7 0.1 ${hForID(clusterID)})` : undefined; + clusterID ? `1px solid oklch(0.8 0.2 ${hForID(clusterID)})` : undefined; const hForID = (id: string) => ([...id].reduce((s, c) => s + c.charCodeAt(0), 0) % 10) * 36; diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index 4cec15a86e..9d5c57b84d 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -190,7 +190,7 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { const faceAndNeigbours: FaceNeighbours[] = []; // For each face, - for (const [i, { faceID, embedding }] of faces.entries()) { + for (const [i, { faceID, blur, embedding }] of faces.entries()) { // If the face is already part of a cluster, then skip it. if (clusterIDForFaceID.get(faceID)) continue; @@ -220,7 +220,8 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { continue; } - if (csim > 0.76 && csim > nnCosineSimilarity) { + const threshold = blur < 100 || n.blur < 100 ? 0.7 : 0.6; + if (csim > threshold && csim > nnCosineSimilarity) { nn = n; nnCosineSimilarity = csim; } From cd5e40a1f504452b5e7c227129d7f62f997eaa06 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 17:41:30 +0530 Subject: [PATCH 078/275] Vars --- .../new/photos/services/ml/cluster-new.ts | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index 9d5c57b84d..c0f5dd51c2 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -190,9 +190,9 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { const faceAndNeigbours: FaceNeighbours[] = []; // For each face, - for (const [i, { faceID, blur, embedding }] of faces.entries()) { + for (const [i, fi] of faces.entries()) { // If the face is already part of a cluster, then skip it. - if (clusterIDForFaceID.get(faceID)) continue; + if (clusterIDForFaceID.get(fi.faceID)) continue; // Find the nearest neighbour from among all the other faces. let nn: Face | undefined; @@ -207,26 +207,26 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { // Can't find a way of avoiding the null assertion here. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const n = faces[j]!; + const fj = faces[j]!; // The vectors are already normalized, so we can directly use their // dot product as their cosine similarity. - const csim = dotProduct(embedding, n.embedding); + const csim = dotProduct(fi.embedding, fj.embedding); // TODO-Cluster Delete me and uncomment the check above // Skip ourselves. if (i == j) { - neighbours.push({ face: n, cosineSimilarity: csim }); + neighbours.push({ face: fj, cosineSimilarity: csim }); continue; } - const threshold = blur < 100 || n.blur < 100 ? 0.7 : 0.6; + const threshold = fi.blur < 100 || fj.blur < 100 ? 0.7 : 0.6; if (csim > threshold && csim > nnCosineSimilarity) { - nn = n; + nn = fj; nnCosineSimilarity = csim; } - neighbours.push({ face: n, cosineSimilarity: csim }); + neighbours.push({ face: fj, cosineSimilarity: csim }); } neighbours = neighbours.sort( @@ -235,8 +235,11 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion faceAndNeigbours.push({ face: faces[i]!, neighbours }); + const { faceID } = fi; + if (nn) { // Found a neighbour near enough. + const nnFaceID = nn.faceID; // Find the cluster the nearest neighbour belongs to, if any. const nnClusterID = clusterIDForFaceID.get(nn.faceID); @@ -256,11 +259,11 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { const cluster = { id: newClusterID(), - faceIDs: [faceID, nn.faceID], + faceIDs: [faceID, nnFaceID], }; clusterIndexForClusterID.set(cluster.id, clusters.length); clusterIDForFaceID.set(faceID, cluster.id); - clusterIDForFaceID.set(nn.faceID, cluster.id); + clusterIDForFaceID.set(nnFaceID, cluster.id); clusters.push(cluster); } } else { From 14ac034c0ba53762d3cd62fc330b715faadc0c46 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 17:49:36 +0530 Subject: [PATCH 079/275] Provide both options --- web/apps/photos/src/pages/gallery/index.tsx | 2 +- .../new/photos/components/MLSettings.tsx | 32 +++++++++++++------ web/packages/new/photos/services/ml/index.ts | 16 +--------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/web/apps/photos/src/pages/gallery/index.tsx b/web/apps/photos/src/pages/gallery/index.tsx index adce308172..1876fca7f4 100644 --- a/web/apps/photos/src/pages/gallery/index.tsx +++ b/web/apps/photos/src/pages/gallery/index.tsx @@ -675,7 +675,7 @@ export default function Gallery() { useEffect(() => { // TODO-Cluster - if (process.env.NEXT_PUBLIC_ENTE_WIP_CL) { + if (process.env.NEXT_PUBLIC_ENTE_WIP_CL_AUTO) { setTimeout(() => { if (!wipHasSwitchedOnceCmpAndSet()) { void wipClusterEnable().then( diff --git a/web/packages/new/photos/components/MLSettings.tsx b/web/packages/new/photos/components/MLSettings.tsx index fb3e6ea008..08e17c7ff1 100644 --- a/web/packages/new/photos/components/MLSettings.tsx +++ b/web/packages/new/photos/components/MLSettings.tsx @@ -1,5 +1,5 @@ import { EnteDrawer } from "@/base/components/EnteDrawer"; -import { MenuItemGroup } from "@/base/components/Menu"; +import { MenuItemGroup, MenuSectionTitle } from "@/base/components/Menu"; import { Titlebar } from "@/base/components/Titlebar"; import { pt, ut } from "@/base/i18n"; import log from "@/base/log"; @@ -8,6 +8,7 @@ import { enableML, mlStatusSnapshot, mlStatusSubscribe, + wipCluster, wipClusterEnable, type MLStatus, } from "@/new/photos/services/ml"; @@ -339,9 +340,9 @@ const ManageML: React.FC = ({ }; // TODO-Cluster - // const wipClusterNow = () => void wipCluster(); const router = useRouter(); - const wipClusterNow = () => router.push("/cluster-debug"); + const wipClusterNow = () => wipCluster(); + const wipClusterShowNow = () => router.push("/cluster-debug"); return ( @@ -390,17 +391,30 @@ const ManageML: React.FC = ({ - {/* */} + /> + + )} + {showClusterOpt && ( + + + + + )} diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 9b8db7cb9c..f53e755502 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -411,21 +411,7 @@ export const wipClusterDebugPageContents = async (): Promise< return { faceFNs, clusters, clusterIDForFaceID }; }; -export const wipCluster = async () => { - if (!(await wipClusterEnable())) return; - - log.info("clustering"); - _wip_isClustering = true; - _wip_searchPersons = undefined; - triggerStatusUpdate(); - - const { clusters, cgroups } = await clusterFaces(await faceIndexes()); - const searchPersons = await convertToSearchPersons(clusters, cgroups); - - _wip_isClustering = false; - _wip_searchPersons = searchPersons; - triggerStatusUpdate(); -}; +export const wipCluster = () => void wipClusterDebugPageContents(); const convertToSearchPersons = async ( clusters: FaceCluster[], From 3563c20997dd6b7c261944292ed95ab0869d7d89 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 20:04:59 +0530 Subject: [PATCH 080/275] Add limits --- web/apps/photos/src/pages/cluster-debug.tsx | 43 +++++++++++-------- .../new/photos/components/MLSettings.tsx | 4 +- .../new/photos/services/ml/cluster-new.ts | 2 +- web/packages/new/photos/services/ml/index.ts | 7 ++- 4 files changed, 35 insertions(+), 21 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 683ce6bec6..c6abe7226f 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -40,25 +40,34 @@ export default function ClusterDebug() { finishLoading(); }; + if (!clusterRes) { + return ( + + + + ); + } return ( <> - {clusterRes ? ( - - - {({ height, width }) => ( - - )} - - - ) : ( - - - - )} + + {`${clusterRes.clusters.length} clusters`} + + + Showing only upto first 30 faces (and only upto 30 nearest + neighbours of each). + +
+ + + {({ height, width }) => ( + + )} + + ); diff --git a/web/packages/new/photos/components/MLSettings.tsx b/web/packages/new/photos/components/MLSettings.tsx index 08e17c7ff1..337bc906e8 100644 --- a/web/packages/new/photos/components/MLSettings.tsx +++ b/web/packages/new/photos/components/MLSettings.tsx @@ -397,7 +397,7 @@ const ManageML: React.FC = ({ @@ -412,7 +412,7 @@ const ManageML: React.FC = ({ diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index c0f5dd51c2..445a91bbba 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -168,7 +168,7 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { const t = Date.now(); // A flattened array of faces. - const faces = [...enumerateFaces(faceIndexes)]; + const faces = [...enumerateFaces(faceIndexes)].slice(0, 900); // Start with the clusters we already have (either from a previous indexing, // or fetched from remote). diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index f53e755502..0567793fbe 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -408,7 +408,12 @@ export const wipClusterDebugPageContents = async (): Promise< _wip_searchPersons = searchPersons; triggerStatusUpdate(); - return { faceFNs, clusters, clusterIDForFaceID }; + const prunedFaceFNs = faceFNs.slice(0, 30).map(({ face, neighbours }) => ({ + face, + neighbours: neighbours.slice(0, 30), + })); + + return { faceFNs: prunedFaceFNs, clusters, clusterIDForFaceID }; }; export const wipCluster = () => void wipClusterDebugPageContents(); From 5aae59cdda0f64b2525902bfb170952daa884c70 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 20:10:23 +0530 Subject: [PATCH 081/275] Add limits --- web/packages/new/photos/components/MLSettings.tsx | 2 +- web/packages/new/photos/services/ml/cluster-new.ts | 2 +- web/packages/new/photos/services/ml/index.ts | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/web/packages/new/photos/components/MLSettings.tsx b/web/packages/new/photos/components/MLSettings.tsx index 337bc906e8..eeff4d1be8 100644 --- a/web/packages/new/photos/components/MLSettings.tsx +++ b/web/packages/new/photos/components/MLSettings.tsx @@ -397,7 +397,7 @@ const ManageML: React.FC = ({ diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index 445a91bbba..eb59c7d703 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -168,7 +168,7 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { const t = Date.now(); // A flattened array of faces. - const faces = [...enumerateFaces(faceIndexes)].slice(0, 900); + const faces = [...enumerateFaces(faceIndexes)].slice(0, 2000); // Start with the clusters we already have (either from a previous indexing, // or fetched from remote). diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 0567793fbe..2b4a1a044f 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -330,8 +330,7 @@ export const indexNewUpload = (enteFile: EnteFile, uploadItem: UploadItem) => { * WIP! Don't enable, dragon eggs are hatching here. */ export const wipClusterEnable = async (): Promise => - !!process.env.NEXT_PUBLIC_ENTE_WIP_CL && - isDevBuild && + (!!process.env.NEXT_PUBLIC_ENTE_WIP_CL && isDevBuild) || (await isInternalUser()); // // TODO-Cluster temporary state here From ac5d37a9e3f94609c3351f3922c8ab8ba6822287 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 20:34:42 +0530 Subject: [PATCH 082/275] Not helping, this is just causing it to run twice --- .github/workflows/web-lint.yml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.github/workflows/web-lint.yml b/.github/workflows/web-lint.yml index 6655587175..c64463384c 100644 --- a/.github/workflows/web-lint.yml +++ b/.github/workflows/web-lint.yml @@ -2,21 +2,10 @@ name: "Lint (web)" on: # Run on every pull request (open or push to it) that changes web/ - # - # This is for running lints on pull requests from external contributors. pull_request: paths: - "web/**" - ".github/workflows/web-lint.yml" - # Run on every push (to a non-main branch) that changes web/ - # - # This reduces the delay in waiting for the pull_request to kick in for the - # PRs from existing contributors. - push: - branches-ignore: [main] - paths: - - "web/**" - - ".github/workflows/web-lint.yml" jobs: lint: From 5ca3ca5289ae60fe5d972c9233604e1c462eeca8 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 28 Aug 2024 20:38:28 +0530 Subject: [PATCH 083/275] Add CHANGELOG entry --- desktop/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/desktop/CHANGELOG.md b/desktop/CHANGELOG.md index a48bbf7ab0..9a32cd383f 100644 --- a/desktop/CHANGELOG.md +++ b/desktop/CHANGELOG.md @@ -3,6 +3,7 @@ ## v1.7.4 (Unreleased) - Improved date search, including support for day of week and hour of day. +- Fix video thumbnail generation and upload on Intel macOS. - . ## v1.7.3 From ca1a292fb29ff5a928d2497ebe1a26ad2ed92a30 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 07:27:01 +0530 Subject: [PATCH 084/275] Prep to try the hdbscan --- .../new/photos/services/ml/cluster-new.ts | 118 +++++++++++++++++- .../new/photos/services/ml/cluster.ts | 2 +- 2 files changed, 117 insertions(+), 3 deletions(-) diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index eb59c7d703..51f9a44d6a 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -1,6 +1,7 @@ import { newNonSecureID } from "@/base/id-worker"; import log from "@/base/log"; import { ensure } from "@/utils/ensure"; +import { clusterFacesHdbscan } from "./cluster"; import { clusterGroups, faceClusters } from "./db"; import type { Face, FaceIndex } from "./face"; import { dotProduct } from "./math"; @@ -168,6 +169,7 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { const t = Date.now(); // A flattened array of faces. + // TODO-Cluster note the 2k slice const faces = [...enumerateFaces(faceIndexes)].slice(0, 2000); // Start with the clusters we already have (either from a previous indexing, @@ -232,8 +234,7 @@ export const clusterFaces = async (faceIndexes: FaceIndex[]) => { neighbours = neighbours.sort( (a, b) => b.cosineSimilarity - a.cosineSimilarity, ); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - faceAndNeigbours.push({ face: faces[i]!, neighbours }); + faceAndNeigbours.push({ face: fi, neighbours }); const { faceID } = fi; @@ -336,3 +337,116 @@ function* enumerateFaces(faceIndices: FaceIndex[]) { } } } + +export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { + const t = Date.now(); + + // A flattened array of faces. + // TODO-Cluster note the 2k slice + const faces = [...enumerateFaces(faceIndexes)].slice(0, 2000); + + const faceEmbeddings = faces.map(({ embedding }) => embedding); + + const { + clusters: clusterIndices, + noise, + debugInfo, + } = clusterFacesHdbscan(faceEmbeddings); + + log.info({ method: "hdbscan", clusterIndices, noise, debugInfo }); + log.info( + `Clustered ${faces.length} faces into ${clusterIndices.length} clusters (${Date.now() - t} ms)`, + ); + + // For fast reverse lookup - map from cluster ids to their index in the + // clusters array. + const clusterIndexForClusterID = new Map(); + + // For fast reverse lookup - map from face ids to the id of the cluster to + // which they belong. + const clusterIDForFaceID = new Map(); + + // A function to generate new cluster IDs. + const newClusterID = () => newNonSecureID("cluster_"); + + // Convert the numerical face indices into the result. + const clusters: FaceCluster[] = []; + for (const [ci, faceIndices] of clusterIndices.entries()) { + const clusterID = newClusterID(); + const faceIDs: string[] = []; + clusterIndexForClusterID.set(clusterID, ci); + for (const fi of faceIndices) { + // Can't find a way of avoiding the null assertion here. + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const face = faces[fi]!; + clusterIDForFaceID.set(face.faceID, clusterID); + faceIDs.push(face.faceID); + } + clusters.push({ id: clusterID, faceIDs }); + } + + // Convert into the data structure we're using to debug/visualize. + const faceAndNeigbours: FaceNeighbours[] = []; + for (const fi of faces) { + let neighbours: FaceNeighbour[] = []; + for (const fj of faces) { + // The vectors are already normalized, so we can directly use their + // dot product as their cosine similarity. + const csim = dotProduct(fi.embedding, fj.embedding); + neighbours.push({ face: fj, cosineSimilarity: csim }); + } + + neighbours = neighbours.sort( + (a, b) => b.cosineSimilarity - a.cosineSimilarity, + ); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + faceAndNeigbours.push({ face: fi, neighbours }); + } + + // Prune too small clusters. + const validClusters = clusters.filter(({ faceIDs }) => faceIDs.length > 1); + + let cgroups = await clusterGroups(); + + // TODO-Cluster - Currently we're not syncing with remote or saving anything + // locally, so cgroups will be empty. Create a temporary (unsaved, unsynced) + // cgroup, one per cluster. + cgroups = cgroups.concat( + validClusters.map((c) => ({ + id: c.id, + name: undefined, + clusterIDs: [c.id], + isHidden: false, + avatarFaceID: undefined, + displayFaceID: undefined, + })), + ); + + // For each cluster group, use the highest scoring face in any of its + // clusters as its display face. + const faceForFaceID = new Map(faces.map((f) => [f.faceID, f])); + for (const cgroup of cgroups) { + cgroup.displayFaceID = cgroup.clusterIDs + .map((clusterID) => clusterIndexForClusterID.get(clusterID)) + .filter((i) => i !== undefined) /* 0 is a valid index */ + .flatMap((i) => clusters[i]?.faceIDs ?? []) + .map((faceID) => faceForFaceID.get(faceID)) + .filter((face) => !!face) + .reduce((max, face) => + max.score > face.score ? max : face, + ).faceID; + } + + log.info("ml/cluster", { + faces, + validClusters, + clusterIndexForClusterID: Object.fromEntries(clusterIndexForClusterID), + clusterIDForFaceID: Object.fromEntries(clusterIDForFaceID), + cgroups, + }); + log.info( + `Clustered ${faces.length} faces into ${validClusters.length} clusters (${Date.now() - t} ms)`, + ); + + return { faces, clusters: validClusters, cgroups, faceAndNeigbours }; +}; diff --git a/web/packages/new/photos/services/ml/cluster.ts b/web/packages/new/photos/services/ml/cluster.ts index c3474b22b8..ff62f466a9 100644 --- a/web/packages/new/photos/services/ml/cluster.ts +++ b/web/packages/new/photos/services/ml/cluster.ts @@ -15,7 +15,7 @@ export interface ClusterFacesResult { * pipeline. Each embedding is for a face detected in an image (a single image * may have multiple faces detected within it). */ -export const clusterFaces = ( +export const clusterFacesHdbscan = ( faceEmbeddings: number[][], ): ClusterFacesResult => { const hdbscan = new Hdbscan({ From e84903d2ddd1dda07c58896ce2f2aa0870a9a8f6 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 08:01:43 +0530 Subject: [PATCH 085/275] Switch --- web/packages/new/photos/services/ml/index.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 2b4a1a044f..43d90578b8 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -20,7 +20,7 @@ import { getAllLocalFiles } from "../files"; import { getRemoteFlag, updateRemoteFlag } from "../remote-store"; import type { SearchPerson } from "../search/types"; import type { UploadItem } from "../upload/types"; -import { clusterFaces, type CGroup, type FaceCluster } from "./cluster-new"; +import { clusterFacesHdb, type CGroup, type FaceCluster } from "./cluster-new"; import { regenerateFaceCrops } from "./crop"; import { clearMLDB, @@ -376,7 +376,8 @@ export const wipClusterDebugPageContents = async (): Promise< _wip_searchPersons = undefined; triggerStatusUpdate(); - const { faceAndNeigbours, clusters, cgroups } = await clusterFaces( + // const { faceAndNeigbours, clusters, cgroups } = await clusterFaces( + const { faceAndNeigbours, clusters, cgroups } = await clusterFacesHdb( await faceIndexes(), ); const searchPersons = await convertToSearchPersons(clusters, cgroups); From 5dd1720b885862eae91c6eafa85e53b0ebb59ee7 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 08:13:56 +0530 Subject: [PATCH 086/275] lf --- web/packages/new/photos/services/ml/cluster-new.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index 51f9a44d6a..9e07b2812c 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -399,7 +399,7 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { neighbours = neighbours.sort( (a, b) => b.cosineSimilarity - a.cosineSimilarity, ); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + faceAndNeigbours.push({ face: fi, neighbours }); } From d5a8f234f8b4c306d0369a1f08aef46364773ece Mon Sep 17 00:00:00 2001 From: ashilkn Date: Thu, 29 Aug 2024 16:08:49 +0530 Subject: [PATCH 087/275] [mob][photos] fix: creating a new album from hidden section is not hidden by default --- mobile/lib/ui/collections/album/vertical_list.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mobile/lib/ui/collections/album/vertical_list.dart b/mobile/lib/ui/collections/album/vertical_list.dart index fd5814f183..825bbbdbd4 100644 --- a/mobile/lib/ui/collections/album/vertical_list.dart +++ b/mobile/lib/ui/collections/album/vertical_list.dart @@ -138,7 +138,8 @@ class AlbumVerticalListWidget extends StatelessWidget { bool hasVerifiedLock = false; late final Collection? collection; - if (actionType == CollectionActionType.moveToHiddenCollection) { + if (actionType == CollectionActionType.moveToHiddenCollection || + actionType == CollectionActionType.addToHiddenAlbum) { collection = await CollectionsService.instance.createHiddenAlbum(albumName); hasVerifiedLock = true; From d99e405f10aae48272115b55ff9a10693ac2927a Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 16:57:16 +0530 Subject: [PATCH 088/275] [web] Clear cached thumbnails if the source file is edited --- web/apps/photos/src/services/fileService.ts | 7 ++- web/packages/new/photos/services/files.ts | 59 +++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/web/apps/photos/src/services/fileService.ts b/web/apps/photos/src/services/fileService.ts index 82ce81ede0..ef364844a2 100644 --- a/web/apps/photos/src/services/fileService.ts +++ b/web/apps/photos/src/services/fileService.ts @@ -1,7 +1,11 @@ import { encryptMetadataJSON } from "@/base/crypto"; import log from "@/base/log"; import { apiURL } from "@/base/origins"; -import { getLocalFiles, setLocalFiles } from "@/new/photos/services/files"; +import { + clearCachedThumbnailsIfChanged, + getLocalFiles, + setLocalFiles, +} from "@/new/photos/services/files"; import { EncryptedEnteFile, EnteFile, @@ -47,6 +51,7 @@ export const syncFiles = async ( } const newFiles = await getFiles(collection, lastSyncTime, setFiles); + await clearCachedThumbnailsIfChanged(localFiles, newFiles); files = getLatestVersionFiles([...files, ...newFiles]); await setLocalFiles(type, files); didUpdateFiles = true; diff --git a/web/packages/new/photos/services/files.ts b/web/packages/new/photos/services/files.ts index 6a0ad4faa1..1d626a482f 100644 --- a/web/packages/new/photos/services/files.ts +++ b/web/packages/new/photos/services/files.ts @@ -1,3 +1,5 @@ +import { blobCache } from "@/base/blob-cache"; +import { FileType } from "@/media/file-type"; import localForage from "@ente/shared/storage/localForage"; import { type EnteFile, type Trash } from "../types/file"; import { mergeMetadata } from "../utils/file"; @@ -73,3 +75,60 @@ const sortTrashFiles = (files: EnteFile[]) => { return (a.deleteBy ?? 0) - (b.deleteBy ?? 0); }); }; + +/** + * Clear cached thumbnails for existing files if the thumbnail data has changed. + * + * This function in expected to be called when we are processing a collection + * diff, updating our local state to reflect files that were updated on remote. + * We use this as an opportune moment to invalidate any cached thumbnails which + * have changed. + * + * An example of when such invalidation is necessary: + * + * 1. Take a photo on mobile, and let it sync via the mobile app to us (web). + * 2. Edit the photo outside of Ente (e.g. using Apple Photos). + * 3. When the Ente mobile client next comes into foreground, it'll update the + * remote thumbnail for the existing file to reflect the changes. + * + * @param existingFiles The {@link EnteFile}s we had in our local database + * before processing the diff response. + * + * @param newFiles The {@link EnteFile}s which we got in the diff response. + */ +export const clearCachedThumbnailsIfChanged = async ( + existingFiles: EnteFile[], + newFiles: EnteFile[], +) => { + if (newFiles.length == 0) { + // Fastpath to no-op if nothing changes. + return; + } + + // TODO: This should be constructed once, at the caller (currently the + // caller doesn't need this, but we'll only know for sure after we + // consolidate all processing that happens during a diff parse). + const existingFileByID = new Map(existingFiles.map((f) => [f.id, f])); + + for (const newFile of newFiles) { + const existingFile = existingFileByID.get(newFile.id); + const m1 = existingFile?.metadata; + if (!m1) continue; + // Need to audit the types, until the add a ?? to be safe. + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + const m2 = newFile.metadata ?? {}; + // Both files exist, have metadata, but their (appropriate) hashes + // differ, which indicates that the change was in the file's contents, + // not the metadata itself, and thus we should refresh the thumbnail. + if ( + m1.fileType == FileType.livePhoto + ? m1.imageHash != m2.imageHash + : m1.hash != m2.hash + ) { + // This is an infrequent occurrence, so we lazily get the cache. + const thumbnailCache = await blobCache("thumbs"); + const key = newFile.id.toString(); + await thumbnailCache.delete(key); + } + } +}; From 3d2a66023d06d1f34fa389f8090bd5758898e15c Mon Sep 17 00:00:00 2001 From: Aaron Torres Date: Wed, 28 Aug 2024 20:30:25 -0700 Subject: [PATCH 089/275] Add RippleMatch icon --- auth/assets/custom-icons/_data/custom-icons.json | 4 ++++ auth/assets/custom-icons/icons/ripplematch.svg | 6 ++++++ 2 files changed, 10 insertions(+) create mode 100644 auth/assets/custom-icons/icons/ripplematch.svg diff --git a/auth/assets/custom-icons/_data/custom-icons.json b/auth/assets/custom-icons/_data/custom-icons.json index a04cb2b857..a7ad53bc20 100644 --- a/auth/assets/custom-icons/_data/custom-icons.json +++ b/auth/assets/custom-icons/_data/custom-icons.json @@ -702,6 +702,10 @@ "altNames": ["Newton Crypto"], "slug": "newton" }, + { + "title": "RippleMatch", + "slug": "ripplematch" + }, { "title": "T-Mobile ID", "altNames": [ diff --git a/auth/assets/custom-icons/icons/ripplematch.svg b/auth/assets/custom-icons/icons/ripplematch.svg new file mode 100644 index 0000000000..716e3d59ad --- /dev/null +++ b/auth/assets/custom-icons/icons/ripplematch.svg @@ -0,0 +1,6 @@ + + + + + + From 67361113af3574e54c860bf92504d3e3d44659b0 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 17:24:20 +0530 Subject: [PATCH 090/275] Help the linter move on --- web/packages/new/photos/services/files.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/packages/new/photos/services/files.ts b/web/packages/new/photos/services/files.ts index 1d626a482f..11fe776807 100644 --- a/web/packages/new/photos/services/files.ts +++ b/web/packages/new/photos/services/files.ts @@ -113,10 +113,10 @@ export const clearCachedThumbnailsIfChanged = async ( for (const newFile of newFiles) { const existingFile = existingFileByID.get(newFile.id); const m1 = existingFile?.metadata; - if (!m1) continue; - // Need to audit the types, until the add a ?? to be safe. + const m2 = newFile.metadata; + // TODO: Add an extra truthy check the EnteFile type is null safe // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - const m2 = newFile.metadata ?? {}; + if (!m1 || !m2) continue; // Both files exist, have metadata, but their (appropriate) hashes // differ, which indicates that the change was in the file's contents, // not the metadata itself, and thus we should refresh the thumbnail. From 6aba9064a7d56b12d58f764475e23bdb1e5e0357 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 16:24:37 +0530 Subject: [PATCH 091/275] [web] Make web app's log handling consistent with how desktop app does it --- web/packages/accounts/services/logout.ts | 4 ++-- web/packages/base/local-storage.ts | 14 ++++++++++++++ web/packages/shared/storage/localStorage/index.ts | 1 - 3 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 web/packages/base/local-storage.ts diff --git a/web/packages/accounts/services/logout.ts b/web/packages/accounts/services/logout.ts index af3ac42053..ac43b21b18 100644 --- a/web/packages/accounts/services/logout.ts +++ b/web/packages/accounts/services/logout.ts @@ -1,9 +1,9 @@ import { clearBlobCaches } from "@/base/blob-cache"; import { clearKVDB } from "@/base/kv"; +import { clearLocalStorage } from "@/base/local-storage"; import log from "@/base/log"; import InMemoryStore from "@ente/shared/storage/InMemoryStore"; import localForage from "@ente/shared/storage/localForage"; -import { clearData } from "@ente/shared/storage/localStorage"; import { clearKeys } from "@ente/shared/storage/sessionStorage"; import { logout as remoteLogout } from "../api/user"; @@ -39,7 +39,7 @@ export const accountLogout = async () => { ignoreError("Session storage", e); } try { - clearData(); + clearLocalStorage(); } catch (e) { ignoreError("Local storage", e); } diff --git a/web/packages/base/local-storage.ts b/web/packages/base/local-storage.ts new file mode 100644 index 0000000000..e71caf48f5 --- /dev/null +++ b/web/packages/base/local-storage.ts @@ -0,0 +1,14 @@ +import { nullToUndefined } from "@/utils/transform"; + +/** + * Clear local storage on logout. + * + * This function clears everything from local storage except the app's logs. + */ +export const clearLocalStorage = () => { + const existingLogs = nullToUndefined(localStorage.getItem("logs")); + localStorage.clear(); + if (existingLogs) { + localStorage.setItem("logs", existingLogs); + } +}; diff --git a/web/packages/shared/storage/localStorage/index.ts b/web/packages/shared/storage/localStorage/index.ts index 99dd51edc1..cf8acf5a95 100644 --- a/web/packages/shared/storage/localStorage/index.ts +++ b/web/packages/shared/storage/localStorage/index.ts @@ -46,7 +46,6 @@ export const getData = (key: LS_KEYS) => { } }; -export const clearData = () => localStorage.clear(); // TODO: Migrate this to `local-user.ts`, with (a) more precise optionality // indication of the constituent fields, (b) moving any fields that need to be From 0c48f53ab1fda42dea64545fd93ded5fd37602d6 Mon Sep 17 00:00:00 2001 From: araghon007 Date: Mon, 26 Aug 2024 15:18:15 +0000 Subject: [PATCH 092/275] Remove X.com custom icon --- auth/assets/custom-icons/_data/custom-icons.json | 7 ------- auth/assets/custom-icons/icons/x.svg | 5 ----- 2 files changed, 12 deletions(-) delete mode 100644 auth/assets/custom-icons/icons/x.svg diff --git a/auth/assets/custom-icons/_data/custom-icons.json b/auth/assets/custom-icons/_data/custom-icons.json index a7ad53bc20..8fe3f7cc9a 100644 --- a/auth/assets/custom-icons/_data/custom-icons.json +++ b/auth/assets/custom-icons/_data/custom-icons.json @@ -667,13 +667,6 @@ "Work OS" ] }, - { - "title": "X", - "altNames": [ - "twitter" - ], - "slug": "x" - }, { "title": "Yandex", "altNames": [ diff --git a/auth/assets/custom-icons/icons/x.svg b/auth/assets/custom-icons/icons/x.svg deleted file mode 100644 index bd4b6e9745..0000000000 --- a/auth/assets/custom-icons/icons/x.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - From 194f07d48efd7ad5c2df01a5c47bf8d7d77da1cb Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 17:50:09 +0530 Subject: [PATCH 093/275] Fix style lint issue --- web/packages/shared/storage/localStorage/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/web/packages/shared/storage/localStorage/index.ts b/web/packages/shared/storage/localStorage/index.ts index cf8acf5a95..df80b21330 100644 --- a/web/packages/shared/storage/localStorage/index.ts +++ b/web/packages/shared/storage/localStorage/index.ts @@ -46,7 +46,6 @@ export const getData = (key: LS_KEYS) => { } }; - // TODO: Migrate this to `local-user.ts`, with (a) more precise optionality // indication of the constituent fields, (b) moving any fields that need to be // accessed from web workers to KV DB. From 87d61051593ab29f34f23915d81b61ff9bd7a5cb Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 17:51:03 +0530 Subject: [PATCH 094/275] Remove leftover migration code --- web/apps/accounts/src/pages/_app.tsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/web/apps/accounts/src/pages/_app.tsx b/web/apps/accounts/src/pages/_app.tsx index 6b19b530fb..31ceecf32d 100644 --- a/web/apps/accounts/src/pages/_app.tsx +++ b/web/apps/accounts/src/pages/_app.tsx @@ -8,7 +8,6 @@ import { Overlay } from "@ente/shared/components/Container"; import DialogBoxV2 from "@ente/shared/components/DialogBoxV2"; import type { DialogBoxAttributesV2 } from "@ente/shared/components/DialogBoxV2/types"; import EnteSpinner from "@ente/shared/components/EnteSpinner"; -import { clearData } from "@ente/shared/storage/localStorage"; import { getTheme } from "@ente/shared/themes"; import { THEME_COLOR } from "@ente/shared/themes/constants"; import { CssBaseline } from "@mui/material"; @@ -30,12 +29,6 @@ const App: React.FC = ({ Component, pageProps }) => { useEffect(() => { disableDiskLogs(); - // The accounts app has no local state, but some older builds might've - // leftover some scraps. Clear it out. - // - // This code added on 1 July 2024, can be removed soon since this data - // was never saved before this was released (tag: Migration). - clearData(); void setupI18n().finally(() => setIsI18nReady(true)); logUnhandledErrorsAndRejections(true); return () => logUnhandledErrorsAndRejections(false); From b55cf7c0d8fd9ab9008f721567d04aac82090526 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 17:51:48 +0530 Subject: [PATCH 095/275] Update --- web/packages/accounts/pages/credentials.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/packages/accounts/pages/credentials.tsx b/web/packages/accounts/pages/credentials.tsx index b29cb952c6..bb3257c3ed 100644 --- a/web/packages/accounts/pages/credentials.tsx +++ b/web/packages/accounts/pages/credentials.tsx @@ -1,5 +1,6 @@ import { sharedCryptoWorker } from "@/base/crypto"; import type { B64EncryptionResult } from "@/base/crypto/libsodium"; +import { clearLocalStorage } from "@/base/local-storage"; import log from "@/base/log"; import { ensure } from "@/utils/ensure"; import { VerticallyCentered } from "@ente/shared/components/Container"; @@ -25,7 +26,6 @@ import { CustomError } from "@ente/shared/error"; import InMemoryStore, { MS_KEYS } from "@ente/shared/storage/InMemoryStore"; import { LS_KEYS, - clearData, getData, setData, setLSUser, @@ -177,7 +177,7 @@ const Page: React.FC = ({ appContext }) => { (!user?.token && !user?.encryptedToken) || (keyAttributes && !keyAttributes.memLimit) ) { - clearData(); + clearLocalStorage(); router.push("/"); return; } From 236d24c79b88c25526c1931ee4d422c9570ac469 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Thu, 29 Aug 2024 18:01:06 +0530 Subject: [PATCH 096/275] [server] Gracefully handle deleted users --- server/ente/errors.go | 6 ++++++ server/pkg/api/user.go | 2 +- server/pkg/controller/user/user_details.go | 11 ++++++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/server/ente/errors.go b/server/ente/errors.go index 696a764f34..c4bbc1db87 100644 --- a/server/ente/errors.go +++ b/server/ente/errors.go @@ -141,6 +141,12 @@ var ErrNotFoundError = ApiError{ HttpStatusCode: http.StatusNotFound, } +var ErrUserNotFound = &ApiError{ + Code: "USER_NOT_FOUND", + Message: "User is either deleted or not found", + HttpStatusCode: http.StatusNotFound, +} + var ErrMaxPasskeysReached = ApiError{ Code: MaxPasskeysReached, Message: "Max passkeys limit reached", diff --git a/server/pkg/api/user.go b/server/pkg/api/user.go index c02fce36c7..939c6bf5c6 100644 --- a/server/pkg/api/user.go +++ b/server/pkg/api/user.go @@ -356,7 +356,7 @@ func (h *UserHandler) FinishPasskeyAuthenticationCeremony(c *gin.Context) { return } - user, err := h.UserController.UserRepo.Get(userID) + user, err := h.UserController.GetUser(userID) if err != nil { handler.Error(c, stacktrace.Propagate(err, "")) return diff --git a/server/pkg/controller/user/user_details.go b/server/pkg/controller/user/user_details.go index 703b8fb2f5..ee4acb730e 100644 --- a/server/pkg/controller/user/user_details.go +++ b/server/pkg/controller/user/user_details.go @@ -1,6 +1,7 @@ package user import ( + "errors" "github.com/ente-io/museum/ente" "github.com/ente-io/museum/ente/details" bonus "github.com/ente-io/museum/ente/storagebonus" @@ -11,6 +12,14 @@ import ( "golang.org/x/sync/errgroup" ) +func (c *UserController) GetUser(userID int64) (ente.User, error) { + user, err := c.UserRepo.Get(userID) + if err != nil && errors.Is(err, ente.ErrUserDeleted) { + return ente.User{}, stacktrace.Propagate(ente.ErrUserNotFound, "") + } + return user, err + +} func (c *UserController) GetDetailsV2(ctx *gin.Context, userID int64, fetchMemoryCount bool, app ente.App) (details.UserDetailsResponse, error) { g := new(errgroup.Group) @@ -21,7 +30,7 @@ func (c *UserController) GetDetailsV2(ctx *gin.Context, userID int64, fetchMemor var fileCount, sharedCollectionCount, usage int64 var bonus *bonus.ActiveStorageBonus g.Go(func() error { - resp, err := c.UserRepo.Get(userID) + resp, err := c.GetUser(userID) if err != nil { return stacktrace.Propagate(err, "failed to get user") } From 67ea0cfe734f9128411cfc1f5e3dec303b09650a Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 12:22:22 +0530 Subject: [PATCH 097/275] Debugging code --- .../new/photos/services/ml/cluster-new.ts | 26 ++++++++++--------- .../new/photos/services/ml/cluster.ts | 2 +- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index 9e07b2812c..94e5efe11e 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -343,17 +343,18 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { // A flattened array of faces. // TODO-Cluster note the 2k slice - const faces = [...enumerateFaces(faceIndexes)].slice(0, 2000); + const faces0 = [...enumerateFaces(faceIndexes)];//.slice(0, 2000); + const faces = Array(1).fill(0).flatMap(() => faces0); const faceEmbeddings = faces.map(({ embedding }) => embedding); const { clusters: clusterIndices, - noise, - debugInfo, + // noise, + // debugInfo, } = clusterFacesHdbscan(faceEmbeddings); - log.info({ method: "hdbscan", clusterIndices, noise, debugInfo }); + // log.info({ method: "hdbscan", clusterIndices, noise, debugInfo }); log.info( `Clustered ${faces.length} faces into ${clusterIndices.length} clusters (${Date.now() - t} ms)`, ); @@ -387,7 +388,8 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { // Convert into the data structure we're using to debug/visualize. const faceAndNeigbours: FaceNeighbours[] = []; - for (const fi of faces) { + const topFaces = faces.sort((a, b) => b.score - a.score).slice(0, 30); + for (const fi of topFaces) { let neighbours: FaceNeighbour[] = []; for (const fj of faces) { // The vectors are already normalized, so we can directly use their @@ -437,13 +439,13 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { ).faceID; } - log.info("ml/cluster", { - faces, - validClusters, - clusterIndexForClusterID: Object.fromEntries(clusterIndexForClusterID), - clusterIDForFaceID: Object.fromEntries(clusterIDForFaceID), - cgroups, - }); + // log.info("ml/cluster", { + // faces, + // validClusters, + // clusterIndexForClusterID: Object.fromEntries(clusterIndexForClusterID), + // clusterIDForFaceID: Object.fromEntries(clusterIDForFaceID), + // cgroups, + // }); log.info( `Clustered ${faces.length} faces into ${validClusters.length} clusters (${Date.now() - t} ms)`, ); diff --git a/web/packages/new/photos/services/ml/cluster.ts b/web/packages/new/photos/services/ml/cluster.ts index ff62f466a9..53e4930d94 100644 --- a/web/packages/new/photos/services/ml/cluster.ts +++ b/web/packages/new/photos/services/ml/cluster.ts @@ -24,7 +24,7 @@ export const clusterFacesHdbscan = ( minSamples: 5, clusterSelectionEpsilon: 0.6, clusterSelectionMethod: "leaf", - debug: true, + debug: false, }); return { From fc66c3e68933bcac5d2989b393f22a3c550c0760 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Thu, 29 Aug 2024 14:14:18 +0200 Subject: [PATCH 098/275] Add Upstox icon --- auth/assets/custom-icons/_data/custom-icons.json | 3 +++ auth/assets/custom-icons/icons/upstox.svg | 12 ++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 auth/assets/custom-icons/icons/upstox.svg diff --git a/auth/assets/custom-icons/_data/custom-icons.json b/auth/assets/custom-icons/_data/custom-icons.json index 8fe3f7cc9a..0918925ace 100644 --- a/auth/assets/custom-icons/_data/custom-icons.json +++ b/auth/assets/custom-icons/_data/custom-icons.json @@ -639,6 +639,9 @@ "slug": "uphold", "hex": "6FE68A" }, + { + "title": "Upstox" + }, { "titile": "Vikunja", "slug": "vikunja" diff --git a/auth/assets/custom-icons/icons/upstox.svg b/auth/assets/custom-icons/icons/upstox.svg new file mode 100644 index 0000000000..2fb1a489f9 --- /dev/null +++ b/auth/assets/custom-icons/icons/upstox.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + From cd69e00451496ca4311f7a551a7e6ce2852bfe41 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 18:27:44 +0530 Subject: [PATCH 099/275] Batch --- .../new/photos/services/ml/cluster-new.ts | 132 +++++++++++++----- 1 file changed, 100 insertions(+), 32 deletions(-) diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index 94e5efe11e..e934b54676 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -342,48 +342,116 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { const t = Date.now(); // A flattened array of faces. - // TODO-Cluster note the 2k slice - const faces0 = [...enumerateFaces(faceIndexes)];//.slice(0, 2000); - const faces = Array(1).fill(0).flatMap(() => faces0); + const faces0 = [...enumerateFaces(faceIndexes)]; + // TODO-Cluster testing code, can be removed once done + const faces = Array(1) + .fill(0) + .flatMap(() => faces0); + + // For fast reverse lookup - map from face ids to the face. + const faceForFaceID = new Map(faces.map((f) => [f.faceID, f])); const faceEmbeddings = faces.map(({ embedding }) => embedding); - const { - clusters: clusterIndices, - // noise, - // debugInfo, - } = clusterFacesHdbscan(faceEmbeddings); - - // log.info({ method: "hdbscan", clusterIndices, noise, debugInfo }); - log.info( - `Clustered ${faces.length} faces into ${clusterIndices.length} clusters (${Date.now() - t} ms)`, - ); - // For fast reverse lookup - map from cluster ids to their index in the // clusters array. const clusterIndexForClusterID = new Map(); - // For fast reverse lookup - map from face ids to the id of the cluster to - // which they belong. + // For fast reverse lookup - map from the id of a face to the id of the + // cluster to which it belongs. const clusterIDForFaceID = new Map(); + // A function to chain two reverse lookup. + const firstFaceOfCluster = (cluster: FaceCluster) => + ensure(faceForFaceID.get(ensure(cluster.faceIDs[0]))); + // A function to generate new cluster IDs. const newClusterID = () => newNonSecureID("cluster_"); - // Convert the numerical face indices into the result. + // The resultant clusters. + // TODO-Cluster Later on, instead of starting from a blank slate, this will + // be list of existing clusters we fetch from remote. const clusters: FaceCluster[] = []; - for (const [ci, faceIndices] of clusterIndices.entries()) { - const clusterID = newClusterID(); - const faceIDs: string[] = []; - clusterIndexForClusterID.set(clusterID, ci); - for (const fi of faceIndices) { - // Can't find a way of avoiding the null assertion here. - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const face = faces[fi]!; - clusterIDForFaceID.set(face.faceID, clusterID); - faceIDs.push(face.faceID); + + // Process the faces in batches of 10k. The faces are already sorted by file + // ID, which is a monotonically increasing integer, so we will also have + // some temporal locality. + // + // The number 10k was derived by ad-hoc observations. On a particular test + // dataset, clustering 10k took ~2 mins, while 20k took ~8 mins. Memory + // usage was constant in both cases. + // + // At around 100k faces, the clustering starts taking hours, and we start + // running into stack overflows. The stack overflows can perhaps be avoided + // by restructuring the code, but hours of uninterruptible work is anyways + // not feasible. + + const batchSize = 10_000; + for (let i = 0; i < faceEmbeddings.length; i += batchSize) { + const embeddings = faceEmbeddings.slice(i, i + batchSize); + const { clusters: hdbClusters } = clusterFacesHdbscan(embeddings); + + log.info( + `hdbscan produced ${hdbClusters.length} clusters from ${embeddings.length} faces (${Date.now() - t} ms)`, + ); + + // Merge the new clusters we got from hdbscan into the existing clusters + // if they are "near" them (using some heuristic). + // + // We need to ensure we don't change any of the existing cluster IDs, + // since these might be existing clusters we got from remote. + + for (const hdbCluster of hdbClusters) { + // Find the existing cluster whose (arbitrarily chosen) first face + // is the nearest neighbour of the (arbitrarily chosen) first face + // of the cluster produced by hdbscan. + + const newFace = ensure(faces[i + ensure(hdbCluster[0])]); + + let nnCluster: FaceCluster | undefined; + let nnCosineSimilarity = 0; + for (const existingCluster of clusters) { + const existingFace = firstFaceOfCluster(existingCluster); + + // The vectors are already normalized, so we can directly use their + // dot product as their cosine similarity. + const csim = dotProduct( + existingFace.embedding, + newFace.embedding, + ); + + // Use a higher cosine similarity threshold if either of the two + // faces are blurry. + const threshold = + existingFace.blur < 100 || newFace.blur < 100 ? 0.84 : 0.7; + if (csim > threshold && csim > nnCosineSimilarity) { + nnCluster = existingCluster; + nnCosineSimilarity = csim; + } + } + + if (nnCluster) { + // If we found an existing cluster that is near enough, + // sublimate the cluster produced by hdbscan into that cluster. + for (const j of hdbCluster) { + const { faceID } = ensure(faces[i + j]); + nnCluster.faceIDs.push(faceID); + clusterIDForFaceID.set(faceID, nnCluster.id); + } + } else { + // Otherwise make a new cluster from the cluster produced by + // hdbscan. + const clusterID = newClusterID(); + const faceIDs: string[] = []; + for (const j of hdbCluster) { + const { faceID } = ensure(faces[i + j]); + faceIDs.push(faceID); + clusterIDForFaceID.set(faceID, clusterID); + } + clusterIndexForClusterID.set(clusterID, clusters.length); + clusters.push({ id: clusterID, faceIDs }); + } } - clusters.push({ id: clusterID, faceIDs }); } // Convert into the data structure we're using to debug/visualize. @@ -398,14 +466,15 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { neighbours.push({ face: fj, cosineSimilarity: csim }); } - neighbours = neighbours.sort( - (a, b) => b.cosineSimilarity - a.cosineSimilarity, - ); + neighbours = neighbours + .sort((a, b) => b.cosineSimilarity - a.cosineSimilarity) + .slice(0, 30); faceAndNeigbours.push({ face: fi, neighbours }); } // Prune too small clusters. + // TODO-Cluster this is likely not needed since hdbscan already has a min? const validClusters = clusters.filter(({ faceIDs }) => faceIDs.length > 1); let cgroups = await clusterGroups(); @@ -426,7 +495,6 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { // For each cluster group, use the highest scoring face in any of its // clusters as its display face. - const faceForFaceID = new Map(faces.map((f) => [f.faceID, f])); for (const cgroup of cgroups) { cgroup.displayFaceID = cgroup.clusterIDs .map((clusterID) => clusterIndexForClusterID.get(clusterID)) From 89a5a9f42f09be8a348676b04f55099d46b87630 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 18:42:17 +0530 Subject: [PATCH 100/275] Prune --- web/packages/new/photos/services/ml/index.ts | 23 +++++++------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 43d90578b8..53940232f6 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -387,16 +387,14 @@ export const wipClusterDebugPageContents = async (): Promise< const fileForFace = ({ faceID }: Face) => ensure(localFileByID.get(ensure(fileIDFromFaceID(faceID)))); - const faceFNs = faceAndNeigbours - .map(({ face, neighbours }) => ({ + const faceFNs = faceAndNeigbours.map(({ face, neighbours }) => ({ + face, + neighbours: neighbours.map(({ face, cosineSimilarity }) => ({ face, - neighbours: neighbours.map(({ face, cosineSimilarity }) => ({ - face, - enteFile: fileForFace(face), - cosineSimilarity, - })), - })) - .sort((a, b) => b.face.score - a.face.score); + enteFile: fileForFace(face), + cosineSimilarity, + })), + })); const clusterIDForFaceID = new Map( clusters.flatMap((cluster) => @@ -408,12 +406,7 @@ export const wipClusterDebugPageContents = async (): Promise< _wip_searchPersons = searchPersons; triggerStatusUpdate(); - const prunedFaceFNs = faceFNs.slice(0, 30).map(({ face, neighbours }) => ({ - face, - neighbours: neighbours.slice(0, 30), - })); - - return { faceFNs: prunedFaceFNs, clusters, clusterIDForFaceID }; + return { faceFNs, clusters, clusterIDForFaceID }; }; export const wipCluster = () => void wipClusterDebugPageContents(); From 2179b193d21af7a7f7218e889a6f16b37736245b Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 19:07:54 +0530 Subject: [PATCH 101/275] Preview --- web/apps/photos/src/pages/cluster-debug.tsx | 4 +- .../new/photos/services/ml/cluster-new.ts | 76 +++++++++++++++---- web/packages/new/photos/services/ml/index.ts | 32 ++++++-- 3 files changed, 89 insertions(+), 23 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index c6abe7226f..dcffaecfd2 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -53,8 +53,8 @@ export default function ClusterDebug() { {`${clusterRes.clusters.length} clusters`} - Showing only upto first 30 faces (and only upto 30 nearest - neighbours of each). + Showing only top 20 and bottom 10 clusters (and only up to 50 faces in + each, sorted by cosine distance to highest scoring face in the cluster).
diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index e934b54676..983c128a6a 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -124,6 +124,16 @@ interface FaceNeighbour { cosineSimilarity: number; } +export interface ClusterPreview { + clusterSize: number; + faces: ClusterPreviewFace[]; +} + +interface ClusterPreviewFace { + face: Face; + cosineSimilarity: number; +} + /** * Cluster faces into groups. * @@ -455,22 +465,56 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { } // Convert into the data structure we're using to debug/visualize. - const faceAndNeigbours: FaceNeighbours[] = []; - const topFaces = faces.sort((a, b) => b.score - a.score).slice(0, 30); - for (const fi of topFaces) { - let neighbours: FaceNeighbour[] = []; - for (const fj of faces) { - // The vectors are already normalized, so we can directly use their - // dot product as their cosine similarity. - const csim = dotProduct(fi.embedding, fj.embedding); - neighbours.push({ face: fj, cosineSimilarity: csim }); + // const faceAndNeigbours: FaceNeighbours[] = []; + // const topFaces = faces.sort((a, b) => b.score - a.score).slice(0, 30); + // for (const fi of topFaces) { + // let neighbours: FaceNeighbour[] = []; + // for (const fj of faces) { + // // The vectors are already normalized, so we can directly use their + // // dot product as their cosine similarity. + // const csim = dotProduct(fi.embedding, fj.embedding); + // neighbours.push({ face: fj, cosineSimilarity: csim }); + // } + + // neighbours = neighbours + // .sort((a, b) => b.cosineSimilarity - a.cosineSimilarity) + // .slice(0, 30); + + // faceAndNeigbours.push({ face: fi, neighbours }); + // } + + // Convert into the data structure we're using to debug/visualize. + // + // > Showing only top 20 and bottom 10 clusters (and only up to 50 faces in + // > each, sorted by cosine distance to highest scoring face in the + // > cluster). + + const sortedClusters = clusters.sort( + (a, b) => b.faceIDs.length - a.faceIDs.length, + ); + const debugClusters = + sortedClusters.length < 30 + ? sortedClusters + : sortedClusters.slice(0, 20).concat(sortedClusters.slice(-10)); + const clusterPreviews: ClusterPreview[] = []; + for (const cluster of debugClusters) { + const faces = cluster.faceIDs.map((id) => + ensure(faceForFaceID.get(id)), + ); + const topFace = faces.reduce((max, face) => + max.score > face.score ? max : face, + ); + const previewFaces: ClusterPreviewFace[] = []; + for (const face of faces) { + const csim = dotProduct(topFace.embedding, face.embedding); + previewFaces.push({ face, cosineSimilarity: csim }); } - - neighbours = neighbours - .sort((a, b) => b.cosineSimilarity - a.cosineSimilarity) - .slice(0, 30); - - faceAndNeigbours.push({ face: fi, neighbours }); + clusterPreviews.push({ + clusterSize: cluster.faceIDs.length, + faces: previewFaces + .sort((a, b) => b.cosineSimilarity - a.cosineSimilarity) + .slice(0, 50), + }); } // Prune too small clusters. @@ -518,5 +562,5 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { `Clustered ${faces.length} faces into ${validClusters.length} clusters (${Date.now() - t} ms)`, ); - return { faces, clusters: validClusters, cgroups, faceAndNeigbours }; + return { faces, clusters: validClusters, cgroups, clusterPreviews }; }; diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 53940232f6..df8d08235c 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -360,6 +360,18 @@ export interface FaceFileNeighbour { cosineSimilarity: number; } +// "with file" +export interface ClusterPreviewWF { + clusterSize: number; + faces: ClusterPreviewFaceWF[]; +} + +interface ClusterPreviewFaceWF { + face: Face; + enteFile: EnteFile; + cosineSimilarity: number; +} + export interface ClusterDebugPageContents { faceFNs: FaceFileNeighbours[]; clusters: FaceCluster[]; @@ -377,7 +389,7 @@ export const wipClusterDebugPageContents = async (): Promise< triggerStatusUpdate(); // const { faceAndNeigbours, clusters, cgroups } = await clusterFaces( - const { faceAndNeigbours, clusters, cgroups } = await clusterFacesHdb( + const { clusterPreviews, clusters, cgroups } = await clusterFacesHdb( await faceIndexes(), ); const searchPersons = await convertToSearchPersons(clusters, cgroups); @@ -387,9 +399,19 @@ export const wipClusterDebugPageContents = async (): Promise< const fileForFace = ({ faceID }: Face) => ensure(localFileByID.get(ensure(fileIDFromFaceID(faceID)))); - const faceFNs = faceAndNeigbours.map(({ face, neighbours }) => ({ - face, - neighbours: neighbours.map(({ face, cosineSimilarity }) => ({ + // const faceFNs = faceAndNeigbours.map( + // ({ topFace: face, faces: neighbours }) => ({ + // face, + // neighbours: neighbours.map(({ face, cosineSimilarity }) => ({ + // face, + // enteFile: fileForFace(face), + // cosineSimilarity, + // })), + // }), + // ); + const clusterPreviewWFs = clusterPreviews.map(({ clusterSize, faces }) => ({ + clusterSize, + faces: faces.map(({ face, cosineSimilarity }) => ({ face, enteFile: fileForFace(face), cosineSimilarity, @@ -406,7 +428,7 @@ export const wipClusterDebugPageContents = async (): Promise< _wip_searchPersons = searchPersons; triggerStatusUpdate(); - return { faceFNs, clusters, clusterIDForFaceID }; + return { clusterPreviewWFs, clusters, clusterIDForFaceID }; }; export const wipCluster = () => void wipClusterDebugPageContents(); From 3d952120233fe9de9b5a8a2dfc46422bfb4aba08 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 19:20:56 +0530 Subject: [PATCH 102/275] Preview --- web/apps/photos/src/pages/cluster-debug.tsx | 61 +++++++++++-------- .../new/photos/services/ml/cluster-new.ts | 7 ++- web/packages/new/photos/services/ml/index.ts | 5 +- 3 files changed, 42 insertions(+), 31 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index dcffaecfd2..23930f1f03 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -4,10 +4,9 @@ import { faceCrop, wipClusterDebugPageContents, type ClusterDebugPageContents, - type FaceFileNeighbour, - type FaceFileNeighbours, + type ClusterPreviewFaceWF, + type ClusterPreviewWF, } from "@/new/photos/services/ml"; -import type { Face } from "@/new/photos/services/ml/face"; import { FlexWrapper, FluidContainer, @@ -15,7 +14,7 @@ import { } from "@ente/shared/components/Container"; import EnteSpinner from "@ente/shared/components/EnteSpinner"; import BackButton from "@mui/icons-material/ArrowBackOutlined"; -import { Box, IconButton, styled, Typography } from "@mui/material"; +import { Box, IconButton, Stack, styled, Typography } from "@mui/material"; import { useRouter } from "next/router"; import { AppContext } from "pages/_app"; import React, { useContext, useEffect, useMemo, useRef, useState } from "react"; @@ -53,8 +52,9 @@ export default function ClusterDebug() { {`${clusterRes.clusters.length} clusters`} - Showing only top 20 and bottom 10 clusters (and only up to 50 faces in - each, sorted by cosine distance to highest scoring face in the cluster). + Showing only top 20 and bottom 10 clusters (and only up to 50 + faces in each, sorted by cosine distance to highest scoring face + in the cluster).
@@ -112,7 +112,7 @@ const ClusterPhotoList: React.FC = ({ width, clusterRes, }) => { - const { faceFNs, clusterIDForFaceID } = clusterRes; + const { clusterPreviewWFs, clusterIDForFaceID } = clusterRes; const [itemList, setItemList] = useState([]); const listRef = useRef(null); @@ -125,8 +125,8 @@ const ClusterPhotoList: React.FC = ({ const listItemHeight = 120 * shrinkRatio + 24 + 4; useEffect(() => { - setItemList(itemListFromFaceFNs(faceFNs, columns)); - }, [columns, faceFNs]); + setItemList(itemListFromClusterPreviewWFs(clusterPreviewWFs, columns)); + }, [columns, clusterPreviewWFs]); useEffect(() => { listRef.current?.resetAfterIndex(0); @@ -138,7 +138,7 @@ const ClusterPhotoList: React.FC = ({ const generateKey = (i: number) => Array.isArray(itemList[i]) ? `${itemList[i][0].enteFile.id}/${itemList[i][0].face.faceID}-${itemList[i].slice(-1)[0].enteFile.id}/${itemList[i].slice(-1)[0].face.faceID}-${i}` - : `${itemList[i].faceID}-${i}`; + : `${itemList[i]}-${i}`; return ( = ({ > {!Array.isArray(item) ? ( - {`score ${item.score.toFixed(2)} blur ${item.blur.toFixed(0)}`} + {`cluster size ${item.toFixed(2)}`} ) : ( - item.map((faceFN, i) => ( + item.map((faceWF, i) => ( )) )} @@ -181,19 +181,20 @@ const ClusterPhotoList: React.FC = ({ ); }; -type ItemListItem = Face | FaceFileNeighbour[]; +// type ItemListItem = Face | FaceFileNeighbour[]; +type ItemListItem = number | ClusterPreviewFaceWF[]; -const itemListFromFaceFNs = ( - faceFNs: FaceFileNeighbours[], +const itemListFromClusterPreviewWFs = ( + clusterPreviewWFs: ClusterPreviewWF[], columns: number, ) => { const result: ItemListItem[] = []; - for (let index = 0; index < faceFNs.length; index++) { - const { face, neighbours } = faceFNs[index]; - result.push(face); + for (let index = 0; index < clusterPreviewWFs.length; index++) { + const { clusterSize, faces } = clusterPreviewWFs[index]; + result.push(clusterSize); let lastIndex = 0; - while (lastIndex < neighbours.length) { - result.push(neighbours.slice(lastIndex, lastIndex + columns)); + while (lastIndex < faces.length) { + result.push(faces.slice(lastIndex, lastIndex + columns)); lastIndex += columns; } } @@ -210,12 +211,12 @@ const getShrinkRatio = (width: number, columns: number) => (columns * 120); interface FaceItemProps { - faceFN: FaceFileNeighbour; + faceWF: ClusterPreviewFaceWF; clusterIDForFaceID: Map; } -const FaceItem: React.FC = ({ faceFN, clusterIDForFaceID }) => { - const { face, enteFile, cosineSimilarity } = faceFN; +const FaceItem: React.FC = ({ faceWF, clusterIDForFaceID }) => { + const { face, enteFile, cosineSimilarity } = faceWF; const { faceID } = face; const [objectURL, setObjectURL] = useState(); @@ -252,9 +253,15 @@ const FaceItem: React.FC = ({ faceFN, clusterIDForFaceID }) => { src={objectURL} /> )} - - {cosineSimilarity.toFixed(2)} - + + + {`${face.blur.toFixed(0)} blr`} + + + + {`cos ${cosineSimilarity.toFixed(2)}`} + +
); }; diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index 983c128a6a..e2bf78eb35 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -352,7 +352,10 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { const t = Date.now(); // A flattened array of faces. - const faces0 = [...enumerateFaces(faceIndexes)]; + // TODO-Cluster ad-hoc filtering and slicing + const faces0 = [...enumerateFaces(faceIndexes)] + .filter((f) => f.blur > 50) + .slice(0, 1000); // TODO-Cluster testing code, can be removed once done const faces = Array(1) .fill(0) @@ -433,7 +436,7 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { // Use a higher cosine similarity threshold if either of the two // faces are blurry. const threshold = - existingFace.blur < 100 || newFace.blur < 100 ? 0.84 : 0.7; + existingFace.blur < 100 || newFace.blur < 100 ? 0.9 : 0.7; if (csim > threshold && csim > nnCosineSimilarity) { nnCluster = existingCluster; nnCosineSimilarity = csim; diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index df8d08235c..699a9b9c14 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -366,14 +366,15 @@ export interface ClusterPreviewWF { faces: ClusterPreviewFaceWF[]; } -interface ClusterPreviewFaceWF { +export interface ClusterPreviewFaceWF { face: Face; enteFile: EnteFile; cosineSimilarity: number; } export interface ClusterDebugPageContents { - faceFNs: FaceFileNeighbours[]; + // faceFNs: FaceFileNeighbours[]; + clusterPreviewWFs: ClusterPreviewWF[]; clusters: FaceCluster[]; clusterIDForFaceID: Map; } From 29b5830e19a861e20fc646d7db5a8bfcbbab8382 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 19:31:24 +0530 Subject: [PATCH 103/275] Print scores --- web/apps/photos/src/pages/cluster-debug.tsx | 8 +++++--- web/packages/new/photos/services/ml/cluster-new.ts | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 23930f1f03..62d2e05df4 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -255,11 +255,13 @@ const FaceItem: React.FC = ({ faceWF, clusterIDForFaceID }) => { )} - {`${face.blur.toFixed(0)} blr`} + {`b ${face.blur.toFixed(0)} b`} - - {`cos ${cosineSimilarity.toFixed(2)}`} + {`s ${face.score.toFixed(2)}`} + + + {`c ${cosineSimilarity.toFixed(2)}`} diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index e2bf78eb35..e2149db180 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -355,7 +355,7 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { // TODO-Cluster ad-hoc filtering and slicing const faces0 = [...enumerateFaces(faceIndexes)] .filter((f) => f.blur > 50) - .slice(0, 1000); + .slice(0, 6000); // TODO-Cluster testing code, can be removed once done const faces = Array(1) .fill(0) From c9acda1b6d4b25149772039607bcbc8ff9e5dec9 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 19:47:16 +0530 Subject: [PATCH 104/275] Show direction --- web/apps/photos/src/pages/cluster-debug.tsx | 15 ++++++++++++--- web/packages/new/photos/services/ml/face.ts | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 62d2e05df4..0798ad608d 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -7,6 +7,7 @@ import { type ClusterPreviewFaceWF, type ClusterPreviewWF, } from "@/new/photos/services/ml"; +import { faceDirection } from "@/new/photos/services/ml/face"; import { FlexWrapper, FluidContainer, @@ -236,6 +237,8 @@ const FaceItem: React.FC = ({ faceWF, clusterIDForFaceID }) => { }; }, [faceID, enteFile]); + const fd = faceDirection(face.detection); + const d = fd == "straight" ? "•" : fd == "left" ? "←" : "→"; return ( = ({ faceWF, clusterIDForFaceID }) => { )} - {`b ${face.blur.toFixed(0)} b`} + {`b${face.blur.toFixed(0)} `} - {`s ${face.score.toFixed(2)}`} + {`s${face.score.toFixed(1)}`} - {`c ${cosineSimilarity.toFixed(2)}`} + {`c${cosineSimilarity.toFixed(1)}`} + + + {`c${cosineSimilarity.toFixed(1)}`} + + + {`d${d}`} diff --git a/web/packages/new/photos/services/ml/face.ts b/web/packages/new/photos/services/ml/face.ts index 891b605db2..d8616b7426 100644 --- a/web/packages/new/photos/services/ml/face.ts +++ b/web/packages/new/photos/services/ml/face.ts @@ -714,7 +714,7 @@ const detectBlur = ( type FaceDirection = "left" | "right" | "straight"; -const faceDirection = ({ landmarks }: FaceDetection): FaceDirection => { +export const faceDirection = ({ landmarks }: FaceDetection): FaceDirection => { const leftEye = landmarks[0]!; const rightEye = landmarks[1]!; const nose = landmarks[2]!; From 4fd32155dc98aee636a0f01e8933f18df91e3a7f Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 19:55:05 +0530 Subject: [PATCH 105/275] Worker --- .../new/photos/services/ml/cluster-new.ts | 13 +++++++++--- web/packages/new/photos/services/ml/index.ts | 21 +++++-------------- web/packages/new/photos/services/ml/worker.ts | 7 +++++++ 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index e2149db180..1258551439 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -399,7 +399,8 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { // by restructuring the code, but hours of uninterruptible work is anyways // not feasible. - const batchSize = 10_000; + // const batchSize = 10_000; // TODO-Cluster + const batchSize = 1_000; for (let i = 0; i < faceEmbeddings.length; i += batchSize) { const embeddings = faceEmbeddings.slice(i, i + batchSize); const { clusters: hdbClusters } = clusterFacesHdbscan(embeddings); @@ -562,8 +563,14 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { // cgroups, // }); log.info( - `Clustered ${faces.length} faces into ${validClusters.length} clusters (${Date.now() - t} ms)`, + `Clustered ${faces.length} faces into ${validClusters.length} clusters, with ${faces.length - clusterIDForFaceID.size} faces remaining unclustered (${Date.now() - t} ms)`, ); - return { faces, clusters: validClusters, cgroups, clusterPreviews }; + return { + faces, + clusters: validClusters, + cgroups, + clusterPreviews, + clusterIDForFaceID, + }; }; diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 699a9b9c14..9f85f47119 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -20,14 +20,9 @@ import { getAllLocalFiles } from "../files"; import { getRemoteFlag, updateRemoteFlag } from "../remote-store"; import type { SearchPerson } from "../search/types"; import type { UploadItem } from "../upload/types"; -import { clusterFacesHdb, type CGroup, type FaceCluster } from "./cluster-new"; +import { type CGroup, type FaceCluster } from "./cluster-new"; import { regenerateFaceCrops } from "./crop"; -import { - clearMLDB, - faceIndex, - faceIndexes, - indexableAndIndexedCounts, -} from "./db"; +import { clearMLDB, faceIndex, indexableAndIndexedCounts } from "./db"; import type { Face } from "./face"; import { MLWorker } from "./worker"; import type { CLIPMatches } from "./worker-types"; @@ -390,9 +385,9 @@ export const wipClusterDebugPageContents = async (): Promise< triggerStatusUpdate(); // const { faceAndNeigbours, clusters, cgroups } = await clusterFaces( - const { clusterPreviews, clusters, cgroups } = await clusterFacesHdb( - await faceIndexes(), - ); + const { clusterPreviews, clusters, cgroups, clusterIDForFaceID } = + await worker().then((w) => w.clusterFacesHdb()); + const searchPersons = await convertToSearchPersons(clusters, cgroups); const localFiles = await getAllLocalFiles(); @@ -419,12 +414,6 @@ export const wipClusterDebugPageContents = async (): Promise< })), })); - const clusterIDForFaceID = new Map( - clusters.flatMap((cluster) => - cluster.faceIDs.map((id) => [id, cluster.id]), - ), - ); - _wip_isClustering = false; _wip_searchPersons = searchPersons; triggerStatusUpdate(); diff --git a/web/packages/new/photos/services/ml/worker.ts b/web/packages/new/photos/services/ml/worker.ts index f21f58d85a..e4a3e5ecab 100644 --- a/web/packages/new/photos/services/ml/worker.ts +++ b/web/packages/new/photos/services/ml/worker.ts @@ -24,8 +24,10 @@ import { indexCLIP, type CLIPIndex, } from "./clip"; +import { clusterFacesHdb } from "./cluster-new"; import { saveFaceCrops } from "./crop"; import { + faceIndexes, indexableFileIDs, markIndexingFailed, saveIndexes, @@ -272,6 +274,11 @@ export class MLWorker { remoteMLData: mlDataByID.get(id), })); } + + // TODO-Cluster + async clusterFacesHdb() { + return clusterFacesHdb(await faceIndexes()); + } } expose(MLWorker); From 15884597b4c27e4253f1db88eaf14360dcf27d51 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 19:57:30 +0530 Subject: [PATCH 106/275] uc --- web/apps/photos/src/pages/cluster-debug.tsx | 5 +---- .../new/photos/services/ml/cluster-new.ts | 11 +++++++--- web/packages/new/photos/services/ml/index.ts | 20 ++++++++++++++++--- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 0798ad608d..db187751de 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -50,7 +50,7 @@ export default function ClusterDebug() { return ( <> - {`${clusterRes.clusters.length} clusters`} + {`${clusterRes.clusters.length} clusters from ${clusterRes.clusteredCount} faces. ${clusterRes.unclusteredCount} unclustered faces.`} Showing only top 20 and bottom 10 clusters (and only up to 50 @@ -266,9 +266,6 @@ const FaceItem: React.FC = ({ faceWF, clusterIDForFaceID }) => { {`c${cosineSimilarity.toFixed(1)}`} - - {`c${cosineSimilarity.toFixed(1)}`} - {`d${d}`} diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index 1258551439..e49db72385 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -354,7 +354,7 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { // A flattened array of faces. // TODO-Cluster ad-hoc filtering and slicing const faces0 = [...enumerateFaces(faceIndexes)] - .filter((f) => f.blur > 50) + .filter((f) => f.blur > 99) .slice(0, 6000); // TODO-Cluster testing code, can be removed once done const faces = Array(1) @@ -437,7 +437,7 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { // Use a higher cosine similarity threshold if either of the two // faces are blurry. const threshold = - existingFace.blur < 100 || newFace.blur < 100 ? 0.9 : 0.7; + existingFace.blur < 200 || newFace.blur < 200 ? 0.9 : 0.7; if (csim > threshold && csim > nnCosineSimilarity) { nnCluster = existingCluster; nnCosineSimilarity = csim; @@ -566,8 +566,13 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { `Clustered ${faces.length} faces into ${validClusters.length} clusters, with ${faces.length - clusterIDForFaceID.size} faces remaining unclustered (${Date.now() - t} ms)`, ); + const clusteredCount = clusterIDForFaceID.size + const unclusteredCount = faces.length - clusteredCount; + return { - faces, + // faces, + clusteredCount, + unclusteredCount, clusters: validClusters, cgroups, clusterPreviews, diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 9f85f47119..3f588c09ad 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -368,6 +368,8 @@ export interface ClusterPreviewFaceWF { } export interface ClusterDebugPageContents { + clusteredCount: number; + unclusteredCount: number; // faceFNs: FaceFileNeighbours[]; clusterPreviewWFs: ClusterPreviewWF[]; clusters: FaceCluster[]; @@ -385,8 +387,14 @@ export const wipClusterDebugPageContents = async (): Promise< triggerStatusUpdate(); // const { faceAndNeigbours, clusters, cgroups } = await clusterFaces( - const { clusterPreviews, clusters, cgroups, clusterIDForFaceID } = - await worker().then((w) => w.clusterFacesHdb()); + const { + clusteredCount, + unclusteredCount, + clusterPreviews, + clusters, + cgroups, + clusterIDForFaceID, + } = await worker().then((w) => w.clusterFacesHdb()); const searchPersons = await convertToSearchPersons(clusters, cgroups); @@ -418,7 +426,13 @@ export const wipClusterDebugPageContents = async (): Promise< _wip_searchPersons = searchPersons; triggerStatusUpdate(); - return { clusterPreviewWFs, clusters, clusterIDForFaceID }; + return { + clusteredCount, + unclusteredCount, + clusterPreviewWFs, + clusters, + clusterIDForFaceID, + }; }; export const wipCluster = () => void wipClusterDebugPageContents(); From d6c7ab0735087aaff9eee6c9b574eaefcaa3fa19 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 20:18:31 +0530 Subject: [PATCH 107/275] Inline --- .../new/photos/services/ml/cluster-new.ts | 66 ++++++++++++------- web/packages/new/photos/services/ml/index.ts | 31 ++++++++- 2 files changed, 73 insertions(+), 24 deletions(-) diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index e49db72385..df97ca4bd9 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -525,34 +525,56 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { // TODO-Cluster this is likely not needed since hdbscan already has a min? const validClusters = clusters.filter(({ faceIDs }) => faceIDs.length > 1); - let cgroups = await clusterGroups(); + // let cgroups = await clusterGroups(); + + // // TODO-Cluster - Currently we're not syncing with remote or saving anything + // // locally, so cgroups will be empty. Create a temporary (unsaved, unsynced) + // // cgroup, one per cluster. + // cgroups = cgroups.concat( + // validClusters.map((c) => ({ + // id: c.id, + // name: undefined, + // clusterIDs: [c.id], + // isHidden: false, + // avatarFaceID: undefined, + // displayFaceID: undefined, + // })), + // ); + + // // For each cluster group, use the highest scoring face in any of its + // // clusters as its display face. + // for (const cgroup of cgroups) { + // cgroup.displayFaceID = cgroup.clusterIDs + // .map((clusterID) => clusterIndexForClusterID.get(clusterID)) + // .filter((i) => i !== undefined) /* 0 is a valid index */ + // .flatMap((i) => clusters[i]?.faceIDs ?? []) + // .map((faceID) => faceForFaceID.get(faceID)) + // .filter((face) => !!face) + // .reduce((max, face) => + // max.score > face.score ? max : face, + // ).faceID; + // } // TODO-Cluster - Currently we're not syncing with remote or saving anything // locally, so cgroups will be empty. Create a temporary (unsaved, unsynced) // cgroup, one per cluster. - cgroups = cgroups.concat( - validClusters.map((c) => ({ - id: c.id, + + const cgroups: CGroup[] = []; + for (const cluster of sortedClusters) { + const faces = cluster.faceIDs.map((id) => + ensure(faceForFaceID.get(id)), + ); + const topFace = faces.reduce((max, face) => + max.score > face.score ? max : face, + ); + cgroups.push({ + id: cluster.id, name: undefined, - clusterIDs: [c.id], + clusterIDs: [cluster.id], isHidden: false, avatarFaceID: undefined, - displayFaceID: undefined, - })), - ); - - // For each cluster group, use the highest scoring face in any of its - // clusters as its display face. - for (const cgroup of cgroups) { - cgroup.displayFaceID = cgroup.clusterIDs - .map((clusterID) => clusterIndexForClusterID.get(clusterID)) - .filter((i) => i !== undefined) /* 0 is a valid index */ - .flatMap((i) => clusters[i]?.faceIDs ?? []) - .map((faceID) => faceForFaceID.get(faceID)) - .filter((face) => !!face) - .reduce((max, face) => - max.score > face.score ? max : face, - ).faceID; + displayFaceID: topFace.faceID, + }); } // log.info("ml/cluster", { @@ -566,7 +588,7 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { `Clustered ${faces.length} faces into ${validClusters.length} clusters, with ${faces.length - clusterIDForFaceID.size} faces remaining unclustered (${Date.now() - t} ms)`, ); - const clusteredCount = clusterIDForFaceID.size + const clusteredCount = clusterIDForFaceID.size; const unclusteredCount = faces.length - clusteredCount; return { diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 3f588c09ad..4248c295f0 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -396,7 +396,7 @@ export const wipClusterDebugPageContents = async (): Promise< clusterIDForFaceID, } = await worker().then((w) => w.clusterFacesHdb()); - const searchPersons = await convertToSearchPersons(clusters, cgroups); + // const searchPersons = await convertToSearchPersons(clusters, cgroups); const localFiles = await getAllLocalFiles(); const localFileByID = new Map(localFiles.map((f) => [f.id, f])); @@ -422,6 +422,32 @@ export const wipClusterDebugPageContents = async (): Promise< })), })); + const clusterByID = new Map(clusters.map((c) => [c.id, c])); + + const searchPersons = cgroups + .map((cgroup) => { + const faceID = ensure(cgroup.displayFaceID); + const fileID = ensure(fileIDFromFaceID(faceID)); + const file = ensure(localFileByID.get(fileID)); + + const faceIDs = cgroup.clusterIDs + .map((id) => ensure(clusterByID.get(id))) + .flatMap((cluster) => cluster.faceIDs); + const fileIDs = faceIDs + .map((faceID) => fileIDFromFaceID(faceID)) + .filter((fileID) => fileID !== undefined); + + return { + id: cgroup.id, + name: cgroup.name, + faceIDs, + files: [...new Set(fileIDs)], + displayFaceID: faceID, + displayFaceFile: file, + }; + }) + .sort((a, b) => b.faceIDs.length - a.faceIDs.length); + _wip_isClustering = false; _wip_searchPersons = searchPersons; triggerStatusUpdate(); @@ -437,7 +463,8 @@ export const wipClusterDebugPageContents = async (): Promise< export const wipCluster = () => void wipClusterDebugPageContents(); -const convertToSearchPersons = async ( +// TODO-Cluster remove me +export const convertToSearchPersons = async ( clusters: FaceCluster[], cgroups: CGroup[], ) => { From 577b2624184a2d45a1c41bc5c86ae72c514b7a13 Mon Sep 17 00:00:00 2001 From: Prateek Sunal Date: Wed, 28 Aug 2024 01:12:41 +0530 Subject: [PATCH 108/275] fix: change sentence case for android debug builds --- mobile/android/app/src/debug/res/values/strings.xml | 2 +- mobile/android/app/src/dev/res/values/strings.xml | 2 +- mobile/android/app/src/face/res/values/strings.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mobile/android/app/src/debug/res/values/strings.xml b/mobile/android/app/src/debug/res/values/strings.xml index 9749285e5b..2253459b7e 100644 --- a/mobile/android/app/src/debug/res/values/strings.xml +++ b/mobile/android/app/src/debug/res/values/strings.xml @@ -1,4 +1,4 @@ - ente debug + Ente Debug backup debug diff --git a/mobile/android/app/src/dev/res/values/strings.xml b/mobile/android/app/src/dev/res/values/strings.xml index 3f5e2af1d1..50a363d10f 100644 --- a/mobile/android/app/src/dev/res/values/strings.xml +++ b/mobile/android/app/src/dev/res/values/strings.xml @@ -1,4 +1,4 @@ - ente dev + Ente Dev backup dev diff --git a/mobile/android/app/src/face/res/values/strings.xml b/mobile/android/app/src/face/res/values/strings.xml index 4932deb961..ac4281e80e 100644 --- a/mobile/android/app/src/face/res/values/strings.xml +++ b/mobile/android/app/src/face/res/values/strings.xml @@ -1,4 +1,4 @@ - ente face + Ente Face backup face From 2044d3eb6bebba5f4f55a374ef798460e2b5a37e Mon Sep 17 00:00:00 2001 From: Prateek Sunal Date: Wed, 28 Aug 2024 01:13:00 +0530 Subject: [PATCH 109/275] chore: add translation keys --- mobile/lib/generated/intl/messages_en.dart | 3 +++ mobile/lib/generated/l10n.dart | 20 ++++++++++++++++++++ mobile/lib/l10n/intl_en.arb | 2 ++ 3 files changed, 25 insertions(+) diff --git a/mobile/lib/generated/intl/messages_en.dart b/mobile/lib/generated/intl/messages_en.dart index 0c377470aa..801ea0c58a 100644 --- a/mobile/lib/generated/intl/messages_en.dart +++ b/mobile/lib/generated/intl/messages_en.dart @@ -390,6 +390,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Backup over mobile data"), "backupSettings": MessageLookupByLibrary.simpleMessage("Backup settings"), + "backupStatus": MessageLookupByLibrary.simpleMessage("Backup status"), + "backupStatusDescription": MessageLookupByLibrary.simpleMessage( + "Items that have been backed up will show up here"), "backupVideos": MessageLookupByLibrary.simpleMessage("Backup videos"), "blackFridaySale": MessageLookupByLibrary.simpleMessage("Black Friday Sale"), diff --git a/mobile/lib/generated/l10n.dart b/mobile/lib/generated/l10n.dart index e88b25f990..5ede242db1 100644 --- a/mobile/lib/generated/l10n.dart +++ b/mobile/lib/generated/l10n.dart @@ -3172,6 +3172,26 @@ class S { ); } + /// `Backup status` + String get backupStatus { + return Intl.message( + 'Backup status', + name: 'backupStatus', + desc: '', + args: [], + ); + } + + /// `Items that have been backed up will show up here` + String get backupStatusDescription { + return Intl.message( + 'Items that have been backed up will show up here', + name: 'backupStatusDescription', + desc: '', + args: [], + ); + } + /// `Backup over mobile data` String get backupOverMobileData { return Intl.message( diff --git a/mobile/lib/l10n/intl_en.arb b/mobile/lib/l10n/intl_en.arb index ae78fa60c3..c252714447 100644 --- a/mobile/lib/l10n/intl_en.arb +++ b/mobile/lib/l10n/intl_en.arb @@ -453,6 +453,8 @@ "showMemories": "Show memories", "yearsAgo": "{count, plural, one{{count} year ago} other{{count} years ago}}", "backupSettings": "Backup settings", + "backupStatus": "Backup status", + "backupStatusDescription": "Items that have been backed up will show up here", "backupOverMobileData": "Backup over mobile data", "backupVideos": "Backup videos", "disableAutoLock": "Disable auto lock", From 864b5514be07a2d0048843a69939d1bfdbd259f4 Mon Sep 17 00:00:00 2001 From: Prateek Sunal Date: Wed, 28 Aug 2024 01:19:44 +0530 Subject: [PATCH 110/275] feat(backup): introduce backup status screen --- mobile/lib/events/backup_updated_event.dart | 10 + mobile/lib/models/backup/backup_item.dart | 55 ++++++ .../lib/models/backup/backup_item_status.dart | 7 + .../ui/settings/backup/backup_item_card.dart | 171 ++++++++++++++++++ .../backup/backup_section_widget.dart | 16 ++ .../settings/backup/backup_status_screen.dart | 110 +++++++++++ mobile/lib/utils/file_uploader.dart | 63 ++++++- 7 files changed, 428 insertions(+), 4 deletions(-) create mode 100644 mobile/lib/events/backup_updated_event.dart create mode 100644 mobile/lib/models/backup/backup_item.dart create mode 100644 mobile/lib/models/backup/backup_item_status.dart create mode 100644 mobile/lib/ui/settings/backup/backup_item_card.dart create mode 100644 mobile/lib/ui/settings/backup/backup_status_screen.dart diff --git a/mobile/lib/events/backup_updated_event.dart b/mobile/lib/events/backup_updated_event.dart new file mode 100644 index 0000000000..7d710df199 --- /dev/null +++ b/mobile/lib/events/backup_updated_event.dart @@ -0,0 +1,10 @@ +import "dart:collection"; + +import "package:photos/events/event.dart"; +import "package:photos/models/backup/backup_item.dart"; + +class BackupUpdatedEvent extends Event { + final LinkedHashMap items; + + BackupUpdatedEvent(this.items); +} diff --git a/mobile/lib/models/backup/backup_item.dart b/mobile/lib/models/backup/backup_item.dart new file mode 100644 index 0000000000..02ea0c442d --- /dev/null +++ b/mobile/lib/models/backup/backup_item.dart @@ -0,0 +1,55 @@ +import "dart:async"; + +import "package:photos/models/backup/backup_item_status.dart"; +import "package:photos/models/file/file.dart"; + +class BackupItem { + final BackupItemStatus status; + final EnteFile file; + final int collectionID; + final Completer completer; + + BackupItem({ + required this.status, + required this.file, + required this.collectionID, + required this.completer, + }); + + BackupItem copyWith({ + BackupItemStatus? status, + EnteFile? file, + int? collectionID, + Completer? completer, + }) { + return BackupItem( + status: status ?? this.status, + file: file ?? this.file, + collectionID: collectionID ?? this.collectionID, + completer: completer ?? this.completer, + ); + } + + @override + String toString() { + return 'BackupItem(status: $status, file: $file, collectionID: $collectionID)'; + } + + @override + bool operator ==(covariant BackupItem other) { + if (identical(this, other)) return true; + + return other.status == status && + other.file == file && + other.collectionID == collectionID && + other.completer == completer; + } + + @override + int get hashCode { + return status.hashCode ^ + file.hashCode ^ + collectionID.hashCode ^ + completer.hashCode; + } +} diff --git a/mobile/lib/models/backup/backup_item_status.dart b/mobile/lib/models/backup/backup_item_status.dart new file mode 100644 index 0000000000..b4aedfa562 --- /dev/null +++ b/mobile/lib/models/backup/backup_item_status.dart @@ -0,0 +1,7 @@ +enum BackupItemStatus { + inBackground, + inQueue, + uploading, + completed, + retry, +} diff --git a/mobile/lib/ui/settings/backup/backup_item_card.dart b/mobile/lib/ui/settings/backup/backup_item_card.dart new file mode 100644 index 0000000000..a566fc6a4a --- /dev/null +++ b/mobile/lib/ui/settings/backup/backup_item_card.dart @@ -0,0 +1,171 @@ +import "dart:typed_data"; + +import 'package:flutter/material.dart'; +import "package:photos/models/backup/backup_item.dart"; +import "package:photos/models/backup/backup_item_status.dart"; +import 'package:photos/theme/ente_theme.dart'; +import "package:photos/utils/file_uploader.dart"; +import "package:photos/utils/thumbnail_util.dart"; + +class BackupItemCard extends StatefulWidget { + const BackupItemCard({ + super.key, + required this.item, + }); + + final BackupItem item; + + @override + State createState() => _BackupItemCardState(); +} + +class _BackupItemCardState extends State { + Uint8List? thumbnail; + String? folderName; + + @override + void initState() { + super.initState(); + _getThumbnail(); + _getFolderName(); + } + + @override + void dispose() { + super.dispose(); + } + + _getThumbnail() async { + thumbnail = await getThumbnail(widget.item.file); + setState(() {}); + } + + _getFolderName() async { + folderName = widget.item.file.deviceFolder ?? ''; + setState(() {}); + } + + @override + Widget build(BuildContext context) { + final colorScheme = getEnteColorScheme(context); + return Container( + height: 60, + margin: const EdgeInsets.symmetric(vertical: 10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + border: Border.all( + color: Theme.of(context).brightness == Brightness.light + ? const Color(0xFF000000).withOpacity(0.08) + : const Color(0xFFFFFFFF).withOpacity(0.08), + width: 1, + ), + ), + child: Row( + children: [ + SizedBox( + width: 60, + height: 60, + child: ClipRRect( + borderRadius: BorderRadius.circular(4), + child: thumbnail != null + ? Image.memory( + thumbnail!, + fit: BoxFit.cover, + ) + : const SizedBox(), + ), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.item.file.displayName, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 16, + height: 20 / 16, + color: Theme.of(context).brightness == Brightness.light + ? const Color(0xFF000000) + : const Color(0xFFFFFFFF), + ), + ), + const SizedBox(height: 4), + Text( + folderName ?? "", + style: TextStyle( + fontSize: 14, + height: 17 / 14, + color: Theme.of(context).brightness == Brightness.light + ? const Color.fromRGBO(0, 0, 0, 0.7) + : const Color.fromRGBO(255, 255, 255, 0.7), + ), + ), + ], + ), + ), + const SizedBox(width: 12), + SizedBox( + height: 48, + width: 48, + child: Center( + child: switch (widget.item.status) { + BackupItemStatus.uploading => SizedBox( + width: 16, + height: 16, + child: CircularProgressIndicator( + strokeWidth: 2.0, + color: colorScheme.primary700, + ), + ), + BackupItemStatus.completed => const SizedBox( + width: 24, + height: 24, + child: Icon( + Icons.check, + color: Color(0xFF00B33C), + ), + ), + BackupItemStatus.inQueue => SizedBox( + width: 24, + height: 24, + child: Icon( + Icons.history, + color: Theme.of(context).brightness == Brightness.light + ? const Color.fromRGBO(0, 0, 0, .6) + : const Color.fromRGBO(255, 255, 255, .6), + ), + ), + BackupItemStatus.retry => IconButton( + icon: const Icon( + Icons.sync, + color: Color(0xFFFDB816), + ), + onPressed: () async { + await FileUploader.instance.forceUpload( + widget.item.file, + widget.item.collectionID, + ); + }, + ), + BackupItemStatus.inBackground => SizedBox( + width: 24, + height: 24, + child: Icon( + Icons.lock_reset, + color: Theme.of(context).brightness == Brightness.light + ? const Color.fromRGBO(0, 0, 0, .6) + : const Color.fromRGBO(255, 255, 255, .6), + ), + ), + }, + ), + ), + ], + ), + ); + } +} diff --git a/mobile/lib/ui/settings/backup/backup_section_widget.dart b/mobile/lib/ui/settings/backup/backup_section_widget.dart index 183b79b203..56ef0e02f7 100644 --- a/mobile/lib/ui/settings/backup/backup_section_widget.dart +++ b/mobile/lib/ui/settings/backup/backup_section_widget.dart @@ -6,6 +6,7 @@ import 'package:photos/ui/components/expandable_menu_item_widget.dart'; import 'package:photos/ui/components/menu_item_widget/menu_item_widget.dart'; import 'package:photos/ui/settings/backup/backup_folder_selection_page.dart'; import 'package:photos/ui/settings/backup/backup_settings_screen.dart'; +import "package:photos/ui/settings/backup/backup_status_screen.dart"; import "package:photos/ui/settings/backup/free_space_options.dart"; import 'package:photos/ui/settings/common_settings.dart'; import 'package:photos/utils/navigation_util.dart'; @@ -47,6 +48,21 @@ class BackupSectionWidgetState extends State { }, ), sectionOptionSpacing, + MenuItemWidget( + captionedTextWidget: CaptionedTextWidget( + title: S.of(context).backupStatus, + ), + pressedColor: getEnteColorScheme(context).fillFaint, + trailingIcon: Icons.chevron_right_outlined, + trailingIconIsMuted: true, + onTap: () async { + await routeToPage( + context, + const BackupStatusScreen(), + ); + }, + ), + sectionOptionSpacing, MenuItemWidget( captionedTextWidget: CaptionedTextWidget( title: S.of(context).backupSettings, diff --git a/mobile/lib/ui/settings/backup/backup_status_screen.dart b/mobile/lib/ui/settings/backup/backup_status_screen.dart new file mode 100644 index 0000000000..4117e2c980 --- /dev/null +++ b/mobile/lib/ui/settings/backup/backup_status_screen.dart @@ -0,0 +1,110 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import "dart:collection"; + +import 'package:flutter/material.dart'; +import "package:photos/core/event_bus.dart"; +import "package:photos/events/backup_updated_event.dart"; +import "package:photos/generated/l10n.dart"; +import "package:photos/models/backup/backup_item.dart"; +import 'package:photos/ui/components/title_bar_title_widget.dart'; +import 'package:photos/ui/components/title_bar_widget.dart'; +import "package:photos/ui/settings/backup/backup_item_card.dart"; +import "package:photos/utils/file_uploader.dart"; + +class BackupStatusScreen extends StatefulWidget { + const BackupStatusScreen({super.key}); + + @override + State createState() => _BackupStatusScreenState(); +} + +class _BackupStatusScreenState extends State { + LinkedHashMap items = FileUploader.instance.allBackups; + + @override + void initState() { + super.initState(); + + checkBackupUpdatedEvent(); + } + + void checkBackupUpdatedEvent() { + Bus.instance.on().listen((event) { + items = event.items; + setState(() {}); + }); + } + + @override + Widget build(BuildContext context) { + final List items = this.items.values.toList(); + + return Scaffold( + body: CustomScrollView( + primary: false, + slivers: [ + TitleBarWidget( + flexibleSpaceTitle: TitleBarTitleWidget( + title: S.of(context).backupStatus, + ), + ), + items.isEmpty + ? SliverFillRemaining( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 60, + vertical: 12, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.cloud_upload_outlined, + color: + Theme.of(context).brightness == Brightness.light + ? const Color.fromRGBO(0, 0, 0, 0.6) + : const Color.fromRGBO(255, 255, 255, 0.6), + ), + const SizedBox(height: 16), + Text( + S.of(context).backupStatusDescription, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + height: 20 / 16, + color: + Theme.of(context).brightness == Brightness.light + ? const Color(0xFF000000).withOpacity(0.7) + : const Color(0xFFFFFFFF).withOpacity(0.7), + ), + ), + const SizedBox(height: 48), + ], + ), + ), + ) + : SliverList( + delegate: SliverChildBuilderDelegate( + (delegateBuildContext, index) { + return Padding( + padding: const EdgeInsets.symmetric( + vertical: 20, + horizontal: 16, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + for (final item in items) + BackupItemCard(item: item), + ], + ), + ); + }, + childCount: 1, + ), + ), + ], + ), + ); + } +} diff --git a/mobile/lib/utils/file_uploader.dart b/mobile/lib/utils/file_uploader.dart index 6e81e5acc5..c4c8217c5e 100644 --- a/mobile/lib/utils/file_uploader.dart +++ b/mobile/lib/utils/file_uploader.dart @@ -16,11 +16,14 @@ import 'package:photos/core/event_bus.dart'; import 'package:photos/core/network/network.dart'; import 'package:photos/db/files_db.dart'; import 'package:photos/db/upload_locks_db.dart'; +import "package:photos/events/backup_updated_event.dart"; import "package:photos/events/file_uploaded_event.dart"; import 'package:photos/events/files_updated_event.dart'; import 'package:photos/events/local_photos_updated_event.dart'; import 'package:photos/events/subscription_purchased_event.dart'; import 'package:photos/main.dart'; +import "package:photos/models/backup/backup_item.dart"; +import "package:photos/models/backup/backup_item_status.dart"; import 'package:photos/models/encryption_result.dart'; import 'package:photos/models/file/file.dart'; import 'package:photos/models/file/file_type.dart'; @@ -59,11 +62,15 @@ class FileUploader { final _enteDio = NetworkClient.instance.enteDio; final LinkedHashMap _queue = LinkedHashMap(); + final LinkedHashMap _allBackups = + LinkedHashMap(); final _uploadLocks = UploadLocksDB.instance; final kSafeBufferForLockExpiry = const Duration(days: 1).inMicroseconds; final kBGTaskDeathTimeout = const Duration(seconds: 5).inMicroseconds; final _uploadURLs = Queue(); + LinkedHashMap get allBackups => _allBackups; + // Maintains the count of files in the current upload session. // Upload session is the period between the first entry into the _queue and last entry out of the _queue int _totalCountInUploadSession = 0; @@ -160,6 +167,13 @@ class FileUploader { if (!_queue.containsKey(localID)) { final completer = Completer(); _queue[localID] = FileUploadItem(file, collectionID, completer); + _allBackups[localID] = BackupItem( + status: BackupItemStatus.inQueue, + file: file, + collectionID: collectionID, + completer: completer, + ); + Bus.instance.fire(BackupUpdatedEvent(_allBackups)); _pollQueue(); return completer.future; } @@ -203,6 +217,10 @@ class FileUploader { }); for (final id in uploadsToBeRemoved) { _queue.remove(id)?.completer.completeError(reason); + _allBackups[id] = _allBackups[id]!.copyWith( + status: BackupItemStatus.retry, + ); + Bus.instance.fire(BackupUpdatedEvent(_allBackups)); } _totalCountInUploadSession = 0; } @@ -225,6 +243,9 @@ class FileUploader { }); for (final id in uploadsToBeRemoved) { _queue.remove(id)?.completer.completeError(reason); + _allBackups[id] = + _allBackups[id]!.copyWith(status: BackupItemStatus.retry); + Bus.instance.fire(BackupUpdatedEvent(_allBackups)); } _logger.info( 'number of enteries removed from queue ${uploadsToBeRemoved.length}', @@ -291,13 +312,21 @@ class FileUploader { }, ); _queue.remove(localID)!.completer.complete(uploadedFile); + _allBackups[localID] = + _allBackups[localID]!.copyWith(status: BackupItemStatus.completed); return uploadedFile; } catch (e) { if (e is LockAlreadyAcquiredError) { _queue[localID]!.status = UploadStatus.inBackground; + _allBackups[localID] = _allBackups[localID]! + .copyWith(status: BackupItemStatus.inBackground); + Bus.instance.fire(BackupUpdatedEvent(_allBackups)); return _queue[localID]!.completer.future; } else { _queue.remove(localID)!.completer.completeError(e); + _allBackups[localID] = + _allBackups[localID]!.copyWith(status: BackupItemStatus.retry); + Bus.instance.fire(BackupUpdatedEvent(_allBackups)); return null; } } finally { @@ -406,7 +435,20 @@ class FileUploader { Future forceUpload(EnteFile file, int collectionID) async { _hasInitiatedForceUpload = true; - return _tryToUpload(file, collectionID, true); + try { + final result = await _tryToUpload(file, collectionID, true); + _allBackups[file.localID!] = _allBackups[file.localID]!.copyWith( + status: BackupItemStatus.completed, + ); + Bus.instance.fire(BackupUpdatedEvent(_allBackups)); + return result; + } catch (_) { + _allBackups[file.localID!] = _allBackups[file.localID]!.copyWith( + status: BackupItemStatus.retry, + ); + Bus.instance.fire(BackupUpdatedEvent(_allBackups)); + rethrow; + } } Future _tryToUpload( @@ -426,6 +468,14 @@ class FileUploader { return fileOnDisk; } } + + if (_allBackups[file.localID!] != null && + _allBackups[file.localID]!.status != BackupItemStatus.uploading) { + _allBackups[file.localID!] = _allBackups[file.localID]!.copyWith( + status: BackupItemStatus.uploading, + ); + Bus.instance.fire(BackupUpdatedEvent(_allBackups)); + } if ((file.localID ?? '') == '') { _logger.severe('Trying to upload file with missing localID'); return file; @@ -442,7 +492,7 @@ class FileUploader { } final String lockKey = file.localID!; - bool _isMultipartUpload = false; + bool isMultipartUpload = false; try { await _uploadLocks.acquireLock( @@ -589,7 +639,7 @@ class FileUploader { final fileUploadURL = await _getUploadURL(); fileObjectKey = await _putFile(fileUploadURL, encryptedFile); } else { - _isMultipartUpload = true; + isMultipartUpload = true; _logger.finest( "Init multipartUpload $multipartEntryExists, isUpdate $isUpdatedFile", ); @@ -757,7 +807,7 @@ class FileUploader { encryptedFilePath, encryptedThumbnailPath, lockKey: lockKey, - isMultiPartUpload: _isMultipartUpload, + isMultiPartUpload: isMultipartUpload, ); } } @@ -1280,10 +1330,15 @@ class FileUploader { if (dbFile?.uploadedFileID != null) { _logger.info("Background upload success detected"); completer?.complete(dbFile); + _allBackups[upload.key] = _allBackups[upload.key]! + .copyWith(status: BackupItemStatus.completed); } else { _logger.info("Background upload failure detected"); completer?.completeError(SilentlyCancelUploadsError()); + _allBackups[upload.key] = + _allBackups[upload.key]!.copyWith(status: BackupItemStatus.retry); } + Bus.instance.fire(BackupUpdatedEvent(_allBackups)); } } Future.delayed(kBlockedUploadsPollFrequency, () async { From 5662661326fd4c8cd62f146991cf1f6cdec88200 Mon Sep 17 00:00:00 2001 From: Prateek Sunal Date: Wed, 28 Aug 2024 01:22:00 +0530 Subject: [PATCH 111/275] fix(backup-status): limit folder name to single line --- mobile/lib/ui/settings/backup/backup_item_card.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mobile/lib/ui/settings/backup/backup_item_card.dart b/mobile/lib/ui/settings/backup/backup_item_card.dart index a566fc6a4a..e99d1ed54b 100644 --- a/mobile/lib/ui/settings/backup/backup_item_card.dart +++ b/mobile/lib/ui/settings/backup/backup_item_card.dart @@ -96,6 +96,8 @@ class _BackupItemCardState extends State { const SizedBox(height: 4), Text( folderName ?? "", + maxLines: 1, + overflow: TextOverflow.ellipsis, style: TextStyle( fontSize: 14, height: 17 / 14, From 325871f7c5456be01e3b32dbde964f4814562056 Mon Sep 17 00:00:00 2001 From: Prateek Sunal Date: Thu, 29 Aug 2024 00:53:57 +0530 Subject: [PATCH 112/275] fix(backup): attach reason of error, use ListView.builder, use upload instead of forceUpload --- mobile/lib/models/backup/backup_item.dart | 9 +++- .../ui/settings/backup/backup_item_card.dart | 10 ++--- .../settings/backup/backup_status_screen.dart | 13 +++--- mobile/lib/utils/file_uploader.dart | 44 ++++++++++++------- 4 files changed, 48 insertions(+), 28 deletions(-) diff --git a/mobile/lib/models/backup/backup_item.dart b/mobile/lib/models/backup/backup_item.dart index 02ea0c442d..957f0f883c 100644 --- a/mobile/lib/models/backup/backup_item.dart +++ b/mobile/lib/models/backup/backup_item.dart @@ -8,12 +8,14 @@ class BackupItem { final EnteFile file; final int collectionID; final Completer completer; + final Object? error; BackupItem({ required this.status, required this.file, required this.collectionID, required this.completer, + this.error, }); BackupItem copyWith({ @@ -21,18 +23,20 @@ class BackupItem { EnteFile? file, int? collectionID, Completer? completer, + Object? error, }) { return BackupItem( status: status ?? this.status, file: file ?? this.file, collectionID: collectionID ?? this.collectionID, completer: completer ?? this.completer, + error: error ?? this.error, ); } @override String toString() { - return 'BackupItem(status: $status, file: $file, collectionID: $collectionID)'; + return 'BackupItem(status: $status, file: $file, collectionID: $collectionID, error: $error)'; } @override @@ -42,7 +46,8 @@ class BackupItem { return other.status == status && other.file == file && other.collectionID == collectionID && - other.completer == completer; + other.completer == completer && + other.error == error; } @override diff --git a/mobile/lib/ui/settings/backup/backup_item_card.dart b/mobile/lib/ui/settings/backup/backup_item_card.dart index e99d1ed54b..40be26cbdc 100644 --- a/mobile/lib/ui/settings/backup/backup_item_card.dart +++ b/mobile/lib/ui/settings/backup/backup_item_card.dart @@ -147,17 +147,17 @@ class _BackupItemCardState extends State { color: Color(0xFFFDB816), ), onPressed: () async { - await FileUploader.instance.forceUpload( + await FileUploader.instance.upload( widget.item.file, widget.item.collectionID, ); }, ), BackupItemStatus.inBackground => SizedBox( - width: 24, - height: 24, - child: Icon( - Icons.lock_reset, + width: 16, + height: 16, + child: CircularProgressIndicator( + strokeWidth: 2.0, color: Theme.of(context).brightness == Brightness.light ? const Color.fromRGBO(0, 0, 0, .6) : const Color.fromRGBO(255, 255, 255, .6), diff --git a/mobile/lib/ui/settings/backup/backup_status_screen.dart b/mobile/lib/ui/settings/backup/backup_status_screen.dart index 4117e2c980..0d7199ca47 100644 --- a/mobile/lib/ui/settings/backup/backup_status_screen.dart +++ b/mobile/lib/ui/settings/backup/backup_status_screen.dart @@ -91,12 +91,13 @@ class _BackupStatusScreenState extends State { vertical: 20, horizontal: 16, ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - for (final item in items) - BackupItemCard(item: item), - ], + child: ListView.builder( + shrinkWrap: true, + primary: false, + itemBuilder: (context, index) { + return BackupItemCard(item: items[index]); + }, + itemCount: items.length, ), ); }, diff --git a/mobile/lib/utils/file_uploader.dart b/mobile/lib/utils/file_uploader.dart index c4c8217c5e..0b3ee1c4bc 100644 --- a/mobile/lib/utils/file_uploader.dart +++ b/mobile/lib/utils/file_uploader.dart @@ -219,6 +219,7 @@ class FileUploader { _queue.remove(id)?.completer.completeError(reason); _allBackups[id] = _allBackups[id]!.copyWith( status: BackupItemStatus.retry, + error: reason, ); Bus.instance.fire(BackupUpdatedEvent(_allBackups)); } @@ -243,8 +244,8 @@ class FileUploader { }); for (final id in uploadsToBeRemoved) { _queue.remove(id)?.completer.completeError(reason); - _allBackups[id] = - _allBackups[id]!.copyWith(status: BackupItemStatus.retry); + _allBackups[id] = _allBackups[id]! + .copyWith(status: BackupItemStatus.retry, error: reason); Bus.instance.fire(BackupUpdatedEvent(_allBackups)); } _logger.info( @@ -283,6 +284,10 @@ class FileUploader { } if (pendingEntry != null) { pendingEntry.status = UploadStatus.inProgress; + _allBackups[pendingEntry.file.localID!] = + _allBackups[pendingEntry.file.localID]! + .copyWith(status: BackupItemStatus.uploading); + Bus.instance.fire(BackupUpdatedEvent(_allBackups)); _encryptAndUploadFileToCollection( pendingEntry.file, pendingEntry.collectionID, @@ -314,6 +319,7 @@ class FileUploader { _queue.remove(localID)!.completer.complete(uploadedFile); _allBackups[localID] = _allBackups[localID]!.copyWith(status: BackupItemStatus.completed); + Bus.instance.fire(BackupUpdatedEvent(_allBackups)); return uploadedFile; } catch (e) { if (e is LockAlreadyAcquiredError) { @@ -324,8 +330,8 @@ class FileUploader { return _queue[localID]!.completer.future; } else { _queue.remove(localID)!.completer.completeError(e); - _allBackups[localID] = - _allBackups[localID]!.copyWith(status: BackupItemStatus.retry); + _allBackups[localID] = _allBackups[localID]! + .copyWith(status: BackupItemStatus.retry, error: e); Bus.instance.fire(BackupUpdatedEvent(_allBackups)); return null; } @@ -435,18 +441,24 @@ class FileUploader { Future forceUpload(EnteFile file, int collectionID) async { _hasInitiatedForceUpload = true; + final isInQueue = _allBackups[file.localID!] != null; try { final result = await _tryToUpload(file, collectionID, true); - _allBackups[file.localID!] = _allBackups[file.localID]!.copyWith( - status: BackupItemStatus.completed, - ); - Bus.instance.fire(BackupUpdatedEvent(_allBackups)); + if (isInQueue) { + _allBackups[file.localID!] = _allBackups[file.localID]!.copyWith( + status: BackupItemStatus.completed, + ); + Bus.instance.fire(BackupUpdatedEvent(_allBackups)); + } return result; - } catch (_) { - _allBackups[file.localID!] = _allBackups[file.localID]!.copyWith( - status: BackupItemStatus.retry, - ); - Bus.instance.fire(BackupUpdatedEvent(_allBackups)); + } catch (error) { + if (isInQueue) { + _allBackups[file.localID!] = _allBackups[file.localID]!.copyWith( + status: BackupItemStatus.retry, + error: error, + ); + Bus.instance.fire(BackupUpdatedEvent(_allBackups)); + } rethrow; } } @@ -1335,8 +1347,10 @@ class FileUploader { } else { _logger.info("Background upload failure detected"); completer?.completeError(SilentlyCancelUploadsError()); - _allBackups[upload.key] = - _allBackups[upload.key]!.copyWith(status: BackupItemStatus.retry); + _allBackups[upload.key] = _allBackups[upload.key]!.copyWith( + status: BackupItemStatus.retry, + error: SilentlyCancelUploadsError(), + ); } Bus.instance.fire(BackupUpdatedEvent(_allBackups)); } From ac0ae000154889154dcc25ca87889369d59554c0 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Tue, 27 Aug 2024 14:29:20 +0530 Subject: [PATCH 113/275] [mob][auth] Update flutter submodule to v3.24.1 --- auth/flutter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auth/flutter b/auth/flutter index 80c2e84975..5874a72aa4 160000 --- a/auth/flutter +++ b/auth/flutter @@ -1 +1 @@ -Subproject commit 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 +Subproject commit 5874a72aa4c779a02553007c47dacbefba2374dc From d413ed2de0e8bf47703ca9603be8e28a0aac9df5 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Tue, 27 Aug 2024 14:29:27 +0530 Subject: [PATCH 114/275] [mob][auth] Update flutter version in github workflows --- .github/workflows/auth-lint.yml | 2 +- .github/workflows/auth-release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/auth-lint.yml b/.github/workflows/auth-lint.yml index 4518c542da..2362d2b344 100644 --- a/.github/workflows/auth-lint.yml +++ b/.github/workflows/auth-lint.yml @@ -8,7 +8,7 @@ on: - ".github/workflows/auth-lint.yml" env: - FLUTTER_VERSION: "3.24.0" + FLUTTER_VERSION: "3.24.1" jobs: lint: diff --git a/.github/workflows/auth-release.yml b/.github/workflows/auth-release.yml index ef7a3d9192..d67cf1c7e9 100644 --- a/.github/workflows/auth-release.yml +++ b/.github/workflows/auth-release.yml @@ -29,7 +29,7 @@ on: - "auth-v*" env: - FLUTTER_VERSION: "3.24.0" + FLUTTER_VERSION: "3.24.1" jobs: build-ubuntu: From d5a1187e13a20c3c58d73b01314eb3447ce14843 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 29 Aug 2024 20:33:18 +0530 Subject: [PATCH 115/275] Prep --- web/apps/photos/src/pages/cluster-debug.tsx | 24 +++++++++----- .../new/photos/components/MLSettings.tsx | 15 +++++---- .../new/photos/services/ml/cluster-new.ts | 32 +++++++++---------- 3 files changed, 40 insertions(+), 31 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index db187751de..fcbeadfcab 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -49,14 +49,22 @@ export default function ClusterDebug() { } return ( <> - - {`${clusterRes.clusters.length} clusters from ${clusterRes.clusteredCount} faces. ${clusterRes.unclusteredCount} unclustered faces.`} - - - Showing only top 20 and bottom 10 clusters (and only up to 50 - faces in each, sorted by cosine distance to highest scoring face - in the cluster). - + + + {`${clusterRes.clusters.length} clusters from ${clusterRes.clusteredCount} faces. ${clusterRes.unclusteredCount} unclustered faces.`} + + + Showing only top 30 and bottom 30 clusters. + + + For each cluster showing only up to 50 faces, sorted by + cosine similarity to highest scoring face in the cluster. + + + Below each face is its{" "} + blur - score - cosineSimilarity - direction + +
diff --git a/web/packages/new/photos/components/MLSettings.tsx b/web/packages/new/photos/components/MLSettings.tsx index eeff4d1be8..c8785110b6 100644 --- a/web/packages/new/photos/components/MLSettings.tsx +++ b/web/packages/new/photos/components/MLSettings.tsx @@ -8,7 +8,6 @@ import { enableML, mlStatusSnapshot, mlStatusSubscribe, - wipCluster, wipClusterEnable, type MLStatus, } from "@/new/photos/services/ml"; @@ -341,7 +340,7 @@ const ManageML: React.FC = ({ // TODO-Cluster const router = useRouter(); - const wipClusterNow = () => wipCluster(); + // const wipClusterNow = () => wipCluster(); const wipClusterShowNow = () => router.push("/cluster-debug"); return ( @@ -391,18 +390,20 @@ const ManageML: React.FC = ({ )} - {showClusterOpt && ( + {/* {showClusterOpt && ( = ({ )} /> - )} + )} */} ); }; diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index df97ca4bd9..d6e1dc505a 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -348,14 +348,13 @@ function* enumerateFaces(faceIndices: FaceIndex[]) { } } -export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { +export const clusterFacesHdb = (faceIndexes: FaceIndex[]) => { const t = Date.now(); // A flattened array of faces. // TODO-Cluster ad-hoc filtering and slicing - const faces0 = [...enumerateFaces(faceIndexes)] - .filter((f) => f.blur > 99) - .slice(0, 6000); + const faces0 = [...enumerateFaces(faceIndexes)].filter((f) => f.blur > 99); + // .slice(0, 6000); // TODO-Cluster testing code, can be removed once done const faces = Array(1) .fill(0) @@ -386,27 +385,28 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { // be list of existing clusters we fetch from remote. const clusters: FaceCluster[] = []; - // Process the faces in batches of 10k. The faces are already sorted by file - // ID, which is a monotonically increasing integer, so we will also have - // some temporal locality. + // Process the faces in batches. The faces are already sorted by file ID, + // which is a monotonically increasing integer, so we will also have some + // temporal locality. // - // The number 10k was derived by ad-hoc observations. On a particular test - // dataset, clustering 10k took ~2 mins, while 20k took ~8 mins. Memory - // usage was constant in both cases. + // The number 2500 was derived by ad-hoc observations and takes a few + // seconds. On a particular test dataset and a particular machine, + // clustering 1k took ~2 seconds, 10k took ~2 mins, while 20k took ~8 mins. + // Memory usage was constant in all these cases. // // At around 100k faces, the clustering starts taking hours, and we start // running into stack overflows. The stack overflows can perhaps be avoided // by restructuring the code, but hours of uninterruptible work is anyways // not feasible. - // const batchSize = 10_000; // TODO-Cluster - const batchSize = 1_000; + const batchSize = 2500; for (let i = 0; i < faceEmbeddings.length; i += batchSize) { + const it = Date.now(); const embeddings = faceEmbeddings.slice(i, i + batchSize); const { clusters: hdbClusters } = clusterFacesHdbscan(embeddings); log.info( - `hdbscan produced ${hdbClusters.length} clusters from ${embeddings.length} faces (${Date.now() - t} ms)`, + `hdbscan produced ${hdbClusters.length} clusters from ${embeddings.length} faces (${Date.now() - it} ms)`, ); // Merge the new clusters we got from hdbscan into the existing clusters @@ -489,7 +489,7 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { // Convert into the data structure we're using to debug/visualize. // - // > Showing only top 20 and bottom 10 clusters (and only up to 50 faces in + // > Showing only top 30 and bottom 30 clusters (and only up to 50 faces in // > each, sorted by cosine distance to highest scoring face in the // > cluster). @@ -497,9 +497,9 @@ export const clusterFacesHdb = async (faceIndexes: FaceIndex[]) => { (a, b) => b.faceIDs.length - a.faceIDs.length, ); const debugClusters = - sortedClusters.length < 30 + sortedClusters.length < 60 ? sortedClusters - : sortedClusters.slice(0, 20).concat(sortedClusters.slice(-10)); + : sortedClusters.slice(0, 30).concat(sortedClusters.slice(-30)); const clusterPreviews: ClusterPreview[] = []; for (const cluster of debugClusters) { const faces = cluster.faceIDs.map((id) => From be3a7093354e8e40096f8640da5c74f6b2047ace Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Thu, 29 Aug 2024 22:26:03 +0530 Subject: [PATCH 116/275] [server] Use nanoId as reqID --- server/cmd/museum/main.go | 10 +++++++++- server/ente/base/id.go | 10 ++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/server/cmd/museum/main.go b/server/cmd/museum/main.go index 234b0435bf..531b720ee3 100644 --- a/server/cmd/museum/main.go +++ b/server/cmd/museum/main.go @@ -5,6 +5,7 @@ import ( "database/sql" b64 "encoding/base64" "fmt" + "github.com/ente-io/museum/ente/base" "github.com/ente-io/museum/pkg/controller/file_copy" "github.com/ente-io/museum/pkg/controller/filedata" "net/http" @@ -361,7 +362,14 @@ func main() { server.Use(p.HandlerFunc()) // note: the recover middleware must be in the last - server.Use(requestid.New(), middleware.Logger(urlSanitizer), cors(), gzip.Gzip(gzip.DefaultCompression), middleware.PanicRecover()) + + server.Use(requestid.New( + requestid.Config{ + Generator: func() string { + return base.ServerReqID() + }, + }), + middleware.Logger(urlSanitizer), cors(), gzip.Gzip(gzip.DefaultCompression), middleware.PanicRecover()) publicAPI := server.Group("/") publicAPI.Use(rateLimiter.GlobalRateLimiter(), rateLimiter.APIRateLimitMiddleware(urlSanitizer)) diff --git a/server/ente/base/id.go b/server/ente/base/id.go index f6579a05c6..559bc41542 100644 --- a/server/ente/base/id.go +++ b/server/ente/base/id.go @@ -3,6 +3,7 @@ package base import ( "errors" "fmt" + "github.com/google/uuid" "github.com/matoous/go-nanoid/v2" ) @@ -28,3 +29,12 @@ func NewID(prefix string) (*string, error) { result := fmt.Sprintf("%s_%s", prefix, id) return &result, nil } + +func ServerReqID() string { + // Generate a nanoid with a custom alphabet and length of 22 + id, err := NewID("ser") + if err != nil { + return "ser_" + uuid.New().String() + } + return *id +} From dc6fde9f77c5afcbf24982d6d1b85fc013c8c836 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Thu, 29 Aug 2024 19:17:33 +0530 Subject: [PATCH 117/275] [mob][photos] Fix: audio not playing on iOS when in silent mode --- mobile/ios/Podfile.lock | 2 +- mobile/ios/Runner/AppDelegate.swift | 28 ++++++++++++++++++++++++++- mobile/lib/audio_session_handler.dart | 16 +++++++++++++++ mobile/lib/main.dart | 5 +++++ 4 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 mobile/lib/audio_session_handler.dart diff --git a/mobile/ios/Podfile.lock b/mobile/ios/Podfile.lock index 8ebcc2c8fe..c40e47d7ab 100644 --- a/mobile/ios/Podfile.lock +++ b/mobile/ios/Podfile.lock @@ -472,7 +472,7 @@ SPEC CHECKSUMS: image_editor_common: d6f6644ae4a6de80481e89fe6d0a8c49e30b4b43 image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 in_app_purchase_storekit: 0e4b3c2e43ba1e1281f4f46dd71b0593ce529892 - integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4 + integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009 local_auth_darwin: c7e464000a6a89e952235699e32b329457608d98 local_auth_ios: 5046a18c018dd973247a0564496c8898dbb5adf9 diff --git a/mobile/ios/Runner/AppDelegate.swift b/mobile/ios/Runner/AppDelegate.swift index 9824022683..3f14877d91 100644 --- a/mobile/ios/Runner/AppDelegate.swift +++ b/mobile/ios/Runner/AppDelegate.swift @@ -1,7 +1,8 @@ import Flutter import UIKit +import AVFoundation -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, @@ -12,11 +13,36 @@ import UIKit UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate } + let controller : FlutterViewController = window?.rootViewController as! FlutterViewController + let audioSessionChannel = FlutterMethodChannel(name: "io.ente.frame/audio_session", + binaryMessenger: controller.binaryMessenger) + + audioSessionChannel.setMethodCallHandler({ + (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in + if call.method == "setAudioSessionCategory" { + self.setAudioSessionCategory(result: result) + } else { + result(FlutterMethodNotImplemented) + } + }) + GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } + private func setAudioSessionCategory(result: @escaping FlutterResult) { + do { + try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers, .defaultToSpeaker]) + try AVAudioSession.sharedInstance().setActive(true) + result(nil) + } catch { + result(FlutterError(code: "AUDIO_SESSION_ERROR", + message: "Failed to set audio session category", + details: error.localizedDescription)) + } + } + override func applicationDidBecomeActive(_ application: UIApplication) { signal(SIGPIPE, SIG_IGN) } diff --git a/mobile/lib/audio_session_handler.dart b/mobile/lib/audio_session_handler.dart new file mode 100644 index 0000000000..8aede31b12 --- /dev/null +++ b/mobile/lib/audio_session_handler.dart @@ -0,0 +1,16 @@ +import "package:flutter/services.dart"; +import "package:logging/logging.dart"; + +class AudioSessionHandler { + static final _logger = Logger("AudioSessionHandler"); + static const MethodChannel _channel = + MethodChannel('io.ente.frame/audio_session'); + + static Future setAudioSessionCategory() async { + try { + await _channel.invokeMethod('setAudioSessionCategory'); + } on PlatformException catch (e) { + _logger.warning("Failed to set audio session category: '${e.message}'."); + } + } +} diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index 09126649df..c2c3a38fa6 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -14,6 +14,7 @@ import 'package:logging/logging.dart'; import "package:media_kit/media_kit.dart"; import 'package:path_provider/path_provider.dart'; import 'package:photos/app.dart'; +import "package:photos/audio_session_handler.dart"; import 'package:photos/core/configuration.dart'; import 'package:photos/core/constants.dart'; import 'package:photos/core/error-reporting/super_logging.dart'; @@ -73,6 +74,10 @@ const kFGTaskDeathTimeoutInMicroseconds = 5000000; void main() async { debugRepaintRainbowEnabled = false; WidgetsFlutterBinding.ensureInitialized(); + //For audio to work on vidoes in iOS when in silent mode. + if (Platform.isIOS) { + unawaited(AudioSessionHandler.setAudioSessionCategory()); + } MediaKit.ensureInitialized(); final savedThemeMode = await AdaptiveTheme.getThemeMode(); From 3feac9f0b40d65e1ce2c64d363af75c6e59a7c9d Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Fri, 30 Aug 2024 13:16:08 +0530 Subject: [PATCH 118/275] [mob] Bump version v0.9.31 --- mobile/lib/generated/intl/messages_en.dart | 2 +- mobile/lib/generated/l10n.dart | 4 ++-- mobile/pubspec.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mobile/lib/generated/intl/messages_en.dart b/mobile/lib/generated/intl/messages_en.dart index 801ea0c58a..9eaa0d5e5e 100644 --- a/mobile/lib/generated/intl/messages_en.dart +++ b/mobile/lib/generated/intl/messages_en.dart @@ -504,7 +504,7 @@ class MessageLookup extends MessageLookupByLibrary { "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage("Confirm Account Deletion"), "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "Yes, I want to permanently delete this account and all its data."), + "Yes, I want to permanently delete this account and its data across all apps."), "confirmPassword": MessageLookupByLibrary.simpleMessage("Confirm password"), "confirmPlanChange": diff --git a/mobile/lib/generated/l10n.dart b/mobile/lib/generated/l10n.dart index 5ede242db1..e12296fb2c 100644 --- a/mobile/lib/generated/l10n.dart +++ b/mobile/lib/generated/l10n.dart @@ -170,10 +170,10 @@ class S { ); } - /// `Yes, I want to permanently delete this account and all its data.` + /// `Yes, I want to permanently delete this account and its data across all apps.` String get confirmDeletePrompt { return Intl.message( - 'Yes, I want to permanently delete this account and all its data.', + 'Yes, I want to permanently delete this account and its data across all apps.', name: 'confirmDeletePrompt', desc: '', args: [], diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index b13a3237f0..1852638d13 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -12,7 +12,7 @@ description: ente photos application # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 0.9.30+930 +version: 0.9.31+931 publish_to: none environment: From d374960c353a073c35e4893e5d1c2215ed4c9f81 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 30 Aug 2024 13:18:57 +0530 Subject: [PATCH 119/275] Tweak the debugging panel --- web/apps/photos/src/pages/gallery/index.tsx | 12 +++------- .../new/photos/components/MLSettings.tsx | 22 +++---------------- 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/web/apps/photos/src/pages/gallery/index.tsx b/web/apps/photos/src/pages/gallery/index.tsx index 1876fca7f4..74273eb014 100644 --- a/web/apps/photos/src/pages/gallery/index.tsx +++ b/web/apps/photos/src/pages/gallery/index.tsx @@ -6,10 +6,7 @@ import { getLocalFiles, getLocalTrashedFiles, } from "@/new/photos/services/files"; -import { - wipClusterEnable, - wipHasSwitchedOnceCmpAndSet, -} from "@/new/photos/services/ml"; +import { wipHasSwitchedOnceCmpAndSet } from "@/new/photos/services/ml"; import { EnteFile } from "@/new/photos/types/file"; import { mergeMetadata } from "@/new/photos/utils/file"; import { CenteredFlex } from "@ente/shared/components/Container"; @@ -677,11 +674,8 @@ export default function Gallery() { // TODO-Cluster if (process.env.NEXT_PUBLIC_ENTE_WIP_CL_AUTO) { setTimeout(() => { - if (!wipHasSwitchedOnceCmpAndSet()) { - void wipClusterEnable().then( - (y) => y && router.push("cluster-debug"), - ); - } + if (!wipHasSwitchedOnceCmpAndSet()) + router.push("cluster-debug"); }, 2000); } }, []); diff --git a/web/packages/new/photos/components/MLSettings.tsx b/web/packages/new/photos/components/MLSettings.tsx index c8785110b6..dde90b5368 100644 --- a/web/packages/new/photos/components/MLSettings.tsx +++ b/web/packages/new/photos/components/MLSettings.tsx @@ -340,8 +340,7 @@ const ManageML: React.FC = ({ // TODO-Cluster const router = useRouter(); - // const wipClusterNow = () => wipCluster(); - const wipClusterShowNow = () => router.push("/cluster-debug"); + const wipClusterDebug = () => router.push("/cluster-debug"); return ( @@ -393,31 +392,16 @@ const ManageML: React.FC = ({ label={ut( "Create clusters • internal only option", )} - onClick={wipClusterShowNow} + onClick={wipClusterDebug} /> )} - {/* {showClusterOpt && ( - - - - - - - )} */} ); }; From ed1970b6d81cc0702fba60ed69b6b7bd2cabb7c5 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Fri, 30 Aug 2024 14:51:43 +0530 Subject: [PATCH 120/275] [docs] Add troubleshooting guide for auth --- docs/docs/.vitepress/sidebar.ts | 9 ++++ .../auth/troubleshooting/windows-login.md | 43 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 docs/docs/auth/troubleshooting/windows-login.md diff --git a/docs/docs/.vitepress/sidebar.ts b/docs/docs/.vitepress/sidebar.ts index 62b3cedf87..35eac00fd5 100644 --- a/docs/docs/.vitepress/sidebar.ts +++ b/docs/docs/.vitepress/sidebar.ts @@ -205,6 +205,15 @@ export const sidebar = [ }, ], }, + { + text: "Troubleshooting", + items: [ + { + text: "Windows login", + link: "/auth/troubleshooting/windows-login", + }, + ], + }, ], }, { diff --git a/docs/docs/auth/troubleshooting/windows-login.md b/docs/docs/auth/troubleshooting/windows-login.md new file mode 100644 index 0000000000..2a990fc7af --- /dev/null +++ b/docs/docs/auth/troubleshooting/windows-login.md @@ -0,0 +1,43 @@ +--- +title: Unable to login on Windows Desktop +description: + Troubleshooting when you are not able to login or register on Ente Auth app on Windows +--- + + + +# Windows Login Error + + +### HandshakeException: Handshake error in client + +This error usually happens when the Trusted Root certificates on your Windows machine are outdated. + +To update the Trusted Root Certificates on Windows, you can use the `certutil` command. Here are the steps to do so: + +1. **Open Command Prompt as Administrator**: + - Press `Windows + X` and select `Command Prompt (Admin)` or `Windows PowerShell (Admin)`. + +2. **Run the following command to update the root certificates**: + ```bash + certutil -generateSSTFromWU roots.sst + ``` + This command will generate a file named `roots.sst` that contains the latest root certificates from Windows Update. + +3. **Install the new root certificates**: + ```bash + certutil -addstore -f ROOT roots.sst + ``` + This command will add the certificates from the `roots.sst` file to the Trusted Root Certification Authorities store. + +4. **Clean up**: + After the installation, you can delete the `roots.sst` file if you no longer need it: + ```bash + del roots.sst + ``` + +Make sure to restart your application after updating the certificates to ensure the changes take effect. + +If the above steps don't resolve the issue, please follow [this guide](https://woshub.com/updating-trusted-root-certificates-in-windows-10/#h2_3) to update your trusted root certicates, and try again. + + From ed3d8b984e721de8902b66549cdbafa8c1012a91 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 30 Aug 2024 15:09:53 +0530 Subject: [PATCH 121/275] Scrollable header --- web/apps/photos/src/pages/cluster-debug.tsx | 221 +++++++++++--------- 1 file changed, 117 insertions(+), 104 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index fcbeadfcab..d1ab0342b0 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -2,10 +2,8 @@ import { SelectionBar } from "@/base/components/Navbar"; import { pt } from "@/base/i18n"; import { faceCrop, - wipClusterDebugPageContents, type ClusterDebugPageContents, type ClusterPreviewFaceWF, - type ClusterPreviewWF, } from "@/new/photos/services/ml"; import { faceDirection } from "@/new/photos/services/ml/face"; import { @@ -24,56 +22,18 @@ import { VariableSizeList } from "react-window"; // TODO-Cluster Temporary component for debugging export default function ClusterDebug() { - const { startLoading, finishLoading, showNavBar } = useContext(AppContext); - const [clusterRes, setClusterRes] = useState< - ClusterDebugPageContents | undefined - >(); + const { showNavBar } = useContext(AppContext); useEffect(() => { showNavBar(true); - cluster(); }, []); - const cluster = async () => { - startLoading(); - setClusterRes(await wipClusterDebugPageContents()); - finishLoading(); - }; - - if (!clusterRes) { - return ( - - - - ); - } return ( <> - - - {`${clusterRes.clusters.length} clusters from ${clusterRes.clusteredCount} faces. ${clusterRes.unclusteredCount} unclustered faces.`} - - - Showing only top 30 and bottom 30 clusters. - - - For each cluster showing only up to 50 faces, sorted by - cosine similarity to highest scoring face in the cluster. - - - Below each face is its{" "} - blur - score - cosineSimilarity - direction - - -
{({ height, width }) => ( - + )} @@ -101,6 +61,7 @@ const Options: React.FC = () => { const Container = styled("div")` display: block; + border: 1px solid tomato; flex: 1; width: 100%; flex-wrap: wrap; @@ -110,21 +71,36 @@ const Container = styled("div")` } `; -interface ClusterPhotoListProps { +interface ClusterListProps { height: number; width: number; - clusterRes: ClusterDebugPageContents; } -const ClusterPhotoList: React.FC = ({ - height, - width, - clusterRes, -}) => { - const { clusterPreviewWFs, clusterIDForFaceID } = clusterRes; - const [itemList, setItemList] = useState([]); +const ClusterList: React.FC = ({ height, width }) => { + const { startLoading, finishLoading } = useContext(AppContext); + + const [clusterRes, setClusterRes] = useState< + ClusterDebugPageContents | undefined + >(); + const [items, setItems] = useState([]); const listRef = useRef(null); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const cluster = async () => { + startLoading(); + // setClusterRes(await wipClusterDebugPageContents()); + setClusterRes({ + clusteredCount: 1, + unclusteredCount: 2, + clusterPreviewWFs: Array(100) + .fill(0) + .map(() => ({ clusterSize: 0, faces: [] })), + clusters: [], + clusterIDForFaceID: new Map(), + }); + finishLoading(); + }; + const columns = useMemo( () => Math.max(Math.floor(getFractionFittableColumns(width)), 4), [width], @@ -134,36 +110,40 @@ const ClusterPhotoList: React.FC = ({ const listItemHeight = 120 * shrinkRatio + 24 + 4; useEffect(() => { - setItemList(itemListFromClusterPreviewWFs(clusterPreviewWFs, columns)); - }, [columns, clusterPreviewWFs]); + setItems(clusterRes ? itemsFromClusterRes(clusterRes, columns) : []); + }, [columns, clusterRes]); useEffect(() => { listRef.current?.resetAfterIndex(0); - }, [itemList]); + }, [items]); - const getItemSize = (i: number) => - Array.isArray(itemList[i]) ? listItemHeight : 36; + const clusterIDForFaceID = clusterRes?.clusterIDForFaceID; - const generateKey = (i: number) => - Array.isArray(itemList[i]) - ? `${itemList[i][0].enteFile.id}/${itemList[i][0].face.faceID}-${itemList[i].slice(-1)[0].enteFile.id}/${itemList[i].slice(-1)[0].face.faceID}-${i}` - : `${itemList[i]}-${i}`; + const getItemSize = (index: number) => + index === 0 + ? 100 + : Array.isArray(items[index - 1]) + ? listItemHeight + : 36; return ( - {({ index, style, data }) => { - const { itemList, columns, shrinkRatio } = data; - const item = itemList[index]; + {({ index, style }) => { + if (index === 0) + return ( +
+
+
+ ); + + const item = items[index - 1]; return ( = ({ ); }; -// type ItemListItem = Face | FaceFileNeighbour[]; -type ItemListItem = number | ClusterPreviewFaceWF[]; +type Item = number | ClusterPreviewFaceWF[]; -const itemListFromClusterPreviewWFs = ( - clusterPreviewWFs: ClusterPreviewWF[], +const itemsFromClusterRes = ( + clusterRes: ClusterDebugPageContents, columns: number, ) => { - const result: ItemListItem[] = []; + const { clusterPreviewWFs } = clusterRes; + + const result: Item[] = []; for (let index = 0; index < clusterPreviewWFs.length; index++) { const { clusterSize, faces } = clusterPreviewWFs[index]; result.push(clusterSize); @@ -219,9 +200,69 @@ const getShrinkRatio = (width: number, columns: number) => (width - 2 * getGapFromScreenEdge(width) - (columns - 1) * 4) / (columns * 120); +const ListContainer = styled(Box, { + shouldForwardProp: (propName) => propName != "shrinkRatio", +})<{ + columns: number; + shrinkRatio: number; +}>` + display: grid; + grid-template-columns: ${({ columns, shrinkRatio }) => + `repeat(${columns},${120 * shrinkRatio}px)`}; + grid-column-gap: 4px; + width: 100%; + padding: 4px; +`; + +const ListItemContainer = styled(FlexWrapper)<{ span: number }>` + grid-column: span ${(props) => props.span}; +`; + +const LabelContainer = styled(ListItemContainer)` + color: ${({ theme }) => theme.colors.text.muted}; + height: 32px; +`; + +const ListItem = styled("div")` + display: flex; + justify-content: center; +`; + +interface HeaderProps { + clusterRes: ClusterDebugPageContents | undefined; +} + +const Header: React.FC = ({ clusterRes }) => { + if (!clusterRes) return ; + return ( + + + {`${clusterRes.clusters.length} clusters from ${clusterRes.clusteredCount} faces. ${clusterRes.unclusteredCount} unclustered faces.`} + + + Showing only top 30 and bottom 30 clusters. + + + For each cluster showing only up to 50 faces, sorted by cosine + similarity to highest scoring face in the cluster. + + + Below each face is its{" "} + blur - score - cosineSimilarity - direction + + + ); +}; + +const Loader = () => ( + + + +); + interface FaceItemProps { faceWF: ClusterPreviewFaceWF; - clusterIDForFaceID: Map; + clusterIDForFaceID: Map | undefined; } const FaceItem: React.FC = ({ faceWF, clusterIDForFaceID }) => { @@ -250,7 +291,7 @@ const FaceItem: React.FC = ({ faceWF, clusterIDForFaceID }) => { return ( @@ -292,31 +333,3 @@ const outlineForCluster = (clusterID: string | undefined) => const hForID = (id: string) => ([...id].reduce((s, c) => s + c.charCodeAt(0), 0) % 10) * 36; - -const ListContainer = styled(Box, { - shouldForwardProp: (propName) => propName != "shrinkRatio", -})<{ - columns: number; - shrinkRatio: number; -}>` - display: grid; - grid-template-columns: ${({ columns, shrinkRatio }) => - `repeat(${columns},${120 * shrinkRatio}px)`}; - grid-column-gap: 4px; - width: 100%; - padding: 4px; -`; - -const ListItemContainer = styled(FlexWrapper)<{ span: number }>` - grid-column: span ${(props) => props.span}; -`; - -const LabelContainer = styled(ListItemContainer)` - color: ${({ theme }) => theme.colors.text.muted}; - height: 32px; -`; - -const ListItem = styled("div")` - display: flex; - justify-content: center; -`; From 657f27822c210c7d03a55426a2af791c1491e9db Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 30 Aug 2024 15:21:28 +0530 Subject: [PATCH 122/275] form 1 --- web/apps/photos/src/pages/cluster-debug.tsx | 39 ++++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index d1ab0342b0..6f6e9d4c23 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -6,6 +6,7 @@ import { type ClusterPreviewFaceWF, } from "@/new/photos/services/ml"; import { faceDirection } from "@/new/photos/services/ml/face"; +import { wait } from "@/utils/promise"; import { FlexWrapper, FluidContainer, @@ -14,6 +15,7 @@ import { import EnteSpinner from "@ente/shared/components/EnteSpinner"; import BackButton from "@mui/icons-material/ArrowBackOutlined"; import { Box, IconButton, Stack, styled, Typography } from "@mui/material"; +import { useFormik } from "formik"; import { useRouter } from "next/router"; import { AppContext } from "pages/_app"; import React, { useContext, useEffect, useMemo, useRef, useState } from "react"; @@ -76,6 +78,12 @@ interface ClusterListProps { width: number; } +interface ClusteringOpts { + method: "hdbscan"; + batchSize: number; + joinThreshold: number; +} + const ClusterList: React.FC = ({ height, width }) => { const { startLoading, finishLoading } = useContext(AppContext); @@ -86,9 +94,11 @@ const ClusterList: React.FC = ({ height, width }) => { const listRef = useRef(null); // eslint-disable-next-line @typescript-eslint/no-unused-vars - const cluster = async () => { + const cluster = async (opts: ClusteringOpts) => { startLoading(); // setClusterRes(await wipClusterDebugPageContents()); + console.log(opts); + await wait(5000); setClusterRes({ clusteredCount: 1, unclusteredCount: 2, @@ -139,7 +149,10 @@ const ClusterList: React.FC = ({ height, width }) => { if (index === 0) return (
-
+
void cluster(opts)} + />
); @@ -230,12 +243,26 @@ const ListItem = styled("div")` interface HeaderProps { clusterRes: ClusterDebugPageContents | undefined; + onCluster: (opts: ClusteringOpts) => void; } -const Header: React.FC = ({ clusterRes }) => { - if (!clusterRes) return ; - return ( +const Header: React.FC = ({ clusterRes, onCluster }) => { + const formik = useFormik({ + initialValues: { + method: "hdbscan", + batchSize: 2500, + joinThreshold: 0.7, + }, + onSubmit: onCluster, + }); + + const clusterInfo = !clusterRes ? ( + + ) : ( +
+ +
{`${clusterRes.clusters.length} clusters from ${clusterRes.clusteredCount} faces. ${clusterRes.unclusteredCount} unclustered faces.`} @@ -252,6 +279,8 @@ const Header: React.FC = ({ clusterRes }) => {
); + + return
{clusterInfo}
; }; const Loader = () => ( From d9ca47914d0b25f8381c1f2f0caf0dc06ea49277 Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Fri, 30 Aug 2024 15:23:26 +0530 Subject: [PATCH 123/275] Add FAQ about shared item organization --- docs/docs/photos/features/share.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/docs/photos/features/share.md b/docs/docs/photos/features/share.md index a1b9be376a..076b5546e1 100644 --- a/docs/docs/photos/features/share.md +++ b/docs/docs/photos/features/share.md @@ -57,6 +57,26 @@ If you wish to collect photos from folks who are not Ente, you can do so with our Links. Simply tick the box that says "Allow uploads", and anyone who has access to the link will be able to add photos to your album. +## Organization + +You can favorite items that have been shared with you, and organize them into +your own albums. + +When you perform these operations, Ente will create a hard copy of these items, +that you fully own. This means, these copied items will count against your +storage space. + +We understand there are use cases where this approach will consume extra space +(for eg. if you are organizing photos of a family member). We chose hard copies +as a first version to avoid complexities regarding the ownership of shared +items, in case the original owner were to delete it from their own library. + +We plan to tackle these complexities in the future, by copying a reference to +the item that was shared, instead of the actual file, so that your storage will +only get consumed if the original owner deletes it from their library. If this +sounds useful to you, please participate in [this +discussion](https://github.com/ente-io/ente/discussions/790). + ## Technical details More details, including technical aspect about how the sharing features were From 91646a809b1429cd16c4e1232dac2b618199813f Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Fri, 30 Aug 2024 12:07:06 +0200 Subject: [PATCH 124/275] [mob][photos] Actual logging in ML Computer --- mobile/lib/services/machine_learning/ml_computer.dart | 4 ++++ .../semantic_search/clip/clip_text_encoder.dart | 4 +++- mobile/lib/utils/image_ml_util.dart | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/mobile/lib/services/machine_learning/ml_computer.dart b/mobile/lib/services/machine_learning/ml_computer.dart index afbd511c62..8f27dfb3d4 100644 --- a/mobile/lib/services/machine_learning/ml_computer.dart +++ b/mobile/lib/services/machine_learning/ml_computer.dart @@ -4,7 +4,9 @@ import 'dart:isolate'; import 'dart:typed_data' show Uint8List; import "package:dart_ui_isolate/dart_ui_isolate.dart"; +import "package:flutter/foundation.dart" show kDebugMode; import "package:logging/logging.dart"; +import "package:photos/core/error-reporting/super_logging.dart"; import "package:photos/models/ml/face/box.dart"; import "package:photos/services/machine_learning/ml_model.dart"; import "package:photos/services/machine_learning/semantic_search/clip/clip_text_encoder.dart"; @@ -59,6 +61,8 @@ class MLComputer { @pragma('vm:entry-point') static void _isolateMain(SendPort mainSendPort) async { + Logger.root.level = kDebugMode ? Level.ALL : Level.INFO; + Logger.root.onRecord.listen(SuperLogging.onLogRecord); final receivePort = ReceivePort(); mainSendPort.send(receivePort.sendPort); diff --git a/mobile/lib/services/machine_learning/semantic_search/clip/clip_text_encoder.dart b/mobile/lib/services/machine_learning/semantic_search/clip/clip_text_encoder.dart index ff75a9028e..cd59fd1aa5 100644 --- a/mobile/lib/services/machine_learning/semantic_search/clip/clip_text_encoder.dart +++ b/mobile/lib/services/machine_learning/semantic_search/clip/clip_text_encoder.dart @@ -56,7 +56,9 @@ class ClipTextEncoder extends MlModel { final embedding = (outputs[0]?.value as List>)[0]; inputOrt.release(); runOptions.release(); - outputs.forEach((element) => element?.release()); + for (var element in outputs) { + element?.release(); + } normalizeEmbedding(embedding); return embedding; } diff --git a/mobile/lib/utils/image_ml_util.dart b/mobile/lib/utils/image_ml_util.dart index ee259dd8af..e8eb3e7312 100644 --- a/mobile/lib/utils/image_ml_util.dart +++ b/mobile/lib/utils/image_ml_util.dart @@ -150,8 +150,8 @@ Future> generateFaceThumbnailsUsingCanvas( await Future.wait(futureFaceThumbnails); return faceThumbnails; } catch (e) { - log('[ImageMlUtils] Error generating face thumbnails: $e'); - log('[ImageMlUtils] cropImage problematic input argument: ${faceBoxes[i]}'); + _logger.severe('Error generating face thumbnails: $e'); + _logger.severe('cropImage problematic input argument: ${faceBoxes[i]}'); return []; } } From df3ba8697736c1192f4976452f9cfca2ec00e36c Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Fri, 30 Aug 2024 14:27:18 +0530 Subject: [PATCH 125/275] Update build file --- mobile/ios/Podfile.lock | 2 +- mobile/pubspec.lock | 36 ++++++++++++++++++------------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/mobile/ios/Podfile.lock b/mobile/ios/Podfile.lock index c40e47d7ab..8ebcc2c8fe 100644 --- a/mobile/ios/Podfile.lock +++ b/mobile/ios/Podfile.lock @@ -472,7 +472,7 @@ SPEC CHECKSUMS: image_editor_common: d6f6644ae4a6de80481e89fe6d0a8c49e30b4b43 image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 in_app_purchase_storekit: 0e4b3c2e43ba1e1281f4f46dd71b0593ce529892 - integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 + integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4 libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009 local_auth_darwin: c7e464000a6a89e952235699e32b329457608d98 local_auth_ios: 5046a18c018dd973247a0564496c8898dbb5adf9 diff --git a/mobile/pubspec.lock b/mobile/pubspec.lock index 0223bc5236..7388ae92f2 100644 --- a/mobile/pubspec.lock +++ b/mobile/pubspec.lock @@ -1297,18 +1297,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.4" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.3" leak_tracker_testing: dependency: transitive description: @@ -1441,10 +1441,10 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.11.1" + version: "0.8.0" media_extension: dependency: "direct main" description: @@ -1529,10 +1529,10 @@ packages: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.12.0" mgrs_dart: dependency: transitive description: @@ -1901,10 +1901,10 @@ packages: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.4" plugin_platform_interface: dependency: transitive description: @@ -2410,26 +2410,26 @@ packages: dependency: "direct dev" description: name: test - sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e" + sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073" url: "https://pub.dev" source: hosted - version: "1.25.7" + version: "1.25.2" test_api: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.0" test_core: dependency: transitive description: name: test_core - sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696" + sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4" url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.6.0" timezone: dependency: transitive description: @@ -2708,10 +2708,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "14.2.1" volume_controller: dependency: transitive description: From e243a914e9ca081ee6263a5ec636618dcebf1549 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Fri, 30 Aug 2024 14:31:17 +0530 Subject: [PATCH 126/275] [mob] Show backup status on status_bar tap --- mobile/lib/ui/home/status_bar_widget.dart | 12 +++++++++++- .../settings/backup/backup_section_widget.dart | 16 ---------------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/mobile/lib/ui/home/status_bar_widget.dart b/mobile/lib/ui/home/status_bar_widget.dart index 8df1a90242..461a92a1c9 100644 --- a/mobile/lib/ui/home/status_bar_widget.dart +++ b/mobile/lib/ui/home/status_bar_widget.dart @@ -16,6 +16,7 @@ import 'package:photos/ui/account/verify_recovery_page.dart'; import 'package:photos/ui/components/home_header_widget.dart'; import 'package:photos/ui/components/notification_widget.dart'; import 'package:photos/ui/home/header_error_widget.dart'; +import "package:photos/ui/settings/backup/backup_status_screen.dart"; import 'package:photos/utils/navigation_util.dart'; const double kContainerHeight = 36; @@ -90,7 +91,16 @@ class _StatusBarWidgetState extends State { centerWidget: _showStatus ? _showErrorBanner ? const Text("ente", style: brandStyleMedium) - : const SyncStatusWidget() + : GestureDetector( + onTap: () { + routeToPage( + context, + const BackupStatusScreen(), + forceCustomPageRoute: true, + ).ignore(); + }, + child: const SyncStatusWidget(), + ) : const Text("ente", style: brandStyleMedium), ), _showErrorBanner diff --git a/mobile/lib/ui/settings/backup/backup_section_widget.dart b/mobile/lib/ui/settings/backup/backup_section_widget.dart index 56ef0e02f7..183b79b203 100644 --- a/mobile/lib/ui/settings/backup/backup_section_widget.dart +++ b/mobile/lib/ui/settings/backup/backup_section_widget.dart @@ -6,7 +6,6 @@ import 'package:photos/ui/components/expandable_menu_item_widget.dart'; import 'package:photos/ui/components/menu_item_widget/menu_item_widget.dart'; import 'package:photos/ui/settings/backup/backup_folder_selection_page.dart'; import 'package:photos/ui/settings/backup/backup_settings_screen.dart'; -import "package:photos/ui/settings/backup/backup_status_screen.dart"; import "package:photos/ui/settings/backup/free_space_options.dart"; import 'package:photos/ui/settings/common_settings.dart'; import 'package:photos/utils/navigation_util.dart'; @@ -48,21 +47,6 @@ class BackupSectionWidgetState extends State { }, ), sectionOptionSpacing, - MenuItemWidget( - captionedTextWidget: CaptionedTextWidget( - title: S.of(context).backupStatus, - ), - pressedColor: getEnteColorScheme(context).fillFaint, - trailingIcon: Icons.chevron_right_outlined, - trailingIconIsMuted: true, - onTap: () async { - await routeToPage( - context, - const BackupStatusScreen(), - ); - }, - ), - sectionOptionSpacing, MenuItemWidget( captionedTextWidget: CaptionedTextWidget( title: S.of(context).backupSettings, From 6da1f892ceefa5fbb1ecb1051536b99516ed93c0 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Fri, 30 Aug 2024 14:33:26 +0530 Subject: [PATCH 127/275] Bump version --- mobile/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index 1852638d13..9188a87ea9 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -12,7 +12,7 @@ description: ente photos application # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 0.9.31+931 +version: 0.9.32+932 publish_to: none environment: From 1b1f54feb0cf1472e933bf4915caa96d860cae2b Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Fri, 30 Aug 2024 12:22:58 +0200 Subject: [PATCH 128/275] [mob][photos] Actual logging in cluster isolate --- .../face_clustering_service.dart | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart b/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart index d37a8821f9..66fa306dcd 100644 --- a/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart +++ b/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart @@ -8,6 +8,7 @@ import "package:flutter/foundation.dart" show kDebugMode; import "package:logging/logging.dart"; import "package:ml_linalg/dtype.dart"; import "package:ml_linalg/vector.dart"; +import "package:photos/core/error-reporting/super_logging.dart"; import "package:photos/generated/protos/ente/common/vector.pb.dart"; import "package:photos/models/base/id.dart"; import "package:photos/services/machine_learning/face_ml/face_clustering/face_db_info_for_clustering.dart"; @@ -118,6 +119,8 @@ class FaceClusteringService { /// The main execution function of the isolate. static void _isolateMain(SendPort mainSendPort) async { + Logger.root.level = kDebugMode ? Level.ALL : Level.INFO; + Logger.root.onRecord.listen(SuperLogging.onLogRecord); final receivePort = ReceivePort(); mainSendPort.send(receivePort.sendPort); @@ -407,6 +410,8 @@ class FaceClusteringService { } } +final _logger = Logger("FaceLinearClustering"); + ClusteringResult _runLinearClustering(Map args) { // final input = args['input'] as Map; final input = args['input'] as Set; @@ -419,8 +424,8 @@ ClusteringResult _runLinearClustering(Map args) { final oldClusterSummaries = args['oldClusterSummaries'] as Map?; - log( - "[ClusterIsolate] ${DateTime.now()} Copied to isolate ${input.length} faces", + _logger.info( + "Copied to isolate ${input.length} faces", ); // Organize everything into a list of FaceInfo objects @@ -470,14 +475,11 @@ ClusteringResult _runLinearClustering(Map args) { } } final alreadyClusteredCount = facesWithClusterID.length; + final newToClusterCount = facesWithoutClusterID.length; final sortedFaceInfos = []; sortedFaceInfos.addAll(facesWithClusterID); sortedFaceInfos.addAll(facesWithoutClusterID); - log( - "[ClusterIsolate] ${DateTime.now()} Clustering ${facesWithoutClusterID.length} new faces without clusterId, and $alreadyClusteredCount faces with clusterId", - ); - // Make sure the first face has a clusterId final int totalFaces = sortedFaceInfos.length; int dynamicThresholdCount = 0; @@ -487,8 +489,8 @@ ClusteringResult _runLinearClustering(Map args) { } // Start actual clustering - log( - "[ClusterIsolate] ${DateTime.now()} Processing $totalFaces faces in total in this round ${offset != null ? "on top of ${offset + facesWithClusterID.length} earlier processed faces" : ""}", + _logger.info( + "[ClusterIsolate] ${DateTime.now()} Processing $totalFaces faces ($newToClusterCount new, $alreadyClusteredCount already done) in total in this round ${offset != null ? "on top of ${offset + facesWithClusterID.length} earlier processed faces" : ""}", ); // set current epoch time as clusterID String clusterID = newClusterID(); @@ -517,7 +519,7 @@ ClusteringResult _runLinearClustering(Map args) { thresholdValue = distanceThreshold; } if (i % 250 == 0) { - log("[ClusterIsolate] ${DateTime.now()} Processed ${offset != null ? i + offset : i} faces"); + _logger.info("Processed ${offset != null ? i + offset : i} faces"); } // WARNING: The loop below is now O(n^2) so be very careful with anything you put in there! for (int j = i - 1; j >= 0; j--) { @@ -536,8 +538,8 @@ ClusteringResult _runLinearClustering(Map args) { if (closestDistance < thresholdValue) { if (sortedFaceInfos[closestIdx].clusterId == null) { // Ideally this should never happen, but just in case log it - log( - " [ClusterIsolate] [WARNING] ${DateTime.now()} Found new cluster $clusterID", + _logger.severe( + "Found new cluster $clusterID, but closest face has no clusterId", ); clusterID = newClusterID(); sortedFaceInfos[closestIdx].clusterId = clusterID; @@ -568,12 +570,12 @@ ClusteringResult _runLinearClustering(Map args) { } stopwatchClustering.stop(); - log( - ' [ClusterIsolate] ${DateTime.now()} Clustering for ${sortedFaceInfos.length} embeddings executed in ${stopwatchClustering.elapsedMilliseconds}ms', + _logger.info( + 'Clustering for ${sortedFaceInfos.length} embeddings executed in ${stopwatchClustering.elapsedMilliseconds}ms', ); if (useDynamicThreshold) { - log( - "[ClusterIsolate] ${DateTime.now()} Dynamic thresholding: $dynamicThresholdCount faces had a low face score or low blur clarity", + _logger.info( + "Dynamic thresholding: $dynamicThresholdCount faces had a low face score or low blur clarity", ); } @@ -838,8 +840,8 @@ Map _updateClusterSummaries({ ); } } - log( - "[ClusterIsolate] ${DateTime.now()} Calculated cluster summaries in ${DateTime.now().difference(calcSummariesStart).inMilliseconds}ms", + _logger.info( + "Calculated cluster summaries in ${DateTime.now().difference(calcSummariesStart).inMilliseconds}ms", ); return newClusterSummaries; From 20c742d43dc0c07990e06f89f4dba603e1d967aa Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 30 Aug 2024 16:15:32 +0530 Subject: [PATCH 129/275] form 2 --- web/apps/photos/src/pages/cluster-debug.tsx | 101 +++++++++++++++----- 1 file changed, 79 insertions(+), 22 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 6f6e9d4c23..d5ca36db34 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -14,7 +14,16 @@ import { } from "@ente/shared/components/Container"; import EnteSpinner from "@ente/shared/components/EnteSpinner"; import BackButton from "@mui/icons-material/ArrowBackOutlined"; -import { Box, IconButton, Stack, styled, Typography } from "@mui/material"; +import { + Box, + Button, + IconButton, + MenuItem, + Stack, + styled, + TextField, + Typography, +} from "@mui/material"; import { useFormik } from "formik"; import { useRouter } from "next/router"; import { AppContext } from "pages/_app"; @@ -55,7 +64,7 @@ const Options: React.FC = () => { - {pt("Faces")} + {pt("Face Clusters")} ); @@ -79,7 +88,7 @@ interface ClusterListProps { } interface ClusteringOpts { - method: "hdbscan"; + method: "linear" | "hdbscan"; batchSize: number; joinThreshold: number; } @@ -131,7 +140,7 @@ const ClusterList: React.FC = ({ height, width }) => { const getItemSize = (index: number) => index === 0 - ? 100 + ? 270 : Array.isArray(items[index - 1]) ? listItemHeight : 36; @@ -151,7 +160,7 @@ const ClusterList: React.FC = ({ height, width }) => {
void cluster(opts)} + onCluster={cluster} />
); @@ -243,26 +252,68 @@ const ListItem = styled("div")` interface HeaderProps { clusterRes: ClusterDebugPageContents | undefined; - onCluster: (opts: ClusteringOpts) => void; + onCluster: (opts: ClusteringOpts) => Promise; } const Header: React.FC = ({ clusterRes, onCluster }) => { - const formik = useFormik({ - initialValues: { - method: "hdbscan", - batchSize: 2500, - joinThreshold: 0.7, - }, - onSubmit: onCluster, - }); + const { values, handleSubmit, handleChange, isSubmitting } = + useFormik({ + initialValues: { + method: "hdbscan", + joinThreshold: 0.7, + batchSize: 2500, + }, + onSubmit: onCluster, + }); - const clusterInfo = !clusterRes ? ( - - ) : ( + const form = ( +
+ + Parameters + + + {["hdbscan", "linear"].map((v) => ( + + {v} + + ))} + + + + + + + + +
+ ); + + const clusterInfo = clusterRes && ( -
- -
{`${clusterRes.clusters.length} clusters from ${clusterRes.clusteredCount} faces. ${clusterRes.unclusteredCount} unclustered faces.`} @@ -280,11 +331,17 @@ const Header: React.FC = ({ clusterRes, onCluster }) => {
); - return
{clusterInfo}
; + return ( +
+ {form} + {isSubmitting && } + {clusterInfo} +
+ ); }; const Loader = () => ( - + ); From 26cb81a7206a0d11956c13882df4b83e53a25ab3 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Fri, 30 Aug 2024 16:21:36 +0530 Subject: [PATCH 130/275] [mob][photos] almost fully functional toggle for toggling video loop --- mobile/lib/core/configuration.dart | 9 +++++ mobile/lib/ui/viewer/file/file_app_bar.dart | 34 +++++++++++++++++++ .../ui/viewer/file/video_widget_native.dart | 5 ++- 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/mobile/lib/core/configuration.dart b/mobile/lib/core/configuration.dart index 16a65d497f..70db6c3d96 100644 --- a/mobile/lib/core/configuration.dart +++ b/mobile/lib/core/configuration.dart @@ -71,6 +71,7 @@ class Configuration { "has_selected_all_folders_for_backup"; static const anonymousUserIDKey = "anonymous_user_id"; static const endPointKey = "endpoint"; + static const shouldLoopVideoKey = "should_loop_video"; static final _logger = Logger("Configuration"); String? _cachedToken; @@ -661,6 +662,14 @@ class Configuration { await _preferences.setBool(hasSelectedAllFoldersForBackupKey, value); } + Future setShouldLoopVideo(bool value) async { + await _preferences.setBool(shouldLoopVideoKey, value); + } + + bool shouldLoopVideo() { + return _preferences.getBool(shouldLoopVideoKey) ?? true; + } + Future _migrateSecurityStorageToFirstUnlock() async { final hasMigratedSecureStorage = _preferences.getBool(hasMigratedSecureStorageKey) ?? false; diff --git a/mobile/lib/ui/viewer/file/file_app_bar.dart b/mobile/lib/ui/viewer/file/file_app_bar.dart index 362868eeec..92d6d54239 100644 --- a/mobile/lib/ui/viewer/file/file_app_bar.dart +++ b/mobile/lib/ui/viewer/file/file_app_bar.dart @@ -6,6 +6,7 @@ import "package:flutter_svg/flutter_svg.dart"; import "package:local_auth/local_auth.dart"; import 'package:logging/logging.dart'; import 'package:media_extension/media_extension.dart'; +import "package:photos/core/configuration.dart"; import "package:photos/core/event_bus.dart"; import "package:photos/events/guest_view_event.dart"; import "package:photos/generated/l10n.dart"; @@ -55,6 +56,7 @@ class FileAppBarState extends State { final List _actions = []; late final StreamSubscription _guestViewEventSubscription; bool isGuestView = false; + bool shouldLoopVideo = Configuration.instance.shouldLoopVideo(); @override void didUpdateWidget(FileAppBar oldWidget) { @@ -315,6 +317,29 @@ class FileAppBarState extends State { ), ), ); + + if (widget.file.isVideo) { + items.add( + PopupMenuItem( + value: 7, + child: Row( + children: [ + Icon( + Icons.repeat_rounded, + color: Theme.of(context).iconTheme.color, + ), + const Padding( + padding: EdgeInsets.all(8), + ), + shouldLoopVideo + ? const Text("Video loop on") + : const Text("Video loop off"), + ], + ), + ), + ); + } + if (items.isNotEmpty) { _actions.add( PopupMenuButton( @@ -334,6 +359,8 @@ class FileAppBarState extends State { await _handleUnHideRequest(context); } else if (value == 6) { await _onTapGuestView(); + } else if (value == 7) { + _onToggleVideoLoop(); } }, ), @@ -342,6 +369,13 @@ class FileAppBarState extends State { return _actions; } + _onToggleVideoLoop() { + Configuration.instance.setShouldLoopVideo(!shouldLoopVideo); + setState(() { + shouldLoopVideo = !shouldLoopVideo; + }); + } + Future _handleHideRequest(BuildContext context) async { try { final hideResult = diff --git a/mobile/lib/ui/viewer/file/video_widget_native.dart b/mobile/lib/ui/viewer/file/video_widget_native.dart index 58e3367122..268bdec5e2 100644 --- a/mobile/lib/ui/viewer/file/video_widget_native.dart +++ b/mobile/lib/ui/viewer/file/video_widget_native.dart @@ -4,6 +4,7 @@ import "dart:io"; import "package:flutter/material.dart"; import "package:logging/logging.dart"; import "package:native_video_player/native_video_player.dart"; +import "package:photos/core/configuration.dart"; import "package:photos/core/constants.dart"; import "package:photos/core/event_bus.dart"; import "package:photos/events/guest_view_event.dart"; @@ -347,7 +348,9 @@ class _VideoWidgetNativeState extends State } void _onPlaybackEnded() { - _controller?.play(); + if (Configuration.instance.shouldLoopVideo()) { + _controller?.play(); + } } void _loadNetworkVideo() { From 598d5aab10fa23c1e79f6f4331d25875c02bb797 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 30 Aug 2024 16:44:58 +0530 Subject: [PATCH 131/275] propagate --- web/apps/photos/src/pages/cluster-debug.tsx | 60 +++----- .../new/photos/services/ml/cluster-new.ts | 22 +-- web/packages/new/photos/services/ml/index.ts | 145 +++++------------- web/packages/new/photos/services/ml/worker.ts | 6 +- 4 files changed, 75 insertions(+), 158 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index d5ca36db34..7f84b0c5f2 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -2,11 +2,12 @@ import { SelectionBar } from "@/base/components/Navbar"; import { pt } from "@/base/i18n"; import { faceCrop, + wipClusterDebugPageContents, type ClusterDebugPageContents, - type ClusterPreviewFaceWF, + type ClusterPreviewFaceWithFile, } from "@/new/photos/services/ml"; +import { type ClusteringOpts } from "@/new/photos/services/ml/cluster-new"; import { faceDirection } from "@/new/photos/services/ml/face"; -import { wait } from "@/utils/promise"; import { FlexWrapper, FluidContainer, @@ -87,12 +88,6 @@ interface ClusterListProps { width: number; } -interface ClusteringOpts { - method: "linear" | "hdbscan"; - batchSize: number; - joinThreshold: number; -} - const ClusterList: React.FC = ({ height, width }) => { const { startLoading, finishLoading } = useContext(AppContext); @@ -105,18 +100,7 @@ const ClusterList: React.FC = ({ height, width }) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const cluster = async (opts: ClusteringOpts) => { startLoading(); - // setClusterRes(await wipClusterDebugPageContents()); - console.log(opts); - await wait(5000); - setClusterRes({ - clusteredCount: 1, - unclusteredCount: 2, - clusterPreviewWFs: Array(100) - .fill(0) - .map(() => ({ clusterSize: 0, faces: [] })), - clusters: [], - clusterIDForFaceID: new Map(), - }); + setClusterRes(await wipClusterDebugPageContents(opts)); finishLoading(); }; @@ -136,8 +120,6 @@ const ClusterList: React.FC = ({ height, width }) => { listRef.current?.resetAfterIndex(0); }, [items]); - const clusterIDForFaceID = clusterRes?.clusterIDForFaceID; - const getItemSize = (index: number) => index === 0 ? 270 @@ -177,10 +159,10 @@ const ClusterList: React.FC = ({ height, width }) => { {`cluster size ${item.toFixed(2)}`} ) : ( - item.map((faceWF, i) => ( + item.map((f, i) => ( )) )} @@ -192,17 +174,17 @@ const ClusterList: React.FC = ({ height, width }) => { ); }; -type Item = number | ClusterPreviewFaceWF[]; +type Item = number | ClusterPreviewFaceWithFile[]; const itemsFromClusterRes = ( clusterRes: ClusterDebugPageContents, columns: number, ) => { - const { clusterPreviewWFs } = clusterRes; + const { clusterPreviewsWithFile } = clusterRes; const result: Item[] = []; - for (let index = 0; index < clusterPreviewWFs.length; index++) { - const { clusterSize, faces } = clusterPreviewWFs[index]; + for (let index = 0; index < clusterPreviewsWithFile.length; index++) { + const { clusterSize, faces } = clusterPreviewsWithFile[index]; result.push(clusterSize); let lastIndex = 0; while (lastIndex < faces.length) { @@ -315,7 +297,7 @@ const Header: React.FC = ({ clusterRes, onCluster }) => { const clusterInfo = clusterRes && ( - {`${clusterRes.clusters.length} clusters from ${clusterRes.clusteredCount} faces. ${clusterRes.unclusteredCount} unclustered faces.`} + {`${clusterRes.clusters.length} clusters from ${clusterRes.clusteredFaceCount} faces. ${clusterRes.unclusteredFaceCount} unclustered faces.`} Showing only top 30 and bottom 30 clusters. @@ -326,7 +308,10 @@ const Header: React.FC = ({ clusterRes, onCluster }) => { Below each face is its{" "} - blur - score - cosineSimilarity - direction + blur - score - cosineSimilarity - direction. + + + Faces added to the cluster as a result of merging are outlined. ); @@ -347,12 +332,11 @@ const Loader = () => ( ); interface FaceItemProps { - faceWF: ClusterPreviewFaceWF; - clusterIDForFaceID: Map | undefined; + faceWithFile: ClusterPreviewFaceWithFile; } -const FaceItem: React.FC = ({ faceWF, clusterIDForFaceID }) => { - const { face, enteFile, cosineSimilarity } = faceWF; +const FaceItem: React.FC = ({ faceWithFile }) => { + const { face, enteFile, cosineSimilarity, wasMerged } = faceWithFile; const { faceID } = face; const [objectURL, setObjectURL] = useState(); @@ -377,7 +361,7 @@ const FaceItem: React.FC = ({ faceWF, clusterIDForFaceID }) => { return ( @@ -413,9 +397,3 @@ const FaceChip = styled(Box)` width: 120px; height: 120px; `; - -const outlineForCluster = (clusterID: string | undefined) => - clusterID ? `1px solid oklch(0.8 0.2 ${hForID(clusterID)})` : undefined; - -const hForID = (id: string) => - ([...id].reduce((s, c) => s + c.charCodeAt(0), 0) % 10) * 36; diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index d6e1dc505a..8bfb00b164 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -113,15 +113,10 @@ export interface CGroup { displayFaceID: string | undefined; } -// TODO-Cluster -export interface FaceNeighbours { - face: Face; - neighbours: FaceNeighbour[]; -} - -interface FaceNeighbour { - face: Face; - cosineSimilarity: number; +export interface ClusteringOpts { + method: "linear" | "hdbscan"; + batchSize: number; + joinThreshold: number; } export interface ClusterPreview { @@ -129,9 +124,10 @@ export interface ClusterPreview { faces: ClusterPreviewFace[]; } -interface ClusterPreviewFace { +export interface ClusterPreviewFace { face: Face; cosineSimilarity: number; + wasMerged: boolean; } /** @@ -348,7 +344,11 @@ function* enumerateFaces(faceIndices: FaceIndex[]) { } } -export const clusterFacesHdb = (faceIndexes: FaceIndex[]) => { +export const clusterFacesHdb = ( + faceIndexes: FaceIndex[], + opts: ClusteringOpts, +) => { + const { batch } = opts; const t = Date.now(); // A flattened array of faces. diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 4248c295f0..c5ff83c2ef 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -20,7 +20,11 @@ import { getAllLocalFiles } from "../files"; import { getRemoteFlag, updateRemoteFlag } from "../remote-store"; import type { SearchPerson } from "../search/types"; import type { UploadItem } from "../upload/types"; -import { type CGroup, type FaceCluster } from "./cluster-new"; +import { + type ClusteringOpts, + type ClusterPreviewFace, + type FaceCluster, +} from "./cluster-new"; import { regenerateFaceCrops } from "./crop"; import { clearMLDB, faceIndex, indexableAndIndexedCounts } from "./db"; import type { Face } from "./face"; @@ -344,42 +348,30 @@ export const wipSearchPersons = async () => { return _wip_searchPersons ?? []; }; -export interface FaceFileNeighbours { - face: Face; - neighbours: FaceFileNeighbour[]; -} - -export interface FaceFileNeighbour { - face: Face; - enteFile: EnteFile; - cosineSimilarity: number; -} - -// "with file" -export interface ClusterPreviewWF { +export interface ClusterPreviewWithFile { clusterSize: number; - faces: ClusterPreviewFaceWF[]; + faces: ClusterPreviewFaceWithFile[]; } -export interface ClusterPreviewFaceWF { - face: Face; +export type ClusterPreviewFaceWithFile = ClusterPreviewFace & { enteFile: EnteFile; - cosineSimilarity: number; -} +}; export interface ClusterDebugPageContents { - clusteredCount: number; - unclusteredCount: number; - // faceFNs: FaceFileNeighbours[]; - clusterPreviewWFs: ClusterPreviewWF[]; + clusteredFaceCount: number; + unclusteredFaceCount: number; clusters: FaceCluster[]; - clusterIDForFaceID: Map; + clusterPreviewsWithFile: ClusterPreviewWithFile[]; + unclusteredFacesWithFile: { + face: Face; + enteFile: EnteFile; + }; } -export const wipClusterDebugPageContents = async (): Promise< - ClusterDebugPageContents | undefined -> => { - if (!(await wipClusterEnable())) return undefined; +export const wipClusterDebugPageContents = async ( + opts: ClusteringOpts, +): Promise => { + if (!(await wipClusterEnable())) throw new Error("Not implemented"); log.info("clustering"); _wip_isClustering = true; @@ -388,38 +380,33 @@ export const wipClusterDebugPageContents = async (): Promise< // const { faceAndNeigbours, clusters, cgroups } = await clusterFaces( const { - clusteredCount, - unclusteredCount, + clusteredFaceCount, + unclusteredFaceCount, clusterPreviews, clusters, cgroups, - clusterIDForFaceID, - } = await worker().then((w) => w.clusterFacesHdb()); - - // const searchPersons = await convertToSearchPersons(clusters, cgroups); + unclusteredFaces, + } = await worker().then((w) => w.clusterFacesHdb(opts)); const localFiles = await getAllLocalFiles(); const localFileByID = new Map(localFiles.map((f) => [f.id, f])); const fileForFace = ({ faceID }: Face) => ensure(localFileByID.get(ensure(fileIDFromFaceID(faceID)))); - // const faceFNs = faceAndNeigbours.map( - // ({ topFace: face, faces: neighbours }) => ({ - // face, - // neighbours: neighbours.map(({ face, cosineSimilarity }) => ({ - // face, - // enteFile: fileForFace(face), - // cosineSimilarity, - // })), - // }), - // ); - const clusterPreviewWFs = clusterPreviews.map(({ clusterSize, faces }) => ({ - clusterSize, - faces: faces.map(({ face, cosineSimilarity }) => ({ - face, - enteFile: fileForFace(face), - cosineSimilarity, - })), + const clusterPreviewsWithFile = clusterPreviews.map( + ({ clusterSize, faces }) => ({ + clusterSize, + faces: faces.map(({ face, cosineSimilarity }) => ({ + face, + enteFile: fileForFace(face), + cosineSimilarity, + })), + }), + ); + + const unclusteredFacesWithFile = unclusteredFaces.map((face) => ({ + face, + enteFile: fileForFace(face), })); const clusterByID = new Map(clusters.map((c) => [c.id, c])); @@ -453,62 +440,14 @@ export const wipClusterDebugPageContents = async (): Promise< triggerStatusUpdate(); return { - clusteredCount, - unclusteredCount, - clusterPreviewWFs, + clusteredFaceCount, + unclusteredFaceCount, clusters, - clusterIDForFaceID, + clusterPreviewsWithFile, + unclusteredFacesWithFile, }; }; -export const wipCluster = () => void wipClusterDebugPageContents(); - -// TODO-Cluster remove me -export const convertToSearchPersons = async ( - clusters: FaceCluster[], - cgroups: CGroup[], -) => { - const clusterByID = new Map(clusters.map((c) => [c.id, c])); - - const localFiles = await getAllLocalFiles(); - const localFileByID = new Map(localFiles.map((f) => [f.id, f])); - - const result: SearchPerson[] = []; - for (const cgroup of cgroups) { - const displayFaceID = cgroup.displayFaceID; - if (!displayFaceID) { - // TODO-Cluster - assertionFailed(`cgroup ${cgroup.id} without displayFaceID`); - continue; - } - - const displayFaceFileID = fileIDFromFaceID(displayFaceID); - if (!displayFaceFileID) continue; - - const displayFaceFile = localFileByID.get(displayFaceFileID); - if (!displayFaceFile) { - assertionFailed(`Face ID ${displayFaceFileID} without local file`); - continue; - } - - const fileIDs = cgroup.clusterIDs - .map((id) => clusterByID.get(id)) - .flatMap((cluster) => cluster?.faceIDs ?? []) - .map((faceID) => fileIDFromFaceID(faceID)) - .filter((fileID) => fileID !== undefined); - - result.push({ - id: cgroup.id, - name: cgroup.name, - files: [...new Set(fileIDs)], - displayFaceID, - displayFaceFile, - }); - } - - return result.sort((a, b) => b.files.length - a.files.length); -}; - export type MLStatus = | { phase: "disabled" /* The ML remote flag is off */ } | { diff --git a/web/packages/new/photos/services/ml/worker.ts b/web/packages/new/photos/services/ml/worker.ts index e4a3e5ecab..6eff182347 100644 --- a/web/packages/new/photos/services/ml/worker.ts +++ b/web/packages/new/photos/services/ml/worker.ts @@ -24,7 +24,7 @@ import { indexCLIP, type CLIPIndex, } from "./clip"; -import { clusterFacesHdb } from "./cluster-new"; +import { clusterFacesHdb, type ClusteringOpts } from "./cluster-new"; import { saveFaceCrops } from "./crop"; import { faceIndexes, @@ -276,8 +276,8 @@ export class MLWorker { } // TODO-Cluster - async clusterFacesHdb() { - return clusterFacesHdb(await faceIndexes()); + async clusterFacesHdb(opts: ClusteringOpts) { + return clusterFacesHdb(await faceIndexes(), opts); } } From f8593255ac2403fed2bc8352e83cfebb099e7584 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Fri, 30 Aug 2024 16:59:26 +0530 Subject: [PATCH 132/275] [mob][photos] Fix most of the seekbar issues when turning off looping videos --- .../file/native_video_player_controls/seek_bar.dart | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mobile/lib/ui/viewer/file/native_video_player_controls/seek_bar.dart b/mobile/lib/ui/viewer/file/native_video_player_controls/seek_bar.dart index 015e6eb5ef..f57d772566 100644 --- a/mobile/lib/ui/viewer/file/native_video_player_controls/seek_bar.dart +++ b/mobile/lib/ui/viewer/file/native_video_player_controls/seek_bar.dart @@ -2,6 +2,7 @@ import "dart:async"; import "package:flutter/material.dart"; import "package:native_video_player/native_video_player.dart"; +import "package:photos/core/configuration.dart"; import "package:photos/theme/colors.dart"; import "package:photos/theme/ente_theme.dart"; import "package:photos/utils/debouncer.dart"; @@ -136,16 +137,21 @@ class _SeekBarState extends State with SingleTickerProviderStateMixin { } void _onPlaybackPositionChanged() async { - if (widget.controller.playbackInfo?.status == PlaybackStatus.paused) { + if (widget.controller.playbackInfo?.status == PlaybackStatus.paused || + (widget.controller.playbackInfo?.status == PlaybackStatus.stopped && + widget.controller.playbackInfo?.positionFraction != 0)) { return; } final target = widget.controller.playbackInfo?.positionFraction ?? 0; - //To immediately set the position to 0 when the ends when playing in loop + //To immediately set the position to 0 when the video ends if (_prevPositionFraction == 1.0 && target == 0.0) { setState(() { _animationController.value = 0; }); + if (!Configuration.instance.shouldLoopVideo()) { + return; + } } //There is a slight delay (around 350 ms) for the event being listened to From 48e00a0ecca6bb531e78816a89e167facc92ba5a Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 30 Aug 2024 17:05:16 +0530 Subject: [PATCH 133/275] Linear --- .../new/photos/services/ml/cluster-hdb.ts | 35 + .../new/photos/services/ml/cluster-new.ts | 603 ------------------ .../new/photos/services/ml/cluster.ts | 522 ++++++++++++++- web/packages/new/photos/services/ml/db.ts | 2 +- web/packages/new/photos/services/ml/index.ts | 4 +- web/packages/new/photos/services/ml/worker.ts | 6 +- .../new/photos/services/user-entity.ts | 2 +- 7 files changed, 539 insertions(+), 635 deletions(-) create mode 100644 web/packages/new/photos/services/ml/cluster-hdb.ts delete mode 100644 web/packages/new/photos/services/ml/cluster-new.ts diff --git a/web/packages/new/photos/services/ml/cluster-hdb.ts b/web/packages/new/photos/services/ml/cluster-hdb.ts new file mode 100644 index 0000000000..3ecda4b5bc --- /dev/null +++ b/web/packages/new/photos/services/ml/cluster-hdb.ts @@ -0,0 +1,35 @@ +import { Hdbscan, type DebugInfo } from "hdbscan"; + +/** + * Each "cluster" is a list of indexes of the embeddings belonging to that + * particular cluster. + */ +export type EmbeddingCluster = number[]; + +export interface ClusterHdbscanResult { + clusters: EmbeddingCluster[]; + noise: number[]; + debugInfo?: DebugInfo; +} + +/** + * Cluster the given {@link embeddings} using hdbscan. + */ +export const clusterHdbscan = ( + embeddings: number[][], +): ClusterHdbscanResult => { + const hdbscan = new Hdbscan({ + input: embeddings, + minClusterSize: 3, + minSamples: 5, + clusterSelectionEpsilon: 0.6, + clusterSelectionMethod: "leaf", + debug: false, + }); + + return { + clusters: hdbscan.getClusters(), + noise: hdbscan.getNoise(), + debugInfo: hdbscan.getDebugInfo(), + }; +}; diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts deleted file mode 100644 index 8bfb00b164..0000000000 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ /dev/null @@ -1,603 +0,0 @@ -import { newNonSecureID } from "@/base/id-worker"; -import log from "@/base/log"; -import { ensure } from "@/utils/ensure"; -import { clusterFacesHdbscan } from "./cluster"; -import { clusterGroups, faceClusters } from "./db"; -import type { Face, FaceIndex } from "./face"; -import { dotProduct } from "./math"; - -/** - * A face cluster is an set of faces. - * - * Each cluster has an id so that a {@link CGroup} can refer to it. - * - * The cluster is not directly synced to remote. Only clusters that the user - * interacts with get synced to remote, as part of a {@link CGroup}. - */ -export interface FaceCluster { - /** - * A nanoid for this cluster. - */ - id: string; - /** - * An unordered set of ids of the faces that belong to this cluster. - * - * For ergonomics of transportation and persistence this is an array, but it - * should conceptually be thought of as a set. - */ - faceIDs: string[]; -} - -/** - * A cgroup ("cluster group") is a group of clusters (possibly containing a - * single cluster) that the user has interacted with. - * - * Interactions include hiding, merging and giving a name and/or a cover photo. - * - * The most frequent interaction is naming a {@link FaceCluster}, which promotes - * it to a become a {@link CGroup}. The promotion comes with the ability to be - * synced with remote (as a "cgroup" user entity). - * - * There after, the user may attach more clusters to the same {@link CGroup}. - * - * > A named cluster group can be thought of as a "person", though this is not - * > necessarily an accurate characterization. e.g. there can be a named cluster - * > group that contains face clusters of pets. - * - * The other form of interaction is hiding. The user may hide a single (unnamed) - * cluster, or they may hide an named {@link CGroup}. In both cases, we promote - * the cluster to a CGroup if needed so that their request to hide gets synced. - * - * While in our local representation we separately maintain clusters and link to - * them from within CGroups by their clusterID, in the remote representation - * clusters themselves don't get synced. Instead, the "cgroup" entities synced - * with remote contain the clusters within themselves. So a group that gets - * synced with remote looks something like: - * - * { id, name, clusters: [{ clusterID, faceIDs }] } - * - */ -export interface CGroup { - /** - * A nanoid for this cluster group. - * - * This is the ID of the "cgroup" user entity (the envelope), and it is not - * contained as part of the group entity payload itself. - */ - id: string; - /** - * A name assigned by the user to this cluster group. - * - * The client should handle both empty strings and undefined as indicating a - * cgroup without a name. When the client needs to set this to an "empty" - * value, which happens when hiding an unnamed cluster, it should it to an - * empty string. That is, expect `"" | undefined`, but set `""`. - */ - name: string | undefined; - /** - * An unordered set of ids of the clusters that belong to this group. - * - * For ergonomics of transportation and persistence this is an array, but it - * should conceptually be thought of as a set. - */ - clusterIDs: string[]; - /** - * True if this cluster group should be hidden. - * - * The user can hide both named cluster groups and single unnamed clusters. - * If the user hides a single cluster that was offered as a suggestion to - * them on a client, the client will create a new unnamed cgroup containing - * it, and set its hidden flag to sync it with remote (so that other clients - * can also stop showing this cluster). - */ - isHidden: boolean; - /** - * The ID of the face that should be used as the cover photo for this - * cluster group (if the user has set one). - * - * This is similar to the [@link displayFaceID}, the difference being: - * - * - {@link avatarFaceID} is the face selected by the user. - * - * - {@link displayFaceID} is the automatic placeholder, and only comes - * into effect if the user has not explicitly selected a face. - */ - avatarFaceID: string | undefined; - /** - * Locally determined ID of the "best" face that should be used as the - * display face, to represent this cluster group in the UI. - * - * This property is not synced with remote. For more details, see - * {@link avatarFaceID}. - */ - displayFaceID: string | undefined; -} - -export interface ClusteringOpts { - method: "linear" | "hdbscan"; - batchSize: number; - joinThreshold: number; -} - -export interface ClusterPreview { - clusterSize: number; - faces: ClusterPreviewFace[]; -} - -export interface ClusterPreviewFace { - face: Face; - cosineSimilarity: number; - wasMerged: boolean; -} - -/** - * Cluster faces into groups. - * - * [Note: Face clustering algorithm] - * - * A cgroup (cluster group) consists of clusters, each of which itself is a set - * of faces. - * - * cgroup << cluster << face - * - * The clusters are generated locally by clients using the following algorithm: - * - * 1. clusters = [] initially, or fetched from remote. - * - * 2. For each face, find its nearest neighbour in the embedding space. - * - * 3. If no such neighbour is found within our threshold, create a new cluster. - * - * 4. Otherwise assign this face to the same cluster as its nearest neighbour. - * - * This user can then tweak the output of the algorithm by performing the - * following actions to the list of clusters that they can see: - * - * - They can provide a name for a cluster ("name a person"). This upgrades a - * cluster into a "cgroup", which is an entity that gets synced via remote - * to the user's other clients. - * - * - They can attach more clusters to a cgroup ("merge clusters") - * - * - They can remove a cluster from a cgroup ("break clusters"). - * - * After clustering, we also do some routine cleanup. Faces belonging to files - * that have been deleted (including those in Trash) should be pruned off. - * - * We should not make strict assumptions about the clusters we get from remote. - * In particular, the same face ID can be in different clusters. In such cases - * we should assign it arbitrarily assign it to the last cluster we find it in. - * Such leeway is intentionally provided to allow clients some slack in how they - * implement the sync without needing to make an blocking API request for every - * user interaction. - */ -export const clusterFaces = async (faceIndexes: FaceIndex[]) => { - const t = Date.now(); - - // A flattened array of faces. - // TODO-Cluster note the 2k slice - const faces = [...enumerateFaces(faceIndexes)].slice(0, 2000); - - // Start with the clusters we already have (either from a previous indexing, - // or fetched from remote). - const clusters = await faceClusters(); - - // For fast reverse lookup - map from cluster ids to their index in the - // clusters array. - const clusterIndexForClusterID = new Map(clusters.map((c, i) => [c.id, i])); - - // For fast reverse lookup - map from face ids to the id of the cluster to - // which they belong. - const clusterIDForFaceID = new Map( - clusters.flatMap((c) => c.faceIDs.map((id) => [id, c.id] as const)), - ); - - // A function to generate new cluster IDs. - const newClusterID = () => newNonSecureID("cluster_"); - - const faceAndNeigbours: FaceNeighbours[] = []; - - // For each face, - for (const [i, fi] of faces.entries()) { - // If the face is already part of a cluster, then skip it. - if (clusterIDForFaceID.get(fi.faceID)) continue; - - // Find the nearest neighbour from among all the other faces. - let nn: Face | undefined; - let nnCosineSimilarity = 0; - let neighbours: FaceNeighbour[] = []; - for (let j = 0; j < faces.length; j++) { - // ! This is an O(n^2) loop, be careful when adding more code here. - - // TODO-Cluster Commenting this here and moving it downward - // // Skip ourselves. - // if (i == j) continue; - - // Can't find a way of avoiding the null assertion here. - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const fj = faces[j]!; - - // The vectors are already normalized, so we can directly use their - // dot product as their cosine similarity. - const csim = dotProduct(fi.embedding, fj.embedding); - - // TODO-Cluster Delete me and uncomment the check above - // Skip ourselves. - if (i == j) { - neighbours.push({ face: fj, cosineSimilarity: csim }); - continue; - } - - const threshold = fi.blur < 100 || fj.blur < 100 ? 0.7 : 0.6; - if (csim > threshold && csim > nnCosineSimilarity) { - nn = fj; - nnCosineSimilarity = csim; - } - - neighbours.push({ face: fj, cosineSimilarity: csim }); - } - - neighbours = neighbours.sort( - (a, b) => b.cosineSimilarity - a.cosineSimilarity, - ); - faceAndNeigbours.push({ face: fi, neighbours }); - - const { faceID } = fi; - - if (nn) { - // Found a neighbour near enough. - const nnFaceID = nn.faceID; - - // Find the cluster the nearest neighbour belongs to, if any. - const nnClusterID = clusterIDForFaceID.get(nn.faceID); - - if (nnClusterID) { - // If the neighbour is already part of a cluster, also add - // ourselves to that cluster. - - const nnClusterIndex = ensure( - clusterIndexForClusterID.get(nnClusterID), - ); - clusters[nnClusterIndex]?.faceIDs.push(faceID); - clusterIDForFaceID.set(faceID, nnClusterID); - } else { - // Otherwise create a new cluster with us and our nearest - // neighbour. - - const cluster = { - id: newClusterID(), - faceIDs: [faceID, nnFaceID], - }; - clusterIndexForClusterID.set(cluster.id, clusters.length); - clusterIDForFaceID.set(faceID, cluster.id); - clusterIDForFaceID.set(nnFaceID, cluster.id); - clusters.push(cluster); - } - } else { - // We didn't find a neighbour within the threshold. Create a new - // cluster with only this face. - - const cluster = { id: newClusterID(), faceIDs: [faceID] }; - clusterIndexForClusterID.set(cluster.id, clusters.length); - clusterIDForFaceID.set(faceID, cluster.id); - clusters.push(cluster); - } - } - - // Prune too small clusters. - const validClusters = clusters.filter(({ faceIDs }) => faceIDs.length > 1); - - let cgroups = await clusterGroups(); - - // TODO-Cluster - Currently we're not syncing with remote or saving anything - // locally, so cgroups will be empty. Create a temporary (unsaved, unsynced) - // cgroup, one per cluster. - cgroups = cgroups.concat( - validClusters.map((c) => ({ - id: c.id, - name: undefined, - clusterIDs: [c.id], - isHidden: false, - avatarFaceID: undefined, - displayFaceID: undefined, - })), - ); - - // For each cluster group, use the highest scoring face in any of its - // clusters as its display face. - const faceForFaceID = new Map(faces.map((f) => [f.faceID, f])); - for (const cgroup of cgroups) { - cgroup.displayFaceID = cgroup.clusterIDs - .map((clusterID) => clusterIndexForClusterID.get(clusterID)) - .filter((i) => i !== undefined) /* 0 is a valid index */ - .flatMap((i) => clusters[i]?.faceIDs ?? []) - .map((faceID) => faceForFaceID.get(faceID)) - .filter((face) => !!face) - .reduce((max, face) => - max.score > face.score ? max : face, - ).faceID; - } - - log.info("ml/cluster", { - faces, - validClusters, - clusterIndexForClusterID: Object.fromEntries(clusterIndexForClusterID), - clusterIDForFaceID: Object.fromEntries(clusterIDForFaceID), - cgroups, - }); - log.info( - `Clustered ${faces.length} faces into ${validClusters.length} clusters (${Date.now() - t} ms)`, - ); - - return { faces, clusters: validClusters, cgroups, faceAndNeigbours }; -}; - -/** - * A generator function that returns a stream of {faceID, embedding} values, - * flattening all the the faces present in the given {@link faceIndices}. - */ -function* enumerateFaces(faceIndices: FaceIndex[]) { - for (const fi of faceIndices) { - for (const f of fi.faces) { - yield f; - } - } -} - -export const clusterFacesHdb = ( - faceIndexes: FaceIndex[], - opts: ClusteringOpts, -) => { - const { batch } = opts; - const t = Date.now(); - - // A flattened array of faces. - // TODO-Cluster ad-hoc filtering and slicing - const faces0 = [...enumerateFaces(faceIndexes)].filter((f) => f.blur > 99); - // .slice(0, 6000); - // TODO-Cluster testing code, can be removed once done - const faces = Array(1) - .fill(0) - .flatMap(() => faces0); - - // For fast reverse lookup - map from face ids to the face. - const faceForFaceID = new Map(faces.map((f) => [f.faceID, f])); - - const faceEmbeddings = faces.map(({ embedding }) => embedding); - - // For fast reverse lookup - map from cluster ids to their index in the - // clusters array. - const clusterIndexForClusterID = new Map(); - - // For fast reverse lookup - map from the id of a face to the id of the - // cluster to which it belongs. - const clusterIDForFaceID = new Map(); - - // A function to chain two reverse lookup. - const firstFaceOfCluster = (cluster: FaceCluster) => - ensure(faceForFaceID.get(ensure(cluster.faceIDs[0]))); - - // A function to generate new cluster IDs. - const newClusterID = () => newNonSecureID("cluster_"); - - // The resultant clusters. - // TODO-Cluster Later on, instead of starting from a blank slate, this will - // be list of existing clusters we fetch from remote. - const clusters: FaceCluster[] = []; - - // Process the faces in batches. The faces are already sorted by file ID, - // which is a monotonically increasing integer, so we will also have some - // temporal locality. - // - // The number 2500 was derived by ad-hoc observations and takes a few - // seconds. On a particular test dataset and a particular machine, - // clustering 1k took ~2 seconds, 10k took ~2 mins, while 20k took ~8 mins. - // Memory usage was constant in all these cases. - // - // At around 100k faces, the clustering starts taking hours, and we start - // running into stack overflows. The stack overflows can perhaps be avoided - // by restructuring the code, but hours of uninterruptible work is anyways - // not feasible. - - const batchSize = 2500; - for (let i = 0; i < faceEmbeddings.length; i += batchSize) { - const it = Date.now(); - const embeddings = faceEmbeddings.slice(i, i + batchSize); - const { clusters: hdbClusters } = clusterFacesHdbscan(embeddings); - - log.info( - `hdbscan produced ${hdbClusters.length} clusters from ${embeddings.length} faces (${Date.now() - it} ms)`, - ); - - // Merge the new clusters we got from hdbscan into the existing clusters - // if they are "near" them (using some heuristic). - // - // We need to ensure we don't change any of the existing cluster IDs, - // since these might be existing clusters we got from remote. - - for (const hdbCluster of hdbClusters) { - // Find the existing cluster whose (arbitrarily chosen) first face - // is the nearest neighbour of the (arbitrarily chosen) first face - // of the cluster produced by hdbscan. - - const newFace = ensure(faces[i + ensure(hdbCluster[0])]); - - let nnCluster: FaceCluster | undefined; - let nnCosineSimilarity = 0; - for (const existingCluster of clusters) { - const existingFace = firstFaceOfCluster(existingCluster); - - // The vectors are already normalized, so we can directly use their - // dot product as their cosine similarity. - const csim = dotProduct( - existingFace.embedding, - newFace.embedding, - ); - - // Use a higher cosine similarity threshold if either of the two - // faces are blurry. - const threshold = - existingFace.blur < 200 || newFace.blur < 200 ? 0.9 : 0.7; - if (csim > threshold && csim > nnCosineSimilarity) { - nnCluster = existingCluster; - nnCosineSimilarity = csim; - } - } - - if (nnCluster) { - // If we found an existing cluster that is near enough, - // sublimate the cluster produced by hdbscan into that cluster. - for (const j of hdbCluster) { - const { faceID } = ensure(faces[i + j]); - nnCluster.faceIDs.push(faceID); - clusterIDForFaceID.set(faceID, nnCluster.id); - } - } else { - // Otherwise make a new cluster from the cluster produced by - // hdbscan. - const clusterID = newClusterID(); - const faceIDs: string[] = []; - for (const j of hdbCluster) { - const { faceID } = ensure(faces[i + j]); - faceIDs.push(faceID); - clusterIDForFaceID.set(faceID, clusterID); - } - clusterIndexForClusterID.set(clusterID, clusters.length); - clusters.push({ id: clusterID, faceIDs }); - } - } - } - - // Convert into the data structure we're using to debug/visualize. - // const faceAndNeigbours: FaceNeighbours[] = []; - // const topFaces = faces.sort((a, b) => b.score - a.score).slice(0, 30); - // for (const fi of topFaces) { - // let neighbours: FaceNeighbour[] = []; - // for (const fj of faces) { - // // The vectors are already normalized, so we can directly use their - // // dot product as their cosine similarity. - // const csim = dotProduct(fi.embedding, fj.embedding); - // neighbours.push({ face: fj, cosineSimilarity: csim }); - // } - - // neighbours = neighbours - // .sort((a, b) => b.cosineSimilarity - a.cosineSimilarity) - // .slice(0, 30); - - // faceAndNeigbours.push({ face: fi, neighbours }); - // } - - // Convert into the data structure we're using to debug/visualize. - // - // > Showing only top 30 and bottom 30 clusters (and only up to 50 faces in - // > each, sorted by cosine distance to highest scoring face in the - // > cluster). - - const sortedClusters = clusters.sort( - (a, b) => b.faceIDs.length - a.faceIDs.length, - ); - const debugClusters = - sortedClusters.length < 60 - ? sortedClusters - : sortedClusters.slice(0, 30).concat(sortedClusters.slice(-30)); - const clusterPreviews: ClusterPreview[] = []; - for (const cluster of debugClusters) { - const faces = cluster.faceIDs.map((id) => - ensure(faceForFaceID.get(id)), - ); - const topFace = faces.reduce((max, face) => - max.score > face.score ? max : face, - ); - const previewFaces: ClusterPreviewFace[] = []; - for (const face of faces) { - const csim = dotProduct(topFace.embedding, face.embedding); - previewFaces.push({ face, cosineSimilarity: csim }); - } - clusterPreviews.push({ - clusterSize: cluster.faceIDs.length, - faces: previewFaces - .sort((a, b) => b.cosineSimilarity - a.cosineSimilarity) - .slice(0, 50), - }); - } - - // Prune too small clusters. - // TODO-Cluster this is likely not needed since hdbscan already has a min? - const validClusters = clusters.filter(({ faceIDs }) => faceIDs.length > 1); - - // let cgroups = await clusterGroups(); - - // // TODO-Cluster - Currently we're not syncing with remote or saving anything - // // locally, so cgroups will be empty. Create a temporary (unsaved, unsynced) - // // cgroup, one per cluster. - // cgroups = cgroups.concat( - // validClusters.map((c) => ({ - // id: c.id, - // name: undefined, - // clusterIDs: [c.id], - // isHidden: false, - // avatarFaceID: undefined, - // displayFaceID: undefined, - // })), - // ); - - // // For each cluster group, use the highest scoring face in any of its - // // clusters as its display face. - // for (const cgroup of cgroups) { - // cgroup.displayFaceID = cgroup.clusterIDs - // .map((clusterID) => clusterIndexForClusterID.get(clusterID)) - // .filter((i) => i !== undefined) /* 0 is a valid index */ - // .flatMap((i) => clusters[i]?.faceIDs ?? []) - // .map((faceID) => faceForFaceID.get(faceID)) - // .filter((face) => !!face) - // .reduce((max, face) => - // max.score > face.score ? max : face, - // ).faceID; - // } - - // TODO-Cluster - Currently we're not syncing with remote or saving anything - // locally, so cgroups will be empty. Create a temporary (unsaved, unsynced) - // cgroup, one per cluster. - - const cgroups: CGroup[] = []; - for (const cluster of sortedClusters) { - const faces = cluster.faceIDs.map((id) => - ensure(faceForFaceID.get(id)), - ); - const topFace = faces.reduce((max, face) => - max.score > face.score ? max : face, - ); - cgroups.push({ - id: cluster.id, - name: undefined, - clusterIDs: [cluster.id], - isHidden: false, - avatarFaceID: undefined, - displayFaceID: topFace.faceID, - }); - } - - // log.info("ml/cluster", { - // faces, - // validClusters, - // clusterIndexForClusterID: Object.fromEntries(clusterIndexForClusterID), - // clusterIDForFaceID: Object.fromEntries(clusterIDForFaceID), - // cgroups, - // }); - log.info( - `Clustered ${faces.length} faces into ${validClusters.length} clusters, with ${faces.length - clusterIDForFaceID.size} faces remaining unclustered (${Date.now() - t} ms)`, - ); - - const clusteredCount = clusterIDForFaceID.size; - const unclusteredCount = faces.length - clusteredCount; - - return { - // faces, - clusteredCount, - unclusteredCount, - clusters: validClusters, - cgroups, - clusterPreviews, - clusterIDForFaceID, - }; -}; diff --git a/web/packages/new/photos/services/ml/cluster.ts b/web/packages/new/photos/services/ml/cluster.ts index 53e4930d94..f13b889aa1 100644 --- a/web/packages/new/photos/services/ml/cluster.ts +++ b/web/packages/new/photos/services/ml/cluster.ts @@ -1,35 +1,507 @@ -import { Hdbscan, type DebugInfo } from "hdbscan"; +import { newNonSecureID } from "@/base/id-worker"; +import log from "@/base/log"; +import { ensure } from "@/utils/ensure"; +import { type EmbeddingCluster, clusterHdbscan } from "./cluster-hdb"; +import type { Face, FaceIndex } from "./face"; +import { dotProduct } from "./math"; -export type Cluster = number[]; - -export interface ClusterFacesResult { - clusters: Cluster[]; - noise: Cluster; - debugInfo?: DebugInfo; +/** + * A face cluster is an set of faces. + * + * Each cluster has an id so that a {@link CGroup} can refer to it. + * + * The cluster is not directly synced to remote. Only clusters that the user + * interacts with get synced to remote, as part of a {@link CGroup}. + */ +export interface FaceCluster { + /** + * A nanoid for this cluster. + */ + id: string; + /** + * An unordered set of ids of the faces that belong to this cluster. + * + * For ergonomics of transportation and persistence this is an array, but it + * should conceptually be thought of as a set. + */ + faceIDs: string[]; } /** - * Cluster the given {@link faceEmbeddings}. + * A cgroup ("cluster group") is a group of clusters (possibly containing a + * single cluster) that the user has interacted with. + * + * Interactions include hiding, merging and giving a name and/or a cover photo. + * + * The most frequent interaction is naming a {@link FaceCluster}, which promotes + * it to a become a {@link CGroup}. The promotion comes with the ability to be + * synced with remote (as a "cgroup" user entity). + * + * There after, the user may attach more clusters to the same {@link CGroup}. + * + * > A named cluster group can be thought of as a "person", though this is not + * > necessarily an accurate characterization. e.g. there can be a named cluster + * > group that contains face clusters of pets. + * + * The other form of interaction is hiding. The user may hide a single (unnamed) + * cluster, or they may hide an named {@link CGroup}. In both cases, we promote + * the cluster to a CGroup if needed so that their request to hide gets synced. + * + * While in our local representation we separately maintain clusters and link to + * them from within CGroups by their clusterID, in the remote representation + * clusters themselves don't get synced. Instead, the "cgroup" entities synced + * with remote contain the clusters within themselves. So a group that gets + * synced with remote looks something like: + * + * { id, name, clusters: [{ clusterID, faceIDs }] } * - * @param faceEmbeddings An array of embeddings produced by our face indexing - * pipeline. Each embedding is for a face detected in an image (a single image - * may have multiple faces detected within it). */ -export const clusterFacesHdbscan = ( - faceEmbeddings: number[][], -): ClusterFacesResult => { - const hdbscan = new Hdbscan({ - input: faceEmbeddings, - minClusterSize: 3, - minSamples: 5, - clusterSelectionEpsilon: 0.6, - clusterSelectionMethod: "leaf", - debug: false, - }); +export interface CGroup { + /** + * A nanoid for this cluster group. + * + * This is the ID of the "cgroup" user entity (the envelope), and it is not + * contained as part of the group entity payload itself. + */ + id: string; + /** + * A name assigned by the user to this cluster group. + * + * The client should handle both empty strings and undefined as indicating a + * cgroup without a name. When the client needs to set this to an "empty" + * value, which happens when hiding an unnamed cluster, it should it to an + * empty string. That is, expect `"" | undefined`, but set `""`. + */ + name: string | undefined; + /** + * An unordered set of ids of the clusters that belong to this group. + * + * For ergonomics of transportation and persistence this is an array, but it + * should conceptually be thought of as a set. + */ + clusterIDs: string[]; + /** + * True if this cluster group should be hidden. + * + * The user can hide both named cluster groups and single unnamed clusters. + * If the user hides a single cluster that was offered as a suggestion to + * them on a client, the client will create a new unnamed cgroup containing + * it, and set its hidden flag to sync it with remote (so that other clients + * can also stop showing this cluster). + */ + isHidden: boolean; + /** + * The ID of the face that should be used as the cover photo for this + * cluster group (if the user has set one). + * + * This is similar to the [@link displayFaceID}, the difference being: + * + * - {@link avatarFaceID} is the face selected by the user. + * + * - {@link displayFaceID} is the automatic placeholder, and only comes + * into effect if the user has not explicitly selected a face. + */ + avatarFaceID: string | undefined; + /** + * Locally determined ID of the "best" face that should be used as the + * display face, to represent this cluster group in the UI. + * + * This property is not synced with remote. For more details, see + * {@link avatarFaceID}. + */ + displayFaceID: string | undefined; +} + +export interface ClusteringOpts { + method: "linear" | "hdbscan"; + batchSize: number; + joinThreshold: number; +} + +export interface ClusterPreview { + clusterSize: number; + faces: ClusterPreviewFace[]; +} + +export interface ClusterPreviewFace { + face: Face; + cosineSimilarity: number; + wasMerged: boolean; +} + +/** + * Cluster faces into groups. + * + * [Note: Face clustering algorithm] + * + * A cgroup (cluster group) consists of clusters, each of which itself is a set + * of faces. + * + * cgroup << cluster << face + * + * The clusters are generated locally by clients using the following algorithm: + * + * 1. clusters = [] initially, or fetched from remote. + * + * 2. For each face, find its nearest neighbour in the embedding space. + * + * 3. If no such neighbour is found within our threshold, create a new cluster. + * + * 4. Otherwise assign this face to the same cluster as its nearest neighbour. + * + * This user can then tweak the output of the algorithm by performing the + * following actions to the list of clusters that they can see: + * + * - They can provide a name for a cluster ("name a person"). This upgrades a + * cluster into a "cgroup", which is an entity that gets synced via remote + * to the user's other clients. + * + * - They can attach more clusters to a cgroup ("merge clusters") + * + * - They can remove a cluster from a cgroup ("break clusters"). + * + * After clustering, we also do some routine cleanup. Faces belonging to files + * that have been deleted (including those in Trash) should be pruned off. + * + * We should not make strict assumptions about the clusters we get from remote. + * In particular, the same face ID can be in different clusters. In such cases + * we should assign it arbitrarily assign it to the last cluster we find it in. + * Such leeway is intentionally provided to allow clients some slack in how they + * implement the sync without needing to make an blocking API request for every + * user interaction. + */ +export const clusterFaces = ( + faceIndexes: FaceIndex[], + opts: ClusteringOpts, +) => { + const { batchSize, joinThreshold } = opts; + const t = Date.now(); + + // A flattened array of faces. + // TODO-Cluster ad-hoc filtering and slicing + const faces0 = [...enumerateFaces(faceIndexes)].filter((f) => f.blur > 99); + // .slice(0, 6000); + // TODO-Cluster testing code, can be removed once done + const faces = Array(1) + .fill(0) + .flatMap(() => faces0); + + // For fast reverse lookup - map from face ids to the face. + const faceForFaceID = new Map(faces.map((f) => [f.faceID, f])); + + const faceEmbeddings = faces.map(({ embedding }) => embedding); + + // For fast reverse lookup - map from cluster ids to their index in the + // clusters array. + const clusterIndexForClusterID = new Map(); + + // For fast reverse lookup - map from the id of a face to the id of the + // cluster to which it belongs. + const clusterIDForFaceID = new Map(); + + // A function to chain two reverse lookup. + const firstFaceOfCluster = (cluster: FaceCluster) => + ensure(faceForFaceID.get(ensure(cluster.faceIDs[0]))); + + // A function to generate new cluster IDs. + const newClusterID = () => newNonSecureID("cluster_"); + + // The resultant clusters. + // TODO-Cluster Later on, instead of starting from a blank slate, this will + // be list of existing clusters we fetch from remote. + const clusters: FaceCluster[] = []; + + // Process the faces in batches. The faces are already sorted by file ID, + // which is a monotonically increasing integer, so we will also have some + // temporal locality. + // + // The number 2500 was derived by ad-hoc observations and takes a few + // seconds. On a particular test dataset and a particular machine, + // clustering 1k took ~2 seconds, 10k took ~2 mins, while 20k took ~8 mins. + // Memory usage was constant in all these cases. + // + // At around 100k faces, the clustering starts taking hours, and we start + // running into stack overflows. The stack overflows can perhaps be avoided + // by restructuring the code, but hours of uninterruptible work is anyways + // not feasible. + + const batchSize = 2500; + for (let i = 0; i < faceEmbeddings.length; i += batchSize) { + const it = Date.now(); + const embeddings = faceEmbeddings.slice(i, i + batchSize); + const { clusters: hdbClusters } = clusterHdbscan(embeddings); + + log.info( + `hdbscan produced ${hdbClusters.length} clusters from ${embeddings.length} faces (${Date.now() - it} ms)`, + ); + + // Merge the new clusters we got from hdbscan into the existing clusters + // if they are "near" them (using some heuristic). + // + // We need to ensure we don't change any of the existing cluster IDs, + // since these might be existing clusters we got from remote. + + for (const hdbCluster of hdbClusters) { + // Find the existing cluster whose (arbitrarily chosen) first face + // is the nearest neighbour of the (arbitrarily chosen) first face + // of the cluster produced by hdbscan. + + const newFace = ensure(faces[i + ensure(hdbCluster[0])]); + + let nnCluster: FaceCluster | undefined; + let nnCosineSimilarity = 0; + for (const existingCluster of clusters) { + const existingFace = firstFaceOfCluster(existingCluster); + + // The vectors are already normalized, so we can directly use their + // dot product as their cosine similarity. + const csim = dotProduct( + existingFace.embedding, + newFace.embedding, + ); + + // Use a higher cosine similarity threshold if either of the two + // faces are blurry. + const threshold = + existingFace.blur < 200 || newFace.blur < 200 ? 0.9 : 0.7; + if (csim > threshold && csim > nnCosineSimilarity) { + nnCluster = existingCluster; + nnCosineSimilarity = csim; + } + } + + if (nnCluster) { + // If we found an existing cluster that is near enough, + // sublimate the cluster produced by hdbscan into that cluster. + for (const j of hdbCluster) { + const { faceID } = ensure(faces[i + j]); + nnCluster.faceIDs.push(faceID); + clusterIDForFaceID.set(faceID, nnCluster.id); + } + } else { + // Otherwise make a new cluster from the cluster produced by + // hdbscan. + const clusterID = newClusterID(); + const faceIDs: string[] = []; + for (const j of hdbCluster) { + const { faceID } = ensure(faces[i + j]); + faceIDs.push(faceID); + clusterIDForFaceID.set(faceID, clusterID); + } + clusterIndexForClusterID.set(clusterID, clusters.length); + clusters.push({ id: clusterID, faceIDs }); + } + } + } + + // Convert into the data structure we're using to debug/visualize. + // const faceAndNeigbours: FaceNeighbours[] = []; + // const topFaces = faces.sort((a, b) => b.score - a.score).slice(0, 30); + // for (const fi of topFaces) { + // let neighbours: FaceNeighbour[] = []; + // for (const fj of faces) { + // // The vectors are already normalized, so we can directly use their + // // dot product as their cosine similarity. + // const csim = dotProduct(fi.embedding, fj.embedding); + // neighbours.push({ face: fj, cosineSimilarity: csim }); + // } + + // neighbours = neighbours + // .sort((a, b) => b.cosineSimilarity - a.cosineSimilarity) + // .slice(0, 30); + + // faceAndNeigbours.push({ face: fi, neighbours }); + // } + + // Convert into the data structure we're using to debug/visualize. + // + // > Showing only top 30 and bottom 30 clusters (and only up to 50 faces in + // > each, sorted by cosine distance to highest scoring face in the + // > cluster). + + const sortedClusters = clusters.sort( + (a, b) => b.faceIDs.length - a.faceIDs.length, + ); + const debugClusters = + sortedClusters.length < 60 + ? sortedClusters + : sortedClusters.slice(0, 30).concat(sortedClusters.slice(-30)); + const clusterPreviews: ClusterPreview[] = []; + for (const cluster of debugClusters) { + const faces = cluster.faceIDs.map((id) => + ensure(faceForFaceID.get(id)), + ); + const topFace = faces.reduce((max, face) => + max.score > face.score ? max : face, + ); + const previewFaces: ClusterPreviewFace[] = []; + for (const face of faces) { + const csim = dotProduct(topFace.embedding, face.embedding); + previewFaces.push({ face, cosineSimilarity: csim }); + } + clusterPreviews.push({ + clusterSize: cluster.faceIDs.length, + faces: previewFaces + .sort((a, b) => b.cosineSimilarity - a.cosineSimilarity) + .slice(0, 50), + }); + } + + // Prune too small clusters. + // TODO-Cluster this is likely not needed since hdbscan already has a min? + const validClusters = clusters.filter(({ faceIDs }) => faceIDs.length > 1); + + // let cgroups = await clusterGroups(); + + // // TODO-Cluster - Currently we're not syncing with remote or saving anything + // // locally, so cgroups will be empty. Create a temporary (unsaved, unsynced) + // // cgroup, one per cluster. + // cgroups = cgroups.concat( + // validClusters.map((c) => ({ + // id: c.id, + // name: undefined, + // clusterIDs: [c.id], + // isHidden: false, + // avatarFaceID: undefined, + // displayFaceID: undefined, + // })), + // ); + + // // For each cluster group, use the highest scoring face in any of its + // // clusters as its display face. + // for (const cgroup of cgroups) { + // cgroup.displayFaceID = cgroup.clusterIDs + // .map((clusterID) => clusterIndexForClusterID.get(clusterID)) + // .filter((i) => i !== undefined) /* 0 is a valid index */ + // .flatMap((i) => clusters[i]?.faceIDs ?? []) + // .map((faceID) => faceForFaceID.get(faceID)) + // .filter((face) => !!face) + // .reduce((max, face) => + // max.score > face.score ? max : face, + // ).faceID; + // } + + // TODO-Cluster - Currently we're not syncing with remote or saving anything + // locally, so cgroups will be empty. Create a temporary (unsaved, unsynced) + // cgroup, one per cluster. + + const cgroups: CGroup[] = []; + for (const cluster of sortedClusters) { + const faces = cluster.faceIDs.map((id) => + ensure(faceForFaceID.get(id)), + ); + const topFace = faces.reduce((max, face) => + max.score > face.score ? max : face, + ); + cgroups.push({ + id: cluster.id, + name: undefined, + clusterIDs: [cluster.id], + isHidden: false, + avatarFaceID: undefined, + displayFaceID: topFace.faceID, + }); + } + + // log.info("ml/cluster", { + // faces, + // validClusters, + // clusterIndexForClusterID: Object.fromEntries(clusterIndexForClusterID), + // clusterIDForFaceID: Object.fromEntries(clusterIDForFaceID), + // cgroups, + // }); + log.info( + `Clustered ${faces.length} faces into ${validClusters.length} clusters, with ${faces.length - clusterIDForFaceID.size} faces remaining unclustered (${Date.now() - t} ms)`, + ); + + const clusteredCount = clusterIDForFaceID.size; + const unclusteredCount = faces.length - clusteredCount; return { - clusters: hdbscan.getClusters(), - noise: hdbscan.getNoise(), - debugInfo: hdbscan.getDebugInfo(), + // faces, + clusteredCount, + unclusteredCount, + clusters: validClusters, + cgroups, + clusterPreviews, + clusterIDForFaceID, }; }; + +/** + * A generator function that returns a stream of {faceID, embedding} values, + * flattening all the the faces present in the given {@link faceIndices}. + */ +function* enumerateFaces(faceIndices: FaceIndex[]) { + for (const fi of faceIndices) { + for (const f of fi.faces) { + yield f; + } + } +} + +interface ClusterLinearResult { + clusters: EmbeddingCluster[]; +} + +const clusterLinear = ( + embeddings: number[][], + threshold: number, +): ClusterLinearResult => { + const clusters: EmbeddingCluster[] = []; + const clusterIndexForEmbeddingIndex = new Map(); + // For each embedding + for (const [i, ei] of embeddings.entries()) { + // If the embedding is already part of a cluster, then skip it. + if (clusterIndexForEmbeddingIndex.get(i)) continue; + + // Find the nearest neighbour from among all the other embeddings. + let nnIndex: number | undefined; + let nnCosineSimilarity = 0; + for (const [j, ej] of embeddings.entries()) { + // ! This is an O(n^2) loop, be careful when adding more code here. + + // Skip ourselves. + if (i == j) continue; + + // The vectors are already normalized, so we can directly use their + // dot product as their cosine similarity. + const csim = dotProduct(ei, ej); + if (csim > threshold && csim > nnCosineSimilarity) { + nnIndex = j; + nnCosineSimilarity = csim; + } + } + + if (nnIndex) { + // Find the cluster the nearest neighbour belongs to, if any. + const nnClusterIndex = clusterIndexForEmbeddingIndex.get(nnIndex); + + if (nnClusterIndex) { + // If the neighbour is already part of a cluster, also add + // ourselves to that cluster. + + ensure(clusters[nnClusterIndex]).push(i); + clusterIndexForEmbeddingIndex.set(i, nnClusterIndex); + } else { + // Otherwise create a new cluster with us and our nearest + // neighbour. + + clusterIndexForEmbeddingIndex.set(i, clusters.length); + clusterIndexForEmbeddingIndex.set(nnIndex, clusters.length); + clusters.push([i, nnIndex]); + } + } else { + // We didn't find a neighbour within the threshold. Create a new + // cluster with only this embedding. + + clusterIndexForEmbeddingIndex.set(i, clusters.length); + clusters.push([i]); + } + } + + // Prune singletone clusters. + const validClusters = clusters.filter((cs) => cs.length > 1); + + return { clusters: validClusters }; +}; diff --git a/web/packages/new/photos/services/ml/db.ts b/web/packages/new/photos/services/ml/db.ts index f6d2043752..5f57ea30e1 100644 --- a/web/packages/new/photos/services/ml/db.ts +++ b/web/packages/new/photos/services/ml/db.ts @@ -3,7 +3,7 @@ import log from "@/base/log"; import localForage from "@ente/shared/storage/localForage"; import { deleteDB, openDB, type DBSchema } from "idb"; import type { LocalCLIPIndex } from "./clip"; -import type { CGroup, FaceCluster } from "./cluster-new"; +import type { CGroup, FaceCluster } from "./cluster"; import type { LocalFaceIndex } from "./face"; /** diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index c5ff83c2ef..d4f3c862e3 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -24,7 +24,7 @@ import { type ClusteringOpts, type ClusterPreviewFace, type FaceCluster, -} from "./cluster-new"; +} from "./cluster"; import { regenerateFaceCrops } from "./crop"; import { clearMLDB, faceIndex, indexableAndIndexedCounts } from "./db"; import type { Face } from "./face"; @@ -386,7 +386,7 @@ export const wipClusterDebugPageContents = async ( clusters, cgroups, unclusteredFaces, - } = await worker().then((w) => w.clusterFacesHdb(opts)); + } = await worker().then((w) => w.clusterFaces(opts)); const localFiles = await getAllLocalFiles(); const localFileByID = new Map(localFiles.map((f) => [f.id, f])); diff --git a/web/packages/new/photos/services/ml/worker.ts b/web/packages/new/photos/services/ml/worker.ts index 6eff182347..518bfb2804 100644 --- a/web/packages/new/photos/services/ml/worker.ts +++ b/web/packages/new/photos/services/ml/worker.ts @@ -24,7 +24,7 @@ import { indexCLIP, type CLIPIndex, } from "./clip"; -import { clusterFacesHdb, type ClusteringOpts } from "./cluster-new"; +import { type ClusteringOpts } from "./cluster"; import { saveFaceCrops } from "./crop"; import { faceIndexes, @@ -276,8 +276,8 @@ export class MLWorker { } // TODO-Cluster - async clusterFacesHdb(opts: ClusteringOpts) { - return clusterFacesHdb(await faceIndexes(), opts); + async clusterFaces(opts: ClusteringOpts) { + return clusterFace(await faceIndexes(), opts); } } diff --git a/web/packages/new/photos/services/user-entity.ts b/web/packages/new/photos/services/user-entity.ts index 7e26726dd5..121171d214 100644 --- a/web/packages/new/photos/services/user-entity.ts +++ b/web/packages/new/photos/services/user-entity.ts @@ -12,7 +12,7 @@ import { ensure } from "@/utils/ensure"; import { nullToUndefined } from "@/utils/transform"; import { z } from "zod"; import { gunzip } from "./gzip"; -import type { CGroup } from "./ml/cluster-new"; +import type { CGroup } from "./ml/cluster"; import { applyCGroupDiff } from "./ml/db"; /** From 4f4eb773fc6c9b6969285cfa7fa0629fea523e5d Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 30 Aug 2024 17:24:49 +0530 Subject: [PATCH 134/275] Clean --- web/apps/photos/src/pages/cluster-debug.tsx | 4 +- .../new/photos/services/ml/cluster.ts | 139 ++++-------------- web/packages/new/photos/services/ml/index.ts | 10 +- web/packages/new/photos/services/ml/worker.ts | 4 +- 4 files changed, 41 insertions(+), 116 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 7f84b0c5f2..60efbb0118 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -6,7 +6,7 @@ import { type ClusterDebugPageContents, type ClusterPreviewFaceWithFile, } from "@/new/photos/services/ml"; -import { type ClusteringOpts } from "@/new/photos/services/ml/cluster-new"; +import { type ClusteringOpts } from "@/new/photos/services/ml/cluster"; import { faceDirection } from "@/new/photos/services/ml/face"; import { FlexWrapper, @@ -297,7 +297,7 @@ const Header: React.FC = ({ clusterRes, onCluster }) => { const clusterInfo = clusterRes && ( - {`${clusterRes.clusters.length} clusters from ${clusterRes.clusteredFaceCount} faces. ${clusterRes.unclusteredFaceCount} unclustered faces.`} + {`${clusterRes.clusters.length} clusters from ${clusterRes.clusteredFaceCount} faces in ${(clusterRes.timeTakenMs / 1000).toFixed(0)} seconds. ${clusterRes.unclusteredFaceCount} unclustered faces.`} Showing only top 30 and bottom 30 clusters. diff --git a/web/packages/new/photos/services/ml/cluster.ts b/web/packages/new/photos/services/ml/cluster.ts index f13b889aa1..7eec7af886 100644 --- a/web/packages/new/photos/services/ml/cluster.ts +++ b/web/packages/new/photos/services/ml/cluster.ts @@ -174,17 +174,11 @@ export const clusterFaces = ( faceIndexes: FaceIndex[], opts: ClusteringOpts, ) => { - const { batchSize, joinThreshold } = opts; + const { method, batchSize, joinThreshold } = opts; const t = Date.now(); // A flattened array of faces. - // TODO-Cluster ad-hoc filtering and slicing - const faces0 = [...enumerateFaces(faceIndexes)].filter((f) => f.blur > 99); - // .slice(0, 6000); - // TODO-Cluster testing code, can be removed once done - const faces = Array(1) - .fill(0) - .flatMap(() => faces0); + const faces = [...enumerateFaces(faceIndexes)].filter((f) => f.blur > 99); // For fast reverse lookup - map from face ids to the face. const faceForFaceID = new Map(faces.map((f) => [f.faceID, f])); @@ -199,6 +193,10 @@ export const clusterFaces = ( // cluster to which it belongs. const clusterIDForFaceID = new Map(); + // Keeps track of which faces were found by the OG clustering algorithm, and + // which were sublimated in from a later match. + const wasMergedFaceIDs = new Set(); + // A function to chain two reverse lookup. const firstFaceOfCluster = (cluster: FaceCluster) => ensure(faceForFaceID.get(ensure(cluster.faceIDs[0]))); @@ -214,18 +212,7 @@ export const clusterFaces = ( // Process the faces in batches. The faces are already sorted by file ID, // which is a monotonically increasing integer, so we will also have some // temporal locality. - // - // The number 2500 was derived by ad-hoc observations and takes a few - // seconds. On a particular test dataset and a particular machine, - // clustering 1k took ~2 seconds, 10k took ~2 mins, while 20k took ~8 mins. - // Memory usage was constant in all these cases. - // - // At around 100k faces, the clustering starts taking hours, and we start - // running into stack overflows. The stack overflows can perhaps be avoided - // by restructuring the code, but hours of uninterruptible work is anyways - // not feasible. - const batchSize = 2500; for (let i = 0; i < faceEmbeddings.length; i += batchSize) { const it = Date.now(); const embeddings = faceEmbeddings.slice(i, i + batchSize); @@ -294,92 +281,34 @@ export const clusterFaces = ( } } - // Convert into the data structure we're using to debug/visualize. - // const faceAndNeigbours: FaceNeighbours[] = []; - // const topFaces = faces.sort((a, b) => b.score - a.score).slice(0, 30); - // for (const fi of topFaces) { - // let neighbours: FaceNeighbour[] = []; - // for (const fj of faces) { - // // The vectors are already normalized, so we can directly use their - // // dot product as their cosine similarity. - // const csim = dotProduct(fi.embedding, fj.embedding); - // neighbours.push({ face: fj, cosineSimilarity: csim }); - // } - - // neighbours = neighbours - // .sort((a, b) => b.cosineSimilarity - a.cosineSimilarity) - // .slice(0, 30); - - // faceAndNeigbours.push({ face: fi, neighbours }); - // } - - // Convert into the data structure we're using to debug/visualize. - // - // > Showing only top 30 and bottom 30 clusters (and only up to 50 faces in - // > each, sorted by cosine distance to highest scoring face in the - // > cluster). - const sortedClusters = clusters.sort( (a, b) => b.faceIDs.length - a.faceIDs.length, ); - const debugClusters = + + // Convert into the data structure we're using to debug/visualize. + const clusterPreviewClusters = sortedClusters.length < 60 ? sortedClusters : sortedClusters.slice(0, 30).concat(sortedClusters.slice(-30)); - const clusterPreviews: ClusterPreview[] = []; - for (const cluster of debugClusters) { + const clusterPreviews = clusterPreviewClusters.map((cluster) => { const faces = cluster.faceIDs.map((id) => ensure(faceForFaceID.get(id)), ); - const topFace = faces.reduce((max, face) => - max.score > face.score ? max : face, + const topFace = faces.reduce((top, face) => + top.score > face.score ? top : face, ); - const previewFaces: ClusterPreviewFace[] = []; - for (const face of faces) { + const previewFaces: ClusterPreviewFace[] = faces.map((face) => { const csim = dotProduct(topFace.embedding, face.embedding); - previewFaces.push({ face, cosineSimilarity: csim }); - } - clusterPreviews.push({ + const wasMerged = wasMergedFaceIDs.has(face.faceID); + return { face, cosineSimilarity: csim, wasMerged }; + }); + return { clusterSize: cluster.faceIDs.length, faces: previewFaces .sort((a, b) => b.cosineSimilarity - a.cosineSimilarity) .slice(0, 50), - }); - } - - // Prune too small clusters. - // TODO-Cluster this is likely not needed since hdbscan already has a min? - const validClusters = clusters.filter(({ faceIDs }) => faceIDs.length > 1); - - // let cgroups = await clusterGroups(); - - // // TODO-Cluster - Currently we're not syncing with remote or saving anything - // // locally, so cgroups will be empty. Create a temporary (unsaved, unsynced) - // // cgroup, one per cluster. - // cgroups = cgroups.concat( - // validClusters.map((c) => ({ - // id: c.id, - // name: undefined, - // clusterIDs: [c.id], - // isHidden: false, - // avatarFaceID: undefined, - // displayFaceID: undefined, - // })), - // ); - - // // For each cluster group, use the highest scoring face in any of its - // // clusters as its display face. - // for (const cgroup of cgroups) { - // cgroup.displayFaceID = cgroup.clusterIDs - // .map((clusterID) => clusterIndexForClusterID.get(clusterID)) - // .filter((i) => i !== undefined) /* 0 is a valid index */ - // .flatMap((i) => clusters[i]?.faceIDs ?? []) - // .map((faceID) => faceForFaceID.get(faceID)) - // .filter((face) => !!face) - // .reduce((max, face) => - // max.score > face.score ? max : face, - // ).faceID; - // } + }; + }); // TODO-Cluster - Currently we're not syncing with remote or saving anything // locally, so cgroups will be empty. Create a temporary (unsaved, unsynced) @@ -390,8 +319,8 @@ export const clusterFaces = ( const faces = cluster.faceIDs.map((id) => ensure(faceForFaceID.get(id)), ); - const topFace = faces.reduce((max, face) => - max.score > face.score ? max : face, + const topFace = faces.reduce((top, face) => + top.score > face.score ? top : face, ); cgroups.push({ id: cluster.id, @@ -403,28 +332,22 @@ export const clusterFaces = ( }); } - // log.info("ml/cluster", { - // faces, - // validClusters, - // clusterIndexForClusterID: Object.fromEntries(clusterIndexForClusterID), - // clusterIDForFaceID: Object.fromEntries(clusterIDForFaceID), - // cgroups, - // }); + const timeTakenMs = Date.now() - t; log.info( - `Clustered ${faces.length} faces into ${validClusters.length} clusters, with ${faces.length - clusterIDForFaceID.size} faces remaining unclustered (${Date.now() - t} ms)`, + `Clustered ${faces.length} faces into ${clusters.length} clusters, with ${faces.length - clusterIDForFaceID.size} faces remaining unclustered (${timeTakenMs} ms)`, ); - const clusteredCount = clusterIDForFaceID.size; - const unclusteredCount = faces.length - clusteredCount; + const clusteredFaceCount = clusterIDForFaceID.size; + const unclusteredFaceCount = faces.length - clusteredFaceCount; return { - // faces, - clusteredCount, - unclusteredCount, - clusters: validClusters, - cgroups, + clusteredFaceCount, + unclusteredFaceCount, clusterPreviews, - clusterIDForFaceID, + clusters: sortedClusters, + cgroups, + unclusteredFaces: [], + timeTakenMs, }; }; diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index d4f3c862e3..836eba693e 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -365,7 +365,8 @@ export interface ClusterDebugPageContents { unclusteredFacesWithFile: { face: Face; enteFile: EnteFile; - }; + }[]; + timeTakenMs: number; } export const wipClusterDebugPageContents = async ( @@ -378,7 +379,6 @@ export const wipClusterDebugPageContents = async ( _wip_searchPersons = undefined; triggerStatusUpdate(); - // const { faceAndNeigbours, clusters, cgroups } = await clusterFaces( const { clusteredFaceCount, unclusteredFaceCount, @@ -386,6 +386,7 @@ export const wipClusterDebugPageContents = async ( clusters, cgroups, unclusteredFaces, + timeTakenMs, } = await worker().then((w) => w.clusterFaces(opts)); const localFiles = await getAllLocalFiles(); @@ -396,10 +397,10 @@ export const wipClusterDebugPageContents = async ( const clusterPreviewsWithFile = clusterPreviews.map( ({ clusterSize, faces }) => ({ clusterSize, - faces: faces.map(({ face, cosineSimilarity }) => ({ + faces: faces.map(({ face, ...rest }) => ({ face, enteFile: fileForFace(face), - cosineSimilarity, + ...rest, })), }), ); @@ -445,6 +446,7 @@ export const wipClusterDebugPageContents = async ( clusters, clusterPreviewsWithFile, unclusteredFacesWithFile, + timeTakenMs, }; }; diff --git a/web/packages/new/photos/services/ml/worker.ts b/web/packages/new/photos/services/ml/worker.ts index 518bfb2804..c663abc2c9 100644 --- a/web/packages/new/photos/services/ml/worker.ts +++ b/web/packages/new/photos/services/ml/worker.ts @@ -24,7 +24,7 @@ import { indexCLIP, type CLIPIndex, } from "./clip"; -import { type ClusteringOpts } from "./cluster"; +import { clusterFaces, type ClusteringOpts } from "./cluster"; import { saveFaceCrops } from "./crop"; import { faceIndexes, @@ -277,7 +277,7 @@ export class MLWorker { // TODO-Cluster async clusterFaces(opts: ClusteringOpts) { - return clusterFace(await faceIndexes(), opts); + return clusterFaces(await faceIndexes(), opts); } } From a9bc6502cb8c32695f3c9048285e727cac439fd7 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Fri, 30 Aug 2024 13:58:46 +0200 Subject: [PATCH 135/275] [mob][photos] proper logging in ML indexing isolate --- .../face_detection_service.dart | 28 +++------- .../face_embedding_service.dart | 8 +-- .../face_ml/face_recognition_service.dart | 54 ++++++++++--------- .../machine_learning/ml_computer.dart | 4 +- .../machine_learning/ml_indexing_isolate.dart | 10 ++-- .../clip/clip_image_encoder.dart | 21 ++++++-- .../semantic_search_service.dart | 7 +-- mobile/lib/utils/image_ml_util.dart | 12 +++-- mobile/lib/utils/ml_util.dart | 15 ++++-- 9 files changed, 85 insertions(+), 74 deletions(-) diff --git a/mobile/lib/services/machine_learning/face_ml/face_detection/face_detection_service.dart b/mobile/lib/services/machine_learning/face_ml/face_detection/face_detection_service.dart index c232317b3a..728de95dae 100644 --- a/mobile/lib/services/machine_learning/face_ml/face_detection/face_detection_service.dart +++ b/mobile/lib/services/machine_learning/face_ml/face_detection/face_detection_service.dart @@ -1,5 +1,4 @@ import "dart:async"; -import "dart:developer" as dev show log; import 'dart:typed_data' show ByteData, Float32List; import 'dart:ui' as ui show Image; @@ -55,9 +54,8 @@ class FaceDetectionService extends MlModel { 'sessionAddress should be valid', ); - final stopwatch = Stopwatch()..start(); + final startTime = DateTime.now(); - final stopwatchPreprocessing = Stopwatch()..start(); final (inputImageList, newSize) = await preprocessImageToFloat32ChannelsFirst( image, @@ -67,17 +65,12 @@ class FaceDetectionService extends MlModel { requiredHeight: kInputHeight, maintainAspectRatio: true, ); - stopwatchPreprocessing.stop(); - dev.log( - 'Face detection image preprocessing is finished, in ${stopwatchPreprocessing.elapsedMilliseconds}ms', - ); + final preprocessingTime = DateTime.now(); _logger.info( - 'Image decoding and preprocessing is finished, in ${stopwatchPreprocessing.elapsedMilliseconds}ms', + 'Face detection preprocessing is finished, in ${preprocessingTime.difference(startTime).inMilliseconds} ms', ); // Run inference - final stopwatchInterpreter = Stopwatch()..start(); - List>>? nestedResults = []; try { if (MlModel.usePlatformPlugin) { @@ -88,23 +81,16 @@ class FaceDetectionService extends MlModel { inputImageList, ); // [1, 25200, 16] } + _logger.info( + 'inference is finished, in ${DateTime.now().difference(preprocessingTime).inMilliseconds} ms', + ); } catch (e, s) { - dev.log('Error while running inference', error: e, stackTrace: s); + _logger.severe('Error while running inference', e, s); throw YOLOFaceInterpreterRunException(); } - stopwatchInterpreter.stop(); try { - _logger.info( - 'interpreter.run is finished, in ${stopwatchInterpreter.elapsedMilliseconds} ms', - ); - final relativeDetections = _yoloPostProcessOutputs(nestedResults!, newSize); - stopwatch.stop(); - _logger.info( - 'predict() face detection executed in ${stopwatch.elapsedMilliseconds}ms', - ); - return relativeDetections; } catch (e, s) { _logger.severe('Error while post processing', e, s); diff --git a/mobile/lib/services/machine_learning/face_ml/face_embedding/face_embedding_service.dart b/mobile/lib/services/machine_learning/face_ml/face_embedding/face_embedding_service.dart index f36a69c752..0853112c44 100644 --- a/mobile/lib/services/machine_learning/face_ml/face_embedding/face_embedding_service.dart +++ b/mobile/lib/services/machine_learning/face_ml/face_embedding/face_embedding_service.dart @@ -46,9 +46,11 @@ class FaceEmbeddingService extends MlModel { } else { return _runFFIBasedPredict(input, sessionAddress); } - } catch (e) { - _logger.info( - 'MobileFaceNet (PlatformPlugin: $MlModel.usePlatformPlugin)Error while running inference: $e', + } catch (e, s) { + _logger.severe( + 'Error while running inference (PlatformPlugin: ${MlModel.usePlatformPlugin})', + e, + s, ); throw MobileFaceNetInterpreterRunException(); } diff --git a/mobile/lib/services/machine_learning/face_ml/face_recognition_service.dart b/mobile/lib/services/machine_learning/face_ml/face_recognition_service.dart index 8b3bb7eda1..22e3019517 100644 --- a/mobile/lib/services/machine_learning/face_ml/face_recognition_service.dart +++ b/mobile/lib/services/machine_learning/face_ml/face_recognition_service.dart @@ -1,5 +1,4 @@ import "dart:async" show unawaited; -import "dart:developer" as dev show log; import "dart:typed_data" show ByteData, Float32List; import "dart:ui" show Image; @@ -16,7 +15,7 @@ import "package:photos/services/machine_learning/ml_result.dart"; import "package:photos/utils/image_ml_util.dart"; class FaceRecognitionService { - final _logger = Logger("FaceRecognitionService"); + static final _logger = Logger("FaceRecognitionService"); // Singleton pattern FaceRecognitionService._privateConstructor(); @@ -76,8 +75,6 @@ class FaceRecognitionService { int faceEmbeddingAddress, ) async { final faceResults = []; - - final Stopwatch stopwatch = Stopwatch()..start(); final startTime = DateTime.now(); // Get the faces @@ -89,19 +86,17 @@ class FaceRecognitionService { faceDetectionAddress, faceResults, ); - dev.log( - "${faceDetectionResult.length} faces detected with scores ${faceDetectionResult.map((e) => e.score).toList()}: completed `detectFacesSync` function, in " - "${stopwatch.elapsedMilliseconds} ms"); + final detectFacesTime = DateTime.now(); + final detectFacesMs = detectFacesTime.difference(startTime).inMilliseconds; // If no faces were detected, return a result with no faces. Otherwise, continue. if (faceDetectionResult.isEmpty) { - dev.log( - "No faceDetectionResult, Completed analyzing image with uploadedFileID $enteFileID, in " - "${stopwatch.elapsedMilliseconds} ms"); + _logger.info( + "Finished runFacesPipeline with fileID $enteFileID in $detectFacesMs ms (${faceDetectionResult.length} faces, detectFaces: $detectFacesMs ms)", + ); return []; } - stopwatch.reset(); // Align the faces final Float32List faceAlignmentResult = await _alignFacesSync( image, @@ -109,23 +104,24 @@ class FaceRecognitionService { faceDetectionResult, faceResults, ); - dev.log("Completed `alignFacesSync` function, in " - "${stopwatch.elapsedMilliseconds} ms"); + final alignFacesTime = DateTime.now(); + final alignFacesMs = + alignFacesTime.difference(detectFacesTime).inMilliseconds; - stopwatch.reset(); // Get the embeddings of the faces - final embeddings = await _embedFacesSync( + await _embedFacesSync( faceAlignmentResult, faceEmbeddingAddress, faceResults, ); - dev.log("Completed `embedFacesSync` function, in " - "${stopwatch.elapsedMilliseconds} ms"); - stopwatch.stop(); + final embedFacesTime = DateTime.now(); + final embedFacesMs = + embedFacesTime.difference(alignFacesTime).inMilliseconds; + final totalMs = DateTime.now().difference(startTime).inMilliseconds; - dev.log("Finished faces pipeline (${embeddings.length} faces) with " - "uploadedFileID $enteFileID, in " - "${DateTime.now().difference(startTime).inMilliseconds} ms"); + _logger.info( + "Finished runFacesPipeline with fileID $enteFileID in $totalMs ms (${faceDetectionResult.length} faces, detectFaces: $detectFacesMs ms, alignFaces: $alignFacesMs ms, embedFaces: $embedFacesMs ms)", + ); return faceResults; } @@ -160,8 +156,8 @@ class FaceRecognitionService { return faces; } on YOLOFaceInterpreterRunException { throw CouldNotRunFaceDetector(); - } catch (e) { - dev.log('[SEVERE] Face detection failed: $e'); + } catch (e, s) { + _logger.severe('Face detection failed', e, s); throw GeneralFaceMlException('Face detection failed: $e'); } } @@ -184,6 +180,9 @@ class FaceRecognitionService { // Store the results if (alignmentResults.length != faces.length) { + _logger.severe( + "The amount of alignment results (${alignmentResults.length}) does not match the number of faces (${faces.length})", + ); throw Exception( "The amount of alignment results (${alignmentResults.length}) does not match the number of faces (${faces.length})", ); @@ -195,7 +194,7 @@ class FaceRecognitionService { return alignedFaces; } catch (e, s) { - dev.log('[SEVERE] Face alignment failed: $e $s'); + _logger.severe('Face alignment failed: $e $s'); throw CouldNotWarpAffine(); } } @@ -214,6 +213,9 @@ class FaceRecognitionService { // Store the results if (embeddings.length != faceResults.length) { + _logger.severe( + "The amount of embeddings (${embeddings.length}) does not match the number of faces (${faceResults.length})", + ); throw Exception( "The amount of embeddings (${embeddings.length}) does not match the number of faces (${faceResults.length})", ); @@ -225,8 +227,8 @@ class FaceRecognitionService { return embeddings; } on MobileFaceNetInterpreterRunException { throw CouldNotRunFaceEmbeddor(); - } catch (e) { - dev.log('[SEVERE] Face embedding (batch) failed: $e'); + } catch (e, s) { + _logger.severe('Face embedding (batch) failed', e, s); throw GeneralFaceMlException('Face embedding (batch) failed: $e'); } } diff --git a/mobile/lib/services/machine_learning/ml_computer.dart b/mobile/lib/services/machine_learning/ml_computer.dart index 8f27dfb3d4..78743bbd84 100644 --- a/mobile/lib/services/machine_learning/ml_computer.dart +++ b/mobile/lib/services/machine_learning/ml_computer.dart @@ -102,6 +102,7 @@ class MLComputer { sendPort.send(true); break; case MLComputerOperation.runClipText: + //TODO:lau check logging here final textEmbedding = await ClipTextEncoder.predict(args); sendPort.send(List.from(textEmbedding, growable: false)); break; @@ -199,7 +200,8 @@ class MLComputer { // Load ClipText model final String modelName = ClipTextEncoder.instance.modelName; - final String? modelPath = await ClipTextEncoder.instance.downloadModelSafe(); + final String? modelPath = + await ClipTextEncoder.instance.downloadModelSafe(); if (modelPath == null) { throw Exception("Could not download clip text model, no wifi"); } diff --git a/mobile/lib/services/machine_learning/ml_indexing_isolate.dart b/mobile/lib/services/machine_learning/ml_indexing_isolate.dart index fec1cbf410..66772dd40b 100644 --- a/mobile/lib/services/machine_learning/ml_indexing_isolate.dart +++ b/mobile/lib/services/machine_learning/ml_indexing_isolate.dart @@ -67,9 +67,7 @@ class MLIndexingIsolate { @pragma('vm:entry-point') static void _isolateMain(SendPort mainSendPort) async { Logger.root.level = kDebugMode ? Level.ALL : Level.INFO; - Logger.root.onRecord.listen((LogRecord rec) { - debugPrint('[MLIsolate] ${rec.toPrettyString()}'); - }); + Logger.root.onRecord.listen(SuperLogging.onLogRecord); final receivePort = ReceivePort(); mainSendPort.send(receivePort.sendPort); receivePort.listen((message) async { @@ -81,11 +79,7 @@ class MLIndexingIsolate { try { switch (function) { case MLIndexingOperation.analyzeImage: - final time = DateTime.now(); final MLResult result = await analyzeImageStatic(args); - _logger.info( - "`analyzeImageSync` function executed in ${DateTime.now().difference(time).inMilliseconds} ms", - ); sendPort.send(result.toJsonString()); break; case MLIndexingOperation.loadModels: @@ -93,6 +87,7 @@ class MLIndexingIsolate { final modelPaths = args['modelPaths'] as List; final addresses = []; for (int i = 0; i < modelNames.length; i++) { + // TODO:lau check logging here final int address = await MlModel.loadModel( modelNames[i], modelPaths[i], @@ -102,6 +97,7 @@ class MLIndexingIsolate { sendPort.send(List.from(addresses, growable: false)); break; case MLIndexingOperation.releaseModels: + // TODO:lau check logging here final modelNames = args['modelNames'] as List; final modelAddresses = args['modelAddresses'] as List; for (int i = 0; i < modelNames.length; i++) { diff --git a/mobile/lib/services/machine_learning/semantic_search/clip/clip_image_encoder.dart b/mobile/lib/services/machine_learning/semantic_search/clip/clip_image_encoder.dart index 1b6e8a9ebe..193e9bac14 100644 --- a/mobile/lib/services/machine_learning/semantic_search/clip/clip_image_encoder.dart +++ b/mobile/lib/services/machine_learning/semantic_search/clip/clip_image_encoder.dart @@ -31,14 +31,27 @@ class ClipImageEncoder extends MlModel { static Future> predict( Image image, ByteData imageByteData, - int sessionAddress, - ) async { + int sessionAddress, [ + int? enteFileID, + ]) async { + final startTime = DateTime.now(); final inputList = await preprocessImageClip(image, imageByteData); + final preprocessingTime = DateTime.now(); + final preprocessingMs = + preprocessingTime.difference(startTime).inMilliseconds; + late List result; if (MlModel.usePlatformPlugin) { - return await _runPlatformPluginPredict(inputList); + result = await _runPlatformPluginPredict(inputList); } else { - return _runFFIBasedPredict(inputList, sessionAddress); + result = _runFFIBasedPredict(inputList, sessionAddress); } + final inferTime = DateTime.now(); + final inferenceMs = inferTime.difference(preprocessingTime).inMilliseconds; + final totalMs = inferTime.difference(startTime).inMilliseconds; + _logger.info( + "Clip predict took $totalMs ms${enteFileID != null ? " with fileID $enteFileID" : ""} (nference: $inferenceMs ms, preprocessing: $preprocessingMs ms)", + ); + return result; } static List _runFFIBasedPredict( diff --git a/mobile/lib/services/machine_learning/semantic_search/semantic_search_service.dart b/mobile/lib/services/machine_learning/semantic_search/semantic_search_service.dart index 7beb284df7..067259307f 100644 --- a/mobile/lib/services/machine_learning/semantic_search/semantic_search_service.dart +++ b/mobile/lib/services/machine_learning/semantic_search/semantic_search_service.dart @@ -24,7 +24,7 @@ import "package:photos/services/machine_learning/semantic_search/clip/clip_image import "package:shared_preferences/shared_preferences.dart"; class SemanticSearchService { - final _logger = Logger("SemanticSearchService"); + static final _logger = Logger("SemanticSearchService"); SemanticSearchService._privateConstructor(); static final SemanticSearchService instance = @@ -293,18 +293,15 @@ class SemanticSearchService { ByteData imageByteData, int clipImageAddress, ) async { - final startTime = DateTime.now(); final embedding = await ClipImageEncoder.predict( image, imageByteData, clipImageAddress, + enteFileID, ); final clipResult = ClipResult(fileID: enteFileID, embedding: embedding); - dev.log('Finished running ClipImage for $enteFileID in ' - '${DateTime.now().difference(startTime).inMilliseconds} ms'); - return clipResult; } } diff --git a/mobile/lib/utils/image_ml_util.dart b/mobile/lib/utils/image_ml_util.dart index e8eb3e7312..0de42f0c98 100644 --- a/mobile/lib/utils/image_ml_util.dart +++ b/mobile/lib/utils/image_ml_util.dart @@ -35,7 +35,9 @@ Future<(Image, ByteData)> decodeImageFromPath(String imagePath) async { await HeifConverter.convert(imagePath, format: 'jpg'); if (jpgPath == null) { _logger.severe('Error converting $format to jpg:', e, s); - throw Exception('InvalidImageFormatException: Error decoding image of format $format'); + throw Exception( + 'InvalidImageFormatException: Error decoding image of format $format', + ); } final imageData = await File(jpgPath).readAsBytes(); final image = await decodeImageFromData(imageData); @@ -47,7 +49,9 @@ Future<(Image, ByteData)> decodeImageFromPath(String imagePath) async { e, s, ); - throw Exception('InvalidImageFormatException: Error decoding image of format $format'); + throw Exception( + 'InvalidImageFormatException: Error decoding image of format $format', + ); } } } @@ -278,7 +282,9 @@ Future<(Float32List, List, List, List, Size)> final (alignmentResult, correctlyEstimated) = SimilarityTransform.estimate(face.allKeypoints); if (!correctlyEstimated) { - log('Face alignment failed because not able to estimate SimilarityTransform, for face: $face'); + _logger.severe( + 'Face alignment failed because not able to estimate SimilarityTransform, for face: $face', + ); throw Exception( 'Face alignment failed because not able to estimate SimilarityTransform', ); diff --git a/mobile/lib/utils/ml_util.dart b/mobile/lib/utils/ml_util.dart index 01ddd353a9..817c0bd4ea 100644 --- a/mobile/lib/utils/ml_util.dart +++ b/mobile/lib/utils/ml_util.dart @@ -388,18 +388,20 @@ Future analyzeImageStatic(Map args) async { final int clipImageAddress = args["clipImageAddress"] as int; _logger.info( - "Start analyzing image with uploadedFileID: $enteFileID inside the isolate", + "Start analyzeImageStatic with fileID: $enteFileID (runFaces: $runFaces, runClip: $runClip)", ); - final time = DateTime.now(); + final startTime = DateTime.now(); // Decode the image once to use for both face detection and alignment final (image, imageByteData) = await decodeImageFromPath(imagePath); - _logger.info('Reading and decoding image took ' - '${DateTime.now().difference(time).inMilliseconds} ms'); final decodedImageSize = Dimensions(height: image.height, width: image.width); final result = MLResult.fromEnteFileID(enteFileID); result.decodedImageSize = decodedImageSize; + final decodeTime = DateTime.now(); + _logger.info( + 'Reading and decoding image took ${decodeTime.difference(startTime).inMilliseconds} ms (fileID: $enteFileID)', + ); if (runFaces) { final resultFaces = await FaceRecognitionService.runFacesPipeline( @@ -426,6 +428,11 @@ Future analyzeImageStatic(Map args) async { result.clip = clipResult; } + final endTime = DateTime.now(); + _logger.info( + 'Finished analyzeImageStatic with fileID: $enteFileID, in ${endTime.difference(startTime).inMilliseconds} ms', + ); + return result; } catch (e, s) { _logger.severe("Could not analyze image", e, s); From 96397c24b41bf79f8a39ccb3f75730b113d46c1b Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 30 Aug 2024 17:36:01 +0530 Subject: [PATCH 136/275] Fin --- .../new/photos/services/ml/cluster.ts | 46 +++++++++++-------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/web/packages/new/photos/services/ml/cluster.ts b/web/packages/new/photos/services/ml/cluster.ts index 7eec7af886..f53b8bbf03 100644 --- a/web/packages/new/photos/services/ml/cluster.ts +++ b/web/packages/new/photos/services/ml/cluster.ts @@ -209,31 +209,37 @@ export const clusterFaces = ( // be list of existing clusters we fetch from remote. const clusters: FaceCluster[] = []; - // Process the faces in batches. The faces are already sorted by file ID, - // which is a monotonically increasing integer, so we will also have some - // temporal locality. - + // Process the faces in batches. for (let i = 0; i < faceEmbeddings.length; i += batchSize) { const it = Date.now(); - const embeddings = faceEmbeddings.slice(i, i + batchSize); - const { clusters: hdbClusters } = clusterHdbscan(embeddings); + + const embeddingBatch = faceEmbeddings.slice(i, i + batchSize); + let embeddingClusters: EmbeddingCluster[]; + if (method == "hdbscan") { + ({ clusters: embeddingClusters } = clusterHdbscan(embeddingBatch)); + } else { + ({ clusters: embeddingClusters } = clusterLinear( + embeddingBatch, + joinThreshold, + )); + } log.info( - `hdbscan produced ${hdbClusters.length} clusters from ${embeddings.length} faces (${Date.now() - it} ms)`, + `${method} produced ${embeddingClusters.length} clusters from ${embeddingBatch.length} faces (${Date.now() - it} ms)`, ); - // Merge the new clusters we got from hdbscan into the existing clusters - // if they are "near" them (using some heuristic). + // Merge the new clusters we got from this batch into the existing + // clusters if they are "near" enough (using some heuristic). // // We need to ensure we don't change any of the existing cluster IDs, // since these might be existing clusters we got from remote. - for (const hdbCluster of hdbClusters) { + for (const newCluster of embeddingClusters) { // Find the existing cluster whose (arbitrarily chosen) first face // is the nearest neighbour of the (arbitrarily chosen) first face - // of the cluster produced by hdbscan. + // of the cluster produced in this batch. - const newFace = ensure(faces[i + ensure(hdbCluster[0])]); + const newFace = ensure(faces[i + ensure(newCluster[0])]); let nnCluster: FaceCluster | undefined; let nnCosineSimilarity = 0; @@ -250,27 +256,29 @@ export const clusterFaces = ( // Use a higher cosine similarity threshold if either of the two // faces are blurry. const threshold = - existingFace.blur < 200 || newFace.blur < 200 ? 0.9 : 0.7; + existingFace.blur < 200 || newFace.blur < 200 + ? 0.9 + : joinThreshold; if (csim > threshold && csim > nnCosineSimilarity) { nnCluster = existingCluster; nnCosineSimilarity = csim; } } + // If we found an existing cluster that is near enough, merge the + // new cluster into the existing cluster. if (nnCluster) { - // If we found an existing cluster that is near enough, - // sublimate the cluster produced by hdbscan into that cluster. - for (const j of hdbCluster) { + for (const j of newCluster) { const { faceID } = ensure(faces[i + j]); + wasMergedFaceIDs.add(faceID); nnCluster.faceIDs.push(faceID); clusterIDForFaceID.set(faceID, nnCluster.id); } } else { - // Otherwise make a new cluster from the cluster produced by - // hdbscan. + // Otherwise retain the new cluster. const clusterID = newClusterID(); const faceIDs: string[] = []; - for (const j of hdbCluster) { + for (const j of newCluster) { const { faceID } = ensure(faces[i + j]); faceIDs.push(faceID); clusterIDForFaceID.set(faceID, clusterID); From 7ff9dd5a5750bf54b29c497f6c2f176a7ff64d12 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 30 Aug 2024 17:48:29 +0530 Subject: [PATCH 137/275] LF --- web/apps/photos/src/pages/cluster-debug.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 60efbb0118..a0997da481 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -97,7 +97,7 @@ const ClusterList: React.FC = ({ height, width }) => { const [items, setItems] = useState([]); const listRef = useRef(null); - // eslint-disable-next-line @typescript-eslint/no-unused-vars + const cluster = async (opts: ClusteringOpts) => { startLoading(); setClusterRes(await wipClusterDebugPageContents(opts)); From b93a591401cfe9182e221ec4579179ed1653e2ad Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 30 Aug 2024 17:58:47 +0530 Subject: [PATCH 138/275] Rem params --- web/apps/photos/src/pages/cluster-debug.tsx | 26 +++++++++++---------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index a0997da481..2795ee5303 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -73,7 +73,6 @@ const Options: React.FC = () => { const Container = styled("div")` display: block; - border: 1px solid tomato; flex: 1; width: 100%; flex-wrap: wrap; @@ -91,14 +90,16 @@ interface ClusterListProps { const ClusterList: React.FC = ({ height, width }) => { const { startLoading, finishLoading } = useContext(AppContext); + const [clusteringOpts, setClusteringOpts] = useState(); const [clusterRes, setClusterRes] = useState< ClusterDebugPageContents | undefined >(); const [items, setItems] = useState([]); const listRef = useRef(null); - const cluster = async (opts: ClusteringOpts) => { + setClusteringOpts(opts); + setClusterRes(undefined); startLoading(); setClusterRes(await wipClusterDebugPageContents(opts)); finishLoading(); @@ -141,6 +142,7 @@ const ClusterList: React.FC = ({ height, width }) => { return (
@@ -233,20 +235,20 @@ const ListItem = styled("div")` `; interface HeaderProps { + clusteringOpts: ClusteringOpts; clusterRes: ClusterDebugPageContents | undefined; onCluster: (opts: ClusteringOpts) => Promise; } -const Header: React.FC = ({ clusterRes, onCluster }) => { - const { values, handleSubmit, handleChange, isSubmitting } = - useFormik({ - initialValues: { - method: "hdbscan", - joinThreshold: 0.7, - batchSize: 2500, - }, - onSubmit: onCluster, - }); +const Header: React.FC = ({ + clusteringOpts, + clusterRes, + onCluster, +}) => { + const { values, handleSubmit, handleChange, isSubmitting } = useFormik({ + initialValues: clusteringOpts, + onSubmit: onCluster, + }); const form = (
From b06bd19bc9bfd7482fffb6fbdcb2e6ab223dbd8f Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 30 Aug 2024 18:07:17 +0530 Subject: [PATCH 139/275] Unclustered --- web/apps/photos/src/pages/cluster-debug.tsx | 47 ++++++++++++++----- .../new/photos/services/ml/cluster.ts | 12 +++-- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 2795ee5303..127133b323 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -4,10 +4,10 @@ import { faceCrop, wipClusterDebugPageContents, type ClusterDebugPageContents, - type ClusterPreviewFaceWithFile, } from "@/new/photos/services/ml"; import { type ClusteringOpts } from "@/new/photos/services/ml/cluster"; -import { faceDirection } from "@/new/photos/services/ml/face"; +import { faceDirection, type Face } from "@/new/photos/services/ml/face"; +import type { EnteFile } from "@/new/photos/types/file"; import { FlexWrapper, FluidContainer, @@ -90,7 +90,11 @@ interface ClusterListProps { const ClusterList: React.FC = ({ height, width }) => { const { startLoading, finishLoading } = useContext(AppContext); - const [clusteringOpts, setClusteringOpts] = useState(); + const [clusteringOpts, setClusteringOpts] = useState({ + method: "hdbscan", + joinThreshold: 0.7, + batchSize: 2500, + }); const [clusterRes, setClusterRes] = useState< ClusterDebugPageContents | undefined >(); @@ -158,7 +162,7 @@ const ClusterList: React.FC = ({ height, width }) => { > {!Array.isArray(item) ? ( - {`cluster size ${item.toFixed(2)}`} + {item} ) : ( item.map((f, i) => ( @@ -176,24 +180,36 @@ const ClusterList: React.FC = ({ height, width }) => { ); }; -type Item = number | ClusterPreviewFaceWithFile[]; +type Item = string | FaceWithFile[]; const itemsFromClusterRes = ( clusterRes: ClusterDebugPageContents, columns: number, ) => { - const { clusterPreviewsWithFile } = clusterRes; + const { clusterPreviewsWithFile, unclusteredFacesWithFile } = clusterRes; const result: Item[] = []; for (let index = 0; index < clusterPreviewsWithFile.length; index++) { const { clusterSize, faces } = clusterPreviewsWithFile[index]; - result.push(clusterSize); + result.push(`cluster size ${clusterSize.toFixed(2)}`); let lastIndex = 0; while (lastIndex < faces.length) { result.push(faces.slice(lastIndex, lastIndex + columns)); lastIndex += columns; } } + + if (unclusteredFacesWithFile.length) { + result.push(`•• unclustered faces ${unclusteredFacesWithFile.length}`); + let lastIndex = 0; + while (lastIndex < unclusteredFacesWithFile.length) { + result.push( + unclusteredFacesWithFile.slice(lastIndex, lastIndex + columns), + ); + lastIndex += columns; + } + } + return result; }; @@ -334,7 +350,14 @@ const Loader = () => ( ); interface FaceItemProps { - faceWithFile: ClusterPreviewFaceWithFile; + faceWithFile: FaceWithFile; +} + +interface FaceWithFile { + face: Face; + enteFile: EnteFile; + cosineSimilarity?: number; + wasMerged?: boolean; } const FaceItem: React.FC = ({ faceWithFile }) => { @@ -384,9 +407,11 @@ const FaceItem: React.FC = ({ faceWithFile }) => { {`s${face.score.toFixed(1)}`} - - {`c${cosineSimilarity.toFixed(1)}`} - + {cosineSimilarity && ( + + {`c${cosineSimilarity.toFixed(1)}`} + + )} {`d${d}`} diff --git a/web/packages/new/photos/services/ml/cluster.ts b/web/packages/new/photos/services/ml/cluster.ts index f53b8bbf03..e667884cb8 100644 --- a/web/packages/new/photos/services/ml/cluster.ts +++ b/web/packages/new/photos/services/ml/cluster.ts @@ -340,21 +340,25 @@ export const clusterFaces = ( }); } + const clusteredFaceCount = clusterIDForFaceID.size; + const unclusteredFaceCount = faces.length - clusteredFaceCount; + + const unclusteredFaces = faces.filter( + ({ faceID }) => !clusterIDForFaceID.has(faceID), + ); + const timeTakenMs = Date.now() - t; log.info( `Clustered ${faces.length} faces into ${clusters.length} clusters, with ${faces.length - clusterIDForFaceID.size} faces remaining unclustered (${timeTakenMs} ms)`, ); - const clusteredFaceCount = clusterIDForFaceID.size; - const unclusteredFaceCount = faces.length - clusteredFaceCount; - return { clusteredFaceCount, unclusteredFaceCount, clusterPreviews, clusters: sortedClusters, cgroups, - unclusteredFaces: [], + unclusteredFaces: unclusteredFaces, timeTakenMs, }; }; From 1881dde11fe605fb8dc0a0d31e7dbea5739b3ca8 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 30 Aug 2024 18:13:10 +0530 Subject: [PATCH 140/275] Fix aliasing --- web/packages/new/photos/services/ml/cluster.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web/packages/new/photos/services/ml/cluster.ts b/web/packages/new/photos/services/ml/cluster.ts index e667884cb8..266a089474 100644 --- a/web/packages/new/photos/services/ml/cluster.ts +++ b/web/packages/new/photos/services/ml/cluster.ts @@ -234,6 +234,10 @@ export const clusterFaces = ( // We need to ensure we don't change any of the existing cluster IDs, // since these might be existing clusters we got from remote. + // Create a copy so that we don't modify existing clusters as we're + // iterating. + const existingClusters = [...clusters]; + for (const newCluster of embeddingClusters) { // Find the existing cluster whose (arbitrarily chosen) first face // is the nearest neighbour of the (arbitrarily chosen) first face @@ -243,7 +247,7 @@ export const clusterFaces = ( let nnCluster: FaceCluster | undefined; let nnCosineSimilarity = 0; - for (const existingCluster of clusters) { + for (const existingCluster of existingClusters) { const existingFace = firstFaceOfCluster(existingCluster); // The vectors are already normalized, so we can directly use their From c6ec5cf64546feba742051362337fc9f26b3da3b Mon Sep 17 00:00:00 2001 From: ashilkn Date: Fri, 30 Aug 2024 18:13:46 +0530 Subject: [PATCH 141/275] [mob][photos] Fix state issue with video loop toggle button --- mobile/lib/ui/viewer/file/file_app_bar.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mobile/lib/ui/viewer/file/file_app_bar.dart b/mobile/lib/ui/viewer/file/file_app_bar.dart index 92d6d54239..b65a9d9c1e 100644 --- a/mobile/lib/ui/viewer/file/file_app_bar.dart +++ b/mobile/lib/ui/viewer/file/file_app_bar.dart @@ -57,6 +57,7 @@ class FileAppBarState extends State { late final StreamSubscription _guestViewEventSubscription; bool isGuestView = false; bool shouldLoopVideo = Configuration.instance.shouldLoopVideo(); + bool _reloadActions = false; @override void didUpdateWidget(FileAppBar oldWidget) { @@ -89,8 +90,9 @@ class FileAppBarState extends State { //When the widget is initialized, the actions are not available. //Cannot call _getActions() in initState. - if (_actions.isEmpty) { + if (_actions.isEmpty || _reloadActions) { _getActions(); + _reloadActions = false; } final isTrashedFile = widget.file is TrashFile; @@ -372,6 +374,7 @@ class FileAppBarState extends State { _onToggleVideoLoop() { Configuration.instance.setShouldLoopVideo(!shouldLoopVideo); setState(() { + _reloadActions = true; shouldLoopVideo = !shouldLoopVideo; }); } From d2459016f12472459db899c656b27da56142250a Mon Sep 17 00:00:00 2001 From: ashilkn Date: Fri, 30 Aug 2024 18:19:11 +0530 Subject: [PATCH 142/275] [mob][photos] Change copy --- mobile/lib/ui/viewer/file/file_app_bar.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mobile/lib/ui/viewer/file/file_app_bar.dart b/mobile/lib/ui/viewer/file/file_app_bar.dart index b65a9d9c1e..9fb901af6e 100644 --- a/mobile/lib/ui/viewer/file/file_app_bar.dart +++ b/mobile/lib/ui/viewer/file/file_app_bar.dart @@ -334,8 +334,8 @@ class FileAppBarState extends State { padding: EdgeInsets.all(8), ), shouldLoopVideo - ? const Text("Video loop on") - : const Text("Video loop off"), + ? const Text("Loop video on") + : const Text("Loop video off"), ], ), ), @@ -362,7 +362,7 @@ class FileAppBarState extends State { } else if (value == 6) { await _onTapGuestView(); } else if (value == 7) { - _onToggleVideoLoop(); + _onToggleLoopVideo(); } }, ), @@ -371,7 +371,7 @@ class FileAppBarState extends State { return _actions; } - _onToggleVideoLoop() { + _onToggleLoopVideo() { Configuration.instance.setShouldLoopVideo(!shouldLoopVideo); setState(() { _reloadActions = true; From 70ad285e094c95c9f384fb766320168a0684ab0f Mon Sep 17 00:00:00 2001 From: ashilkn Date: Fri, 30 Aug 2024 18:21:36 +0530 Subject: [PATCH 143/275] [mob][photos] Extract strings --- mobile/lib/generated/intl/messages_ar.dart | 2 ++ mobile/lib/generated/intl/messages_bg.dart | 5 ++++- mobile/lib/generated/intl/messages_ca.dart | 5 ++++- mobile/lib/generated/intl/messages_cs.dart | 5 ++++- mobile/lib/generated/intl/messages_da.dart | 2 ++ mobile/lib/generated/intl/messages_de.dart | 2 ++ mobile/lib/generated/intl/messages_el.dart | 4 +++- mobile/lib/generated/intl/messages_en.dart | 4 +++- mobile/lib/generated/intl/messages_es.dart | 2 ++ mobile/lib/generated/intl/messages_et.dart | 5 ++++- mobile/lib/generated/intl/messages_fa.dart | 2 ++ mobile/lib/generated/intl/messages_fr.dart | 2 ++ mobile/lib/generated/intl/messages_gu.dart | 5 ++++- mobile/lib/generated/intl/messages_he.dart | 2 ++ mobile/lib/generated/intl/messages_hi.dart | 2 ++ mobile/lib/generated/intl/messages_id.dart | 2 ++ mobile/lib/generated/intl/messages_it.dart | 2 ++ mobile/lib/generated/intl/messages_ja.dart | 5 ++++- mobile/lib/generated/intl/messages_km.dart | 5 ++++- mobile/lib/generated/intl/messages_ko.dart | 2 ++ mobile/lib/generated/intl/messages_nl.dart | 2 ++ mobile/lib/generated/intl/messages_no.dart | 2 ++ mobile/lib/generated/intl/messages_pl.dart | 2 ++ mobile/lib/generated/intl/messages_pt.dart | 2 ++ mobile/lib/generated/intl/messages_ru.dart | 2 ++ mobile/lib/generated/intl/messages_sv.dart | 2 ++ mobile/lib/generated/intl/messages_te.dart | 5 ++++- mobile/lib/generated/intl/messages_th.dart | 2 ++ mobile/lib/generated/intl/messages_ti.dart | 5 ++++- mobile/lib/generated/intl/messages_tr.dart | 2 ++ mobile/lib/generated/intl/messages_zh.dart | 2 ++ mobile/lib/generated/l10n.dart | 24 +++++++++++++++++++-- mobile/lib/l10n/intl_ar.arb | 4 +++- mobile/lib/l10n/intl_bg.arb | 4 +++- mobile/lib/l10n/intl_ca.arb | 4 +++- mobile/lib/l10n/intl_cs.arb | 4 +++- mobile/lib/l10n/intl_da.arb | 4 +++- mobile/lib/l10n/intl_de.arb | 4 +++- mobile/lib/l10n/intl_el.arb | 4 +++- mobile/lib/l10n/intl_en.arb | 4 +++- mobile/lib/l10n/intl_es.arb | 4 +++- mobile/lib/l10n/intl_et.arb | 4 +++- mobile/lib/l10n/intl_fa.arb | 4 +++- mobile/lib/l10n/intl_fr.arb | 4 +++- mobile/lib/l10n/intl_gu.arb | 4 +++- mobile/lib/l10n/intl_he.arb | 4 +++- mobile/lib/l10n/intl_hi.arb | 4 +++- mobile/lib/l10n/intl_id.arb | 4 +++- mobile/lib/l10n/intl_it.arb | 4 +++- mobile/lib/l10n/intl_ja.arb | 4 +++- mobile/lib/l10n/intl_km.arb | 4 +++- mobile/lib/l10n/intl_ko.arb | 4 +++- mobile/lib/l10n/intl_nl.arb | 4 +++- mobile/lib/l10n/intl_no.arb | 4 +++- mobile/lib/l10n/intl_pl.arb | 4 +++- mobile/lib/l10n/intl_pt.arb | 4 +++- mobile/lib/l10n/intl_ru.arb | 4 +++- mobile/lib/l10n/intl_sv.arb | 4 +++- mobile/lib/l10n/intl_te.arb | 4 +++- mobile/lib/l10n/intl_th.arb | 4 +++- mobile/lib/l10n/intl_ti.arb | 4 +++- mobile/lib/l10n/intl_tr.arb | 4 +++- mobile/lib/l10n/intl_zh.arb | 4 +++- mobile/lib/ui/viewer/file/file_app_bar.dart | 4 ++-- 64 files changed, 199 insertions(+), 46 deletions(-) diff --git a/mobile/lib/generated/intl/messages_ar.dart b/mobile/lib/generated/intl/messages_ar.dart index 1ce7ba622c..aea20b16df 100644 --- a/mobile/lib/generated/intl/messages_ar.dart +++ b/mobile/lib/generated/intl/messages_ar.dart @@ -41,6 +41,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("مفتاح الاسترداد غير صحيح"), "invalidEmailAddress": MessageLookupByLibrary.simpleMessage( "عنوان البريد الإلكتروني غير صالح"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "noRecoveryKey": MessageLookupByLibrary.simpleMessage("ما من مفتاح استرداد؟"), "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( diff --git a/mobile/lib/generated/intl/messages_bg.dart b/mobile/lib/generated/intl/messages_bg.dart index e887127f40..851852e93c 100644 --- a/mobile/lib/generated/intl/messages_bg.dart +++ b/mobile/lib/generated/intl/messages_bg.dart @@ -21,5 +21,8 @@ class MessageLookup extends MessageLookupByLibrary { String get localeName => 'bg'; final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => {}; + static Map _notInlinedMessages(_) => { + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on") + }; } diff --git a/mobile/lib/generated/intl/messages_ca.dart b/mobile/lib/generated/intl/messages_ca.dart index 84dea987b0..09442d5939 100644 --- a/mobile/lib/generated/intl/messages_ca.dart +++ b/mobile/lib/generated/intl/messages_ca.dart @@ -21,5 +21,8 @@ class MessageLookup extends MessageLookupByLibrary { String get localeName => 'ca'; final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => {}; + static Map _notInlinedMessages(_) => { + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on") + }; } diff --git a/mobile/lib/generated/intl/messages_cs.dart b/mobile/lib/generated/intl/messages_cs.dart index 2bfb5800f1..d356229fc0 100644 --- a/mobile/lib/generated/intl/messages_cs.dart +++ b/mobile/lib/generated/intl/messages_cs.dart @@ -21,5 +21,8 @@ class MessageLookup extends MessageLookupByLibrary { String get localeName => 'cs'; final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => {}; + static Map _notInlinedMessages(_) => { + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on") + }; } diff --git a/mobile/lib/generated/intl/messages_da.dart b/mobile/lib/generated/intl/messages_da.dart index f243887b61..9b8ffaf2a0 100644 --- a/mobile/lib/generated/intl/messages_da.dart +++ b/mobile/lib/generated/intl/messages_da.dart @@ -100,6 +100,8 @@ class MessageLookup extends MessageLookupByLibrary { "longPressAnEmailToVerifyEndToEndEncryption": MessageLookupByLibrary.simpleMessage( "Langt tryk på en e-mail for at bekræfte slutningen af krypteringen."), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "manage": MessageLookupByLibrary.simpleMessage("Administrér"), "memoryCount": m0, "mlIndexingDescription": MessageLookupByLibrary.simpleMessage( diff --git a/mobile/lib/generated/intl/messages_de.dart b/mobile/lib/generated/intl/messages_de.dart index 90dc0b7f0d..3efeeb2b0a 100644 --- a/mobile/lib/generated/intl/messages_de.dart +++ b/mobile/lib/generated/intl/messages_de.dart @@ -1009,6 +1009,8 @@ class MessageLookup extends MessageLookupByLibrary { "Lange auf eine E-Mail drücken, um die Ende-zu-Ende-Verschlüsselung zu überprüfen."), "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Drücken Sie lange auf ein Element, um es im Vollbildmodus anzuzeigen"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "lostDevice": MessageLookupByLibrary.simpleMessage("Gerät verloren?"), "machineLearning": MessageLookupByLibrary.simpleMessage("Maschinelles Lernen"), diff --git a/mobile/lib/generated/intl/messages_el.dart b/mobile/lib/generated/intl/messages_el.dart index 79c0433b27..806ebe1f80 100644 --- a/mobile/lib/generated/intl/messages_el.dart +++ b/mobile/lib/generated/intl/messages_el.dart @@ -23,6 +23,8 @@ class MessageLookup extends MessageLookupByLibrary { final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { "enterYourEmailAddress": MessageLookupByLibrary.simpleMessage( - "Εισάγετε την διεύθυνση ηλ. ταχυδρομείου σας") + "Εισάγετε την διεύθυνση ηλ. ταχυδρομείου σας"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on") }; } diff --git a/mobile/lib/generated/intl/messages_en.dart b/mobile/lib/generated/intl/messages_en.dart index 0c377470aa..cd4e029a65 100644 --- a/mobile/lib/generated/intl/messages_en.dart +++ b/mobile/lib/generated/intl/messages_en.dart @@ -501,7 +501,7 @@ class MessageLookup extends MessageLookupByLibrary { "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage("Confirm Account Deletion"), "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "Yes, I want to permanently delete this account and all its data."), + "Yes, I want to permanently delete this account and its data across all apps."), "confirmPassword": MessageLookupByLibrary.simpleMessage("Confirm password"), "confirmPlanChange": @@ -969,6 +969,8 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Long-press on an item to view in full-screen"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "lostDevice": MessageLookupByLibrary.simpleMessage("Lost device?"), "machineLearning": MessageLookupByLibrary.simpleMessage("Machine learning"), diff --git a/mobile/lib/generated/intl/messages_es.dart b/mobile/lib/generated/intl/messages_es.dart index 479c1538a0..8fdf9da3e8 100644 --- a/mobile/lib/generated/intl/messages_es.dart +++ b/mobile/lib/generated/intl/messages_es.dart @@ -987,6 +987,8 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Manten presionado un elemento para ver en pantalla completa"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "lostDevice": MessageLookupByLibrary.simpleMessage("¿Perdiste tu dispositivo?"), "machineLearning": diff --git a/mobile/lib/generated/intl/messages_et.dart b/mobile/lib/generated/intl/messages_et.dart index c1b8a2ba7e..064920dfe8 100644 --- a/mobile/lib/generated/intl/messages_et.dart +++ b/mobile/lib/generated/intl/messages_et.dart @@ -21,5 +21,8 @@ class MessageLookup extends MessageLookupByLibrary { String get localeName => 'et'; final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => {}; + static Map _notInlinedMessages(_) => { + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on") + }; } diff --git a/mobile/lib/generated/intl/messages_fa.dart b/mobile/lib/generated/intl/messages_fa.dart index b6650a943a..0ad7da61da 100644 --- a/mobile/lib/generated/intl/messages_fa.dart +++ b/mobile/lib/generated/intl/messages_fa.dart @@ -249,6 +249,8 @@ class MessageLookup extends MessageLookupByLibrary { "loginTerms": MessageLookupByLibrary.simpleMessage( "با کلیک بر روی ورود به سیستم، من با شرایط خدمات و سیاست حفظ حریم خصوصی موافقم"), "logout": MessageLookupByLibrary.simpleMessage("خروج"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "manage": MessageLookupByLibrary.simpleMessage("مدیریت"), "manageFamily": MessageLookupByLibrary.simpleMessage("مدیریت خانواده"), "manageLink": MessageLookupByLibrary.simpleMessage("مدیریت پیوند"), diff --git a/mobile/lib/generated/intl/messages_fr.dart b/mobile/lib/generated/intl/messages_fr.dart index af1060e22b..001b99ef5f 100644 --- a/mobile/lib/generated/intl/messages_fr.dart +++ b/mobile/lib/generated/intl/messages_fr.dart @@ -1010,6 +1010,8 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Appuyez longuement sur un élément pour le voir en plein écran"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "lostDevice": MessageLookupByLibrary.simpleMessage("Appareil perdu ?"), "machineLearning": MessageLookupByLibrary.simpleMessage("Apprentissage automatique"), diff --git a/mobile/lib/generated/intl/messages_gu.dart b/mobile/lib/generated/intl/messages_gu.dart index 6c1d7e4d90..fb3ab8be3b 100644 --- a/mobile/lib/generated/intl/messages_gu.dart +++ b/mobile/lib/generated/intl/messages_gu.dart @@ -21,5 +21,8 @@ class MessageLookup extends MessageLookupByLibrary { String get localeName => 'gu'; final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => {}; + static Map _notInlinedMessages(_) => { + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on") + }; } diff --git a/mobile/lib/generated/intl/messages_he.dart b/mobile/lib/generated/intl/messages_he.dart index e27bbe712b..ca95dae231 100644 --- a/mobile/lib/generated/intl/messages_he.dart +++ b/mobile/lib/generated/intl/messages_he.dart @@ -557,6 +557,8 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "לחץ לחיצה ארוכה על פריט על מנת לראות אותו במסך מלא"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "lostDevice": MessageLookupByLibrary.simpleMessage("איבדת את המכשיר?"), "manage": MessageLookupByLibrary.simpleMessage("נהל"), "manageDeviceStorage": diff --git a/mobile/lib/generated/intl/messages_hi.dart b/mobile/lib/generated/intl/messages_hi.dart index ce390ea7e0..f90d881b1d 100644 --- a/mobile/lib/generated/intl/messages_hi.dart +++ b/mobile/lib/generated/intl/messages_hi.dart @@ -77,6 +77,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("अमान्य ईमेल ऐड्रेस"), "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( "कृपया हमें इस जानकारी के लिए सहायता करें"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "noRecoveryKey": MessageLookupByLibrary.simpleMessage("रिकवरी कुंजी नहीं है?"), "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( diff --git a/mobile/lib/generated/intl/messages_id.dart b/mobile/lib/generated/intl/messages_id.dart index 3d0cee4c14..cfa7ce2c60 100644 --- a/mobile/lib/generated/intl/messages_id.dart +++ b/mobile/lib/generated/intl/messages_id.dart @@ -817,6 +817,8 @@ class MessageLookup extends MessageLookupByLibrary { "longPressAnEmailToVerifyEndToEndEncryption": MessageLookupByLibrary.simpleMessage( "Tekan dan tahan email untuk membuktikan enkripsi ujung ke ujung."), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "lostDevice": MessageLookupByLibrary.simpleMessage("Perangkat hilang?"), "machineLearning": MessageLookupByLibrary.simpleMessage("Pemelajaran mesin"), diff --git a/mobile/lib/generated/intl/messages_it.dart b/mobile/lib/generated/intl/messages_it.dart index 782eb147c5..867febe2b9 100644 --- a/mobile/lib/generated/intl/messages_it.dart +++ b/mobile/lib/generated/intl/messages_it.dart @@ -801,6 +801,8 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Premi a lungo su un elemento per visualizzarlo a schermo intero"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "lostDevice": MessageLookupByLibrary.simpleMessage("Dispositivo perso?"), "manage": MessageLookupByLibrary.simpleMessage("Gestisci"), diff --git a/mobile/lib/generated/intl/messages_ja.dart b/mobile/lib/generated/intl/messages_ja.dart index a36e46602c..4f9b5f9d57 100644 --- a/mobile/lib/generated/intl/messages_ja.dart +++ b/mobile/lib/generated/intl/messages_ja.dart @@ -21,5 +21,8 @@ class MessageLookup extends MessageLookupByLibrary { String get localeName => 'ja'; final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => {}; + static Map _notInlinedMessages(_) => { + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on") + }; } diff --git a/mobile/lib/generated/intl/messages_km.dart b/mobile/lib/generated/intl/messages_km.dart index 22d4231361..d034501147 100644 --- a/mobile/lib/generated/intl/messages_km.dart +++ b/mobile/lib/generated/intl/messages_km.dart @@ -21,5 +21,8 @@ class MessageLookup extends MessageLookupByLibrary { String get localeName => 'km'; final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => {}; + static Map _notInlinedMessages(_) => { + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on") + }; } diff --git a/mobile/lib/generated/intl/messages_ko.dart b/mobile/lib/generated/intl/messages_ko.dart index e378d62fd9..95f7a65da1 100644 --- a/mobile/lib/generated/intl/messages_ko.dart +++ b/mobile/lib/generated/intl/messages_ko.dart @@ -40,6 +40,8 @@ class MessageLookup extends MessageLookupByLibrary { "feedback": MessageLookupByLibrary.simpleMessage("피드백"), "invalidEmailAddress": MessageLookupByLibrary.simpleMessage("잘못된 이메일 주소"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "verify": MessageLookupByLibrary.simpleMessage("인증"), "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("계정이 삭제되었습니다.") diff --git a/mobile/lib/generated/intl/messages_nl.dart b/mobile/lib/generated/intl/messages_nl.dart index a33e630355..50469948cc 100644 --- a/mobile/lib/generated/intl/messages_nl.dart +++ b/mobile/lib/generated/intl/messages_nl.dart @@ -1005,6 +1005,8 @@ class MessageLookup extends MessageLookupByLibrary { "Druk lang op een e-mail om de versleuteling te verifiëren."), "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Houd een bestand lang ingedrukt om te bekijken op volledig scherm"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "lostDevice": MessageLookupByLibrary.simpleMessage("Apparaat verloren?"), "machineLearning": diff --git a/mobile/lib/generated/intl/messages_no.dart b/mobile/lib/generated/intl/messages_no.dart index e5badae7f5..d3589b9b62 100644 --- a/mobile/lib/generated/intl/messages_no.dart +++ b/mobile/lib/generated/intl/messages_no.dart @@ -263,6 +263,8 @@ class MessageLookup extends MessageLookupByLibrary { "logInLabel": MessageLookupByLibrary.simpleMessage("Logg inn"), "loginTerms": MessageLookupByLibrary.simpleMessage( "Ved å klikke Logg inn, godtar jeg brukervilkårene og personvernreglene"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "lostDevice": MessageLookupByLibrary.simpleMessage("Mistet enhet?"), "machineLearning": MessageLookupByLibrary.simpleMessage("Maskinlæring"), "magicSearch": MessageLookupByLibrary.simpleMessage("Magisk søk"), diff --git a/mobile/lib/generated/intl/messages_pl.dart b/mobile/lib/generated/intl/messages_pl.dart index 8cb6018be4..c888ded391 100644 --- a/mobile/lib/generated/intl/messages_pl.dart +++ b/mobile/lib/generated/intl/messages_pl.dart @@ -1000,6 +1000,8 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Długo naciśnij element, aby wyświetlić go na pełnym ekranie"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "lostDevice": MessageLookupByLibrary.simpleMessage("Utracono urządzenie?"), "machineLearning": diff --git a/mobile/lib/generated/intl/messages_pt.dart b/mobile/lib/generated/intl/messages_pt.dart index 0472cbcbe0..d21045fdec 100644 --- a/mobile/lib/generated/intl/messages_pt.dart +++ b/mobile/lib/generated/intl/messages_pt.dart @@ -999,6 +999,8 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Pressione e segure em um item para exibir em tela cheia"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "lostDevice": MessageLookupByLibrary.simpleMessage("Dispositivo perdido?"), "machineLearning": diff --git a/mobile/lib/generated/intl/messages_ru.dart b/mobile/lib/generated/intl/messages_ru.dart index e40aaf8ce5..f7789a20e3 100644 --- a/mobile/lib/generated/intl/messages_ru.dart +++ b/mobile/lib/generated/intl/messages_ru.dart @@ -982,6 +982,8 @@ class MessageLookup extends MessageLookupByLibrary { "Длительное нажатие на email для подтверждения сквозного шифрования."), "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Удерживайте нажатие на элемент для просмотра в полноэкранном режиме"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "lostDevice": MessageLookupByLibrary.simpleMessage("Потеряли свое устройство?"), "machineLearning": diff --git a/mobile/lib/generated/intl/messages_sv.dart b/mobile/lib/generated/intl/messages_sv.dart index 16f3eafe48..0adaac9efd 100644 --- a/mobile/lib/generated/intl/messages_sv.dart +++ b/mobile/lib/generated/intl/messages_sv.dart @@ -318,6 +318,8 @@ class MessageLookup extends MessageLookupByLibrary { "loginTerms": MessageLookupByLibrary.simpleMessage( "Genom att klicka på logga in godkänner jag användarvillkoren och våran integritetspolicy"), "logout": MessageLookupByLibrary.simpleMessage("Logga ut"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "lostDevice": MessageLookupByLibrary.simpleMessage("Förlorad enhet?"), "manage": MessageLookupByLibrary.simpleMessage("Hantera"), "manageLink": MessageLookupByLibrary.simpleMessage("Hantera länk"), diff --git a/mobile/lib/generated/intl/messages_te.dart b/mobile/lib/generated/intl/messages_te.dart index 5e415c9da0..63ee905c5e 100644 --- a/mobile/lib/generated/intl/messages_te.dart +++ b/mobile/lib/generated/intl/messages_te.dart @@ -21,5 +21,8 @@ class MessageLookup extends MessageLookupByLibrary { String get localeName => 'te'; final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => {}; + static Map _notInlinedMessages(_) => { + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on") + }; } diff --git a/mobile/lib/generated/intl/messages_th.dart b/mobile/lib/generated/intl/messages_th.dart index a1bc4df70a..3ecc08c00d 100644 --- a/mobile/lib/generated/intl/messages_th.dart +++ b/mobile/lib/generated/intl/messages_th.dart @@ -211,6 +211,8 @@ class MessageLookup extends MessageLookupByLibrary { "logInLabel": MessageLookupByLibrary.simpleMessage("เข้าสู่ระบบ"), "loginTerms": MessageLookupByLibrary.simpleMessage( "โดยการคลิกเข้าสู่ระบบ ฉันยอมรับเงื่อนไขการให้บริการและนโยบายความเป็นส่วนตัว"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "manageParticipants": MessageLookupByLibrary.simpleMessage("จัดการ"), "map": MessageLookupByLibrary.simpleMessage("แผนที่"), "maps": MessageLookupByLibrary.simpleMessage("แผนที่"), diff --git a/mobile/lib/generated/intl/messages_ti.dart b/mobile/lib/generated/intl/messages_ti.dart index 775cc78213..f366d5665f 100644 --- a/mobile/lib/generated/intl/messages_ti.dart +++ b/mobile/lib/generated/intl/messages_ti.dart @@ -21,5 +21,8 @@ class MessageLookup extends MessageLookupByLibrary { String get localeName => 'ti'; final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => {}; + static Map _notInlinedMessages(_) => { + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on") + }; } diff --git a/mobile/lib/generated/intl/messages_tr.dart b/mobile/lib/generated/intl/messages_tr.dart index fd82236d0d..e2b1057550 100644 --- a/mobile/lib/generated/intl/messages_tr.dart +++ b/mobile/lib/generated/intl/messages_tr.dart @@ -857,6 +857,8 @@ class MessageLookup extends MessageLookupByLibrary { "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage( "Tam ekranda görüntülemek için bir öğeye uzun basın"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "lostDevice": MessageLookupByLibrary.simpleMessage("Cihazı kayıp mı ettiniz?"), "machineLearning": diff --git a/mobile/lib/generated/intl/messages_zh.dart b/mobile/lib/generated/intl/messages_zh.dart index 2a34fee561..47482f612b 100644 --- a/mobile/lib/generated/intl/messages_zh.dart +++ b/mobile/lib/generated/intl/messages_zh.dart @@ -825,6 +825,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("长按电子邮件以验证端到端加密。"), "longpressOnAnItemToViewInFullscreen": MessageLookupByLibrary.simpleMessage("长按一个项目来全屏查看"), + "loopVideoOff": MessageLookupByLibrary.simpleMessage("Loop video off"), + "loopVideoOn": MessageLookupByLibrary.simpleMessage("Loop video on"), "lostDevice": MessageLookupByLibrary.simpleMessage("设备丢失?"), "machineLearning": MessageLookupByLibrary.simpleMessage("机器学习"), "magicSearch": MessageLookupByLibrary.simpleMessage("魔法搜索"), diff --git a/mobile/lib/generated/l10n.dart b/mobile/lib/generated/l10n.dart index e88b25f990..9cb39c1c2a 100644 --- a/mobile/lib/generated/l10n.dart +++ b/mobile/lib/generated/l10n.dart @@ -170,10 +170,10 @@ class S { ); } - /// `Yes, I want to permanently delete this account and all its data.` + /// `Yes, I want to permanently delete this account and its data across all apps.` String get confirmDeletePrompt { return Intl.message( - 'Yes, I want to permanently delete this account and all its data.', + 'Yes, I want to permanently delete this account and its data across all apps.', name: 'confirmDeletePrompt', desc: '', args: [], @@ -9494,6 +9494,26 @@ class S { args: [], ); } + + /// `Loop video on` + String get loopVideoOn { + return Intl.message( + 'Loop video on', + name: 'loopVideoOn', + desc: '', + args: [], + ); + } + + /// `Loop video off` + String get loopVideoOff { + return Intl.message( + 'Loop video off', + name: 'loopVideoOff', + desc: '', + args: [], + ); + } } class AppLocalizationDelegate extends LocalizationsDelegate { diff --git a/mobile/lib/l10n/intl_ar.arb b/mobile/lib/l10n/intl_ar.arb index 86273581a6..dbea9b3da1 100644 --- a/mobile/lib/l10n/intl_ar.arb +++ b/mobile/lib/l10n/intl_ar.arb @@ -23,5 +23,7 @@ "noRecoveryKeyNoDecryption": "لا يمكن فك تشفير بياناتك دون كلمة المرور أو مفتاح الاسترداد بسبب طبيعة بروتوكول التشفير الخاص بنا من النهاية إلى النهاية", "verifyEmail": "التحقق من البريد الإلكتروني", "toResetVerifyEmail": "لإعادة تعيين كلمة المرور، يرجى التحقق من بريدك الإلكتروني أولاً.", - "ackPasswordLostWarning": "أُدركُ أنّني فقدتُ كلمة مروري، فقد أفقد بياناتي لأن بياناتي مشفرة تشفيرًا تامًّا من النهاية إلى النهاية." + "ackPasswordLostWarning": "أُدركُ أنّني فقدتُ كلمة مروري، فقد أفقد بياناتي لأن بياناتي مشفرة تشفيرًا تامًّا من النهاية إلى النهاية.", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_bg.arb b/mobile/lib/l10n/intl_bg.arb index c8494661c6..3c06fdbe82 100644 --- a/mobile/lib/l10n/intl_bg.arb +++ b/mobile/lib/l10n/intl_bg.arb @@ -1,3 +1,5 @@ { - "@@locale ": "en" + "@@locale ": "en", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ca.arb b/mobile/lib/l10n/intl_ca.arb index c8494661c6..3c06fdbe82 100644 --- a/mobile/lib/l10n/intl_ca.arb +++ b/mobile/lib/l10n/intl_ca.arb @@ -1,3 +1,5 @@ { - "@@locale ": "en" + "@@locale ": "en", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_cs.arb b/mobile/lib/l10n/intl_cs.arb index c8494661c6..3c06fdbe82 100644 --- a/mobile/lib/l10n/intl_cs.arb +++ b/mobile/lib/l10n/intl_cs.arb @@ -1,3 +1,5 @@ { - "@@locale ": "en" + "@@locale ": "en", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_da.arb b/mobile/lib/l10n/intl_da.arb index 49c26657f9..1f008e0571 100644 --- a/mobile/lib/l10n/intl_da.arb +++ b/mobile/lib/l10n/intl_da.arb @@ -85,5 +85,7 @@ "longPressAnEmailToVerifyEndToEndEncryption": "Langt tryk på en e-mail for at bekræfte slutningen af krypteringen.", "developerSettingsWarning": "Er du sikker på, at du vil ændre udviklerindstillingerne?", "next": "Næste", - "enterPin": "Indtast PIN" + "enterPin": "Indtast PIN", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_de.arb b/mobile/lib/l10n/intl_de.arb index aa50482f8d..f7250591dd 100644 --- a/mobile/lib/l10n/intl_de.arb +++ b/mobile/lib/l10n/intl_de.arb @@ -1314,5 +1314,7 @@ "cl_video_player_description": "Einführung eines neuen Video-Players mit besserer Wiedergabesteuerung und Unterstützung für HDR-Videos.", "appLockDescriptions": "Wähle zwischen dem Standard-Sperrbildschirm deines Gerätes und einem eigenen Sperrbildschirm mit PIN oder Passwort.", "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Um die App-Sperre zu aktivieren, konfiguriere bitte den Gerätepasscode oder die Bildschirmsperre in den Systemeinstellungen.", - "authToViewPasskey": "Bitte authentifizieren, um deinen Passkey zu sehen" + "authToViewPasskey": "Bitte authentifizieren, um deinen Passkey zu sehen", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_el.arb b/mobile/lib/l10n/intl_el.arb index ce8b1a1a54..16e2bbf02a 100644 --- a/mobile/lib/l10n/intl_el.arb +++ b/mobile/lib/l10n/intl_el.arb @@ -1,4 +1,6 @@ { "@@locale ": "en", - "enterYourEmailAddress": "Εισάγετε την διεύθυνση ηλ. ταχυδρομείου σας" + "enterYourEmailAddress": "Εισάγετε την διεύθυνση ηλ. ταχυδρομείου σας", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_en.arb b/mobile/lib/l10n/intl_en.arb index ae78fa60c3..ad4c9a2b85 100644 --- a/mobile/lib/l10n/intl_en.arb +++ b/mobile/lib/l10n/intl_en.arb @@ -1315,5 +1315,7 @@ "cl_video_player_description": "Introducing a fresh new video player, with better playback controls and support for HDR videos.", "appLockDescriptions": "Choose between your device's default lock screen and a custom lock screen with a PIN or password.", "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "To enable app lock, please setup device passcode or screen lock in your system settings.", - "authToViewPasskey": "Please authenticate to view your passkey" + "authToViewPasskey": "Please authenticate to view your passkey", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_es.arb b/mobile/lib/l10n/intl_es.arb index 238f61095f..a08d08e877 100644 --- a/mobile/lib/l10n/intl_es.arb +++ b/mobile/lib/l10n/intl_es.arb @@ -1287,5 +1287,7 @@ "removePublicLinks": "Eliminar enlaces públicos", "thisWillRemovePublicLinksOfAllSelectedQuickLinks": "Esto eliminará los enlaces públicos de todos los enlaces rápidos seleccionados.", "guestView": "Vista de invitado", - "guestViewEnablePreSteps": "Para habilitar la vista de invitados, por favor configure el código de acceso del dispositivo o el bloqueo de pantalla en los ajustes de su sistema." + "guestViewEnablePreSteps": "Para habilitar la vista de invitados, por favor configure el código de acceso del dispositivo o el bloqueo de pantalla en los ajustes de su sistema.", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_et.arb b/mobile/lib/l10n/intl_et.arb index c8494661c6..3c06fdbe82 100644 --- a/mobile/lib/l10n/intl_et.arb +++ b/mobile/lib/l10n/intl_et.arb @@ -1,3 +1,5 @@ { - "@@locale ": "en" + "@@locale ": "en", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_fa.arb b/mobile/lib/l10n/intl_fa.arb index d5dbe63862..b42295354d 100644 --- a/mobile/lib/l10n/intl_fa.arb +++ b/mobile/lib/l10n/intl_fa.arb @@ -308,5 +308,7 @@ "developerSettings": "تنظیمات توسعه‌دهنده", "search": "جستجو", "whatsNew": "تغییرات جدید", - "reviewSuggestions": "مرور پیشنهادها" + "reviewSuggestions": "مرور پیشنهادها", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_fr.arb b/mobile/lib/l10n/intl_fr.arb index 8f4b1e375e..55714b9125 100644 --- a/mobile/lib/l10n/intl_fr.arb +++ b/mobile/lib/l10n/intl_fr.arb @@ -1285,5 +1285,7 @@ "cl_panorama_viewer_description": "Nous avons ajouté le support pour visionner des photos panoramiques avec des vues à 360 degrés. L'expérience est immersive avec la navigation basée sur les mouvements !", "cl_video_player_title": "Lecteur vidéo", "cl_video_player_description": "Intégration d'un nouveau lecteur vidéo, avec de meilleurs contrôles de lecture et la prise en charge des vidéos HDR.", - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Pour activer le verrouillage d'application, veuillez configurer le code d'accès de l'appareil ou le verrouillage de l'écran dans les paramètres de votre système." + "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Pour activer le verrouillage d'application, veuillez configurer le code d'accès de l'appareil ou le verrouillage de l'écran dans les paramètres de votre système.", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_gu.arb b/mobile/lib/l10n/intl_gu.arb index c8494661c6..3c06fdbe82 100644 --- a/mobile/lib/l10n/intl_gu.arb +++ b/mobile/lib/l10n/intl_gu.arb @@ -1,3 +1,5 @@ { - "@@locale ": "en" + "@@locale ": "en", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_he.arb b/mobile/lib/l10n/intl_he.arb index ad713b19d7..237ccf1332 100644 --- a/mobile/lib/l10n/intl_he.arb +++ b/mobile/lib/l10n/intl_he.arb @@ -819,5 +819,7 @@ "addPhotos": "הוסף תמונות", "create": "צור", "viewAll": "הצג הכל", - "hiding": "מחביא..." + "hiding": "מחביא...", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_hi.arb b/mobile/lib/l10n/intl_hi.arb index 35f1e866b4..c70c8bee50 100644 --- a/mobile/lib/l10n/intl_hi.arb +++ b/mobile/lib/l10n/intl_hi.arb @@ -49,5 +49,7 @@ "sorry": "क्षमा करें!", "noRecoveryKeyNoDecryption": "हमारे एंड-टू-एंड एन्क्रिप्शन प्रोटोकॉल की प्रकृति के कारण, आपके डेटा को आपके पासवर्ड या रिकवरी कुंजी के बिना डिक्रिप्ट नहीं किया जा सकता है", "verifyEmail": "ईमेल सत्यापित करें", - "toResetVerifyEmail": "अपना पासवर्ड रीसेट करने के लिए, कृपया पहले अपना ईमेल सत्यापित करें।" + "toResetVerifyEmail": "अपना पासवर्ड रीसेट करने के लिए, कृपया पहले अपना ईमेल सत्यापित करें।", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_id.arb b/mobile/lib/l10n/intl_id.arb index 0768a2d798..ca032e8060 100644 --- a/mobile/lib/l10n/intl_id.arb +++ b/mobile/lib/l10n/intl_id.arb @@ -1065,5 +1065,7 @@ "rotate": "Putar", "left": "Kiri", "right": "Kanan", - "whatsNew": "Hal yang baru" + "whatsNew": "Hal yang baru", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_it.arb b/mobile/lib/l10n/intl_it.arb index ac66ecca17..f03bb21411 100644 --- a/mobile/lib/l10n/intl_it.arb +++ b/mobile/lib/l10n/intl_it.arb @@ -1103,5 +1103,7 @@ "selectALocation": "Seleziona un luogo", "selectALocationFirst": "Scegli prima una posizione", "changeLocationOfSelectedItems": "Cambiare la posizione degli elementi selezionati?", - "editsToLocationWillOnlyBeSeenWithinEnte": "Le modifiche alla posizione saranno visibili solo all'interno di Ente" + "editsToLocationWillOnlyBeSeenWithinEnte": "Le modifiche alla posizione saranno visibili solo all'interno di Ente", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ja.arb b/mobile/lib/l10n/intl_ja.arb index c8494661c6..3c06fdbe82 100644 --- a/mobile/lib/l10n/intl_ja.arb +++ b/mobile/lib/l10n/intl_ja.arb @@ -1,3 +1,5 @@ { - "@@locale ": "en" + "@@locale ": "en", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_km.arb b/mobile/lib/l10n/intl_km.arb index c8494661c6..3c06fdbe82 100644 --- a/mobile/lib/l10n/intl_km.arb +++ b/mobile/lib/l10n/intl_km.arb @@ -1,3 +1,5 @@ { - "@@locale ": "en" + "@@locale ": "en", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ko.arb b/mobile/lib/l10n/intl_ko.arb index 06c81195f7..f9e862d51f 100644 --- a/mobile/lib/l10n/intl_ko.arb +++ b/mobile/lib/l10n/intl_ko.arb @@ -12,5 +12,7 @@ "feedback": "피드백", "confirmAccountDeletion": "계정 삭제 확인", "deleteAccountPermanentlyButton": "계정을 영구적으로 삭제", - "yourAccountHasBeenDeleted": "계정이 삭제되었습니다." + "yourAccountHasBeenDeleted": "계정이 삭제되었습니다.", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_nl.arb b/mobile/lib/l10n/intl_nl.arb index 62dc45e844..d1db7d56d4 100644 --- a/mobile/lib/l10n/intl_nl.arb +++ b/mobile/lib/l10n/intl_nl.arb @@ -1313,5 +1313,7 @@ "cl_video_player_title": "Videospeler", "cl_video_player_description": "Een verfrissende nieuwe videospeler, met betere afspeelknoppen en ondersteuning voor HDR-video's.", "appLockDescriptions": "Kies tussen het standaard vergrendelscherm van uw apparaat en een aangepast vergrendelscherm met een pincode of wachtwoord.", - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Om appvergrendeling in te schakelen, moet u een toegangscode of schermvergrendeling instellen in uw systeeminstellingen." + "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Om appvergrendeling in te schakelen, moet u een toegangscode of schermvergrendeling instellen in uw systeeminstellingen.", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_no.arb b/mobile/lib/l10n/intl_no.arb index 9bf690cd30..cfc1df2fa9 100644 --- a/mobile/lib/l10n/intl_no.arb +++ b/mobile/lib/l10n/intl_no.arb @@ -373,5 +373,7 @@ "advanced": "Avansert", "general": "Generelt", "security": "Sikkerhet", - "authToViewYourRecoveryKey": "Vennligst autentiser deg for å se gjennopprettingsnøkkelen din" + "authToViewYourRecoveryKey": "Vennligst autentiser deg for å se gjennopprettingsnøkkelen din", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_pl.arb b/mobile/lib/l10n/intl_pl.arb index 7be752f684..cf4654be3a 100644 --- a/mobile/lib/l10n/intl_pl.arb +++ b/mobile/lib/l10n/intl_pl.arb @@ -1315,5 +1315,7 @@ "cl_video_player_description": "Wprowadzamy nowy odtwarzacz wideo z lepszym sterowaniem odtwarzania i obsługą wideo HDR.", "appLockDescriptions": "Wybierz między domyślnym ekranem blokady urządzenia a niestandardowym ekranem blokady z kodem PIN lub hasłem.", "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Aby włączyć blokadę aplikacji, należy skonfigurować hasło urządzenia lub blokadę ekranu w ustawieniach systemu.", - "authToViewPasskey": "Prosimy uwierzytelnić się, aby wyświetlić swój klucz dostępu" + "authToViewPasskey": "Prosimy uwierzytelnić się, aby wyświetlić swój klucz dostępu", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_pt.arb b/mobile/lib/l10n/intl_pt.arb index 0ca1ce69cd..b57fb95802 100644 --- a/mobile/lib/l10n/intl_pt.arb +++ b/mobile/lib/l10n/intl_pt.arb @@ -1315,5 +1315,7 @@ "cl_video_player_description": "Apresentando um novo reprodutor de vídeo, com melhores controles de reprodução e suporte para vídeos HDR.", "appLockDescriptions": "Escolha entre a tela de bloqueio padrão do seu dispositivo e uma tela de bloqueio personalizada com PIN ou senha.", "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Para ativar o bloqueio do app, configure uma senha no dispositivo ou tela de bloqueio nas configurações do sistema.", - "authToViewPasskey": "Por favor, autentique-se para ver sua chave de acesso" + "authToViewPasskey": "Por favor, autentique-se para ver sua chave de acesso", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ru.arb b/mobile/lib/l10n/intl_ru.arb index 2bf2d4efc1..a61e1bd024 100644 --- a/mobile/lib/l10n/intl_ru.arb +++ b/mobile/lib/l10n/intl_ru.arb @@ -1295,5 +1295,7 @@ "guestViewEnablePreSteps": "Чтобы включить гостевой вид, настройте пароль устройства или блокировку экрана в настройках системы.", "cl_guest_view_title": "Гостевой вид", "cl_panorama_viewer_title": "Просмотр Панорамы", - "cl_video_player_title": "Видеоплеер" + "cl_video_player_title": "Видеоплеер", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_sv.arb b/mobile/lib/l10n/intl_sv.arb index 3c51f175e0..89d190c136 100644 --- a/mobile/lib/l10n/intl_sv.arb +++ b/mobile/lib/l10n/intl_sv.arb @@ -423,5 +423,7 @@ "next": "Nästa", "guestView": "Gästvy", "cl_guest_view_title": "Gästvy", - "cl_video_player_title": "Videospelare" + "cl_video_player_title": "Videospelare", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_te.arb b/mobile/lib/l10n/intl_te.arb index c8494661c6..3c06fdbe82 100644 --- a/mobile/lib/l10n/intl_te.arb +++ b/mobile/lib/l10n/intl_te.arb @@ -1,3 +1,5 @@ { - "@@locale ": "en" + "@@locale ": "en", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_th.arb b/mobile/lib/l10n/intl_th.arb index 9d6b4c0801..a0c717ce17 100644 --- a/mobile/lib/l10n/intl_th.arb +++ b/mobile/lib/l10n/intl_th.arb @@ -297,5 +297,7 @@ "description": "Label for the map view" }, "maps": "แผนที่", - "enableMaps": "เปิดใช้งานแผนที่" + "enableMaps": "เปิดใช้งานแผนที่", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_ti.arb b/mobile/lib/l10n/intl_ti.arb index c8494661c6..3c06fdbe82 100644 --- a/mobile/lib/l10n/intl_ti.arb +++ b/mobile/lib/l10n/intl_ti.arb @@ -1,3 +1,5 @@ { - "@@locale ": "en" + "@@locale ": "en", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_tr.arb b/mobile/lib/l10n/intl_tr.arb index a51913a120..18c052eb7d 100644 --- a/mobile/lib/l10n/intl_tr.arb +++ b/mobile/lib/l10n/intl_tr.arb @@ -1168,5 +1168,7 @@ "invalidEndpoint": "Geçersiz uç nokta", "invalidEndpointMessage": "Üzgünüz, girdiğiniz uç nokta geçersiz. Lütfen geçerli bir uç nokta girin ve tekrar deneyin.", "endpointUpdatedMessage": "Fatura başarıyla güncellendi", - "customEndpoint": "{endpoint}'e bağlanıldı" + "customEndpoint": "{endpoint}'e bağlanıldı", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_zh.arb b/mobile/lib/l10n/intl_zh.arb index abb3a223ae..bacd3f7623 100644 --- a/mobile/lib/l10n/intl_zh.arb +++ b/mobile/lib/l10n/intl_zh.arb @@ -1315,5 +1315,7 @@ "cl_video_player_description": "推出全新的视频播放器,提供更好的播放控制并添加了对 HDR 视频的支持。", "appLockDescriptions": "在设备的默认锁定屏幕和带有 PIN 或密码的自定义锁定屏幕之间进行选择。", "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "要启用应用锁,请在系统设置中设置设备密码或屏幕锁。", - "authToViewPasskey": "请验证身份以查看您的通行密钥" + "authToViewPasskey": "请验证身份以查看您的通行密钥", + "loopVideoOn": "Loop video on", + "loopVideoOff": "Loop video off" } \ No newline at end of file diff --git a/mobile/lib/ui/viewer/file/file_app_bar.dart b/mobile/lib/ui/viewer/file/file_app_bar.dart index 9fb901af6e..a0905c16e6 100644 --- a/mobile/lib/ui/viewer/file/file_app_bar.dart +++ b/mobile/lib/ui/viewer/file/file_app_bar.dart @@ -334,8 +334,8 @@ class FileAppBarState extends State { padding: EdgeInsets.all(8), ), shouldLoopVideo - ? const Text("Loop video on") - : const Text("Loop video off"), + ? Text(S.of(context).loopVideoOn) + : Text(S.of(context).loopVideoOff), ], ), ), From e1f2a7dcf7799494b18e6f9a4835f2604d31a771 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Fri, 30 Aug 2024 18:50:48 +0530 Subject: [PATCH 144/275] [mob][photos] Improve play pause button in video player --- .../play_pause_button.dart | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/mobile/lib/ui/viewer/file/native_video_player_controls/play_pause_button.dart b/mobile/lib/ui/viewer/file/native_video_player_controls/play_pause_button.dart index 9e0f388bb4..887b98db47 100644 --- a/mobile/lib/ui/viewer/file/native_video_player_controls/play_pause_button.dart +++ b/mobile/lib/ui/viewer/file/native_video_player_controls/play_pause_button.dart @@ -1,9 +1,5 @@ -import "dart:async"; - import "package:flutter/material.dart"; import "package:native_video_player/native_video_player.dart"; -import "package:photos/core/event_bus.dart"; -import "package:photos/events/pause_video_event.dart"; import "package:photos/theme/colors.dart"; class PlayPauseButton extends StatefulWidget { @@ -15,22 +11,31 @@ class PlayPauseButton extends StatefulWidget { } class _PlayPauseButtonState extends State { - late StreamSubscription pauseVideoSubscription; bool _isPlaying = true; @override void initState() { super.initState(); - pauseVideoSubscription = Bus.instance.on().listen((event) { + widget.controller?.onPlaybackStatusChanged + .addListener(_onPlaybackStatusChanged); + } + + _onPlaybackStatusChanged() { + if (_playbackStatus == PlaybackStatus.playing) { + setState(() { + _isPlaying = true; + }); + } else { setState(() { _isPlaying = false; }); - }); + } } @override void dispose() { - pauseVideoSubscription.cancel(); + widget.controller?.onPlaybackStatusChanged + .removeListener(_onPlaybackStatusChanged); super.dispose(); } @@ -41,14 +46,8 @@ class _PlayPauseButtonState extends State { onTap: () { if (_playbackStatus == PlaybackStatus.playing) { widget.controller?.pause(); - setState(() { - _isPlaying = false; - }); } else { widget.controller?.play(); - setState(() { - _isPlaying = true; - }); } }, child: Container( From 4dc9ed643862b1d47f94a0b5097b11136558087f Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 30 Aug 2024 18:14:47 +0530 Subject: [PATCH 145/275] Don't overwrite submitting state --- web/apps/photos/src/pages/cluster-debug.tsx | 38 ++++++++------------ web/packages/new/photos/services/ml/index.ts | 2 +- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 127133b323..ddcc7b28b1 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -25,7 +25,7 @@ import { TextField, Typography, } from "@mui/material"; -import { useFormik } from "formik"; +import { useFormik, type Formik } from "formik"; import { useRouter } from "next/router"; import { AppContext } from "pages/_app"; import React, { useContext, useEffect, useMemo, useRef, useState } from "react"; @@ -90,11 +90,6 @@ interface ClusterListProps { const ClusterList: React.FC = ({ height, width }) => { const { startLoading, finishLoading } = useContext(AppContext); - const [clusteringOpts, setClusteringOpts] = useState({ - method: "hdbscan", - joinThreshold: 0.7, - batchSize: 2500, - }); const [clusterRes, setClusterRes] = useState< ClusterDebugPageContents | undefined >(); @@ -102,13 +97,21 @@ const ClusterList: React.FC = ({ height, width }) => { const listRef = useRef(null); const cluster = async (opts: ClusteringOpts) => { - setClusteringOpts(opts); setClusterRes(undefined); startLoading(); setClusterRes(await wipClusterDebugPageContents(opts)); finishLoading(); }; + const formik = useFormik({ + initialValues: { + method: "hdbscan", + joinThreshold: 0.7, + batchSize: 2500, + }, + onSubmit: cluster, + }); + const columns = useMemo( () => Math.max(Math.floor(getFractionFittableColumns(width)), 4), [width], @@ -145,11 +148,7 @@ const ClusterList: React.FC = ({ height, width }) => { if (index === 0) return (
-
+
); @@ -251,21 +250,12 @@ const ListItem = styled("div")` `; interface HeaderProps { - clusteringOpts: ClusteringOpts; + formik: Formik; clusterRes: ClusterDebugPageContents | undefined; - onCluster: (opts: ClusteringOpts) => Promise; } -const Header: React.FC = ({ - clusteringOpts, - clusterRes, - onCluster, -}) => { - const { values, handleSubmit, handleChange, isSubmitting } = useFormik({ - initialValues: clusteringOpts, - onSubmit: onCluster, - }); - +const Header: React.FC = ({ formik, clusterRes }) => { + const { values, handleSubmit, handleChange, isSubmitting } = formik; const form = ( diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 836eba693e..6f8bb91a49 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -374,7 +374,7 @@ export const wipClusterDebugPageContents = async ( ): Promise => { if (!(await wipClusterEnable())) throw new Error("Not implemented"); - log.info("clustering"); + log.info("clustering", opts); _wip_isClustering = true; _wip_searchPersons = undefined; triggerStatusUpdate(); From b7e67d4e2a8f3cadd303f2b589437a67b8ff4426 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 30 Aug 2024 19:11:51 +0530 Subject: [PATCH 146/275] Lint fix --- web/apps/photos/src/pages/cluster-debug.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index ddcc7b28b1..2cc97f4511 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -25,7 +25,7 @@ import { TextField, Typography, } from "@mui/material"; -import { useFormik, type Formik } from "formik"; +import { useFormik, type FormikContextType } from "formik"; import { useRouter } from "next/router"; import { AppContext } from "pages/_app"; import React, { useContext, useEffect, useMemo, useRef, useState } from "react"; @@ -250,7 +250,7 @@ const ListItem = styled("div")` `; interface HeaderProps { - formik: Formik; + formik: FormikContextType; clusterRes: ClusterDebugPageContents | undefined; } From 737e46a90e5b98bd550ad2c008952d56645aed67 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 30 Aug 2024 19:15:04 +0530 Subject: [PATCH 147/275] Use correct type --- web/apps/photos/src/pages/cluster-debug.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 2cc97f4511..225bd79780 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -25,7 +25,7 @@ import { TextField, Typography, } from "@mui/material"; -import { useFormik, type FormikContextType } from "formik"; +import { useFormik, type FormikProps } from "formik"; import { useRouter } from "next/router"; import { AppContext } from "pages/_app"; import React, { useContext, useEffect, useMemo, useRef, useState } from "react"; @@ -250,7 +250,7 @@ const ListItem = styled("div")` `; interface HeaderProps { - formik: FormikContextType; + formik: FormikProps; clusterRes: ClusterDebugPageContents | undefined; } From cb83f3592be432cd8489b09845b6fee16d827864 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Fri, 30 Aug 2024 19:37:28 +0530 Subject: [PATCH 148/275] [mob][photos] Use custom icon for 'loop video off' button --- mobile/lib/ui/viewer/file/file_app_bar.dart | 24 ++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/mobile/lib/ui/viewer/file/file_app_bar.dart b/mobile/lib/ui/viewer/file/file_app_bar.dart index a0905c16e6..04df35146c 100644 --- a/mobile/lib/ui/viewer/file/file_app_bar.dart +++ b/mobile/lib/ui/viewer/file/file_app_bar.dart @@ -326,9 +326,27 @@ class FileAppBarState extends State { value: 7, child: Row( children: [ - Icon( - Icons.repeat_rounded, - color: Theme.of(context).iconTheme.color, + Stack( + alignment: Alignment.center, + children: [ + Icon( + Icons.loop_rounded, + color: Theme.of(context).iconTheme.color, + ), + shouldLoopVideo + ? const SizedBox.shrink() + : Transform.rotate( + angle: (3.14 / 4) * 1, + child: Container( + width: 2, + height: 24, + decoration: BoxDecoration( + color: Theme.of(context).iconTheme.color, + borderRadius: BorderRadius.circular(1), + ), + ), + ), + ], ), const Padding( padding: EdgeInsets.all(8), From ccb0e5278d480538fc8912529780beea1d770c39 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 30 Aug 2024 19:58:55 +0530 Subject: [PATCH 149/275] Minscore --- web/apps/photos/src/pages/cluster-debug.tsx | 18 ++++++++++++++++++ web/packages/new/photos/services/ml/cluster.ts | 10 +++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 225bd79780..d0788500de 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -106,6 +106,8 @@ const ClusterList: React.FC = ({ height, width }) => { const formik = useFormik({ initialValues: { method: "hdbscan", + minBlur: 99, + minScore: 0, joinThreshold: 0.7, batchSize: 2500, }, @@ -276,6 +278,22 @@ const Header: React.FC = ({ formik, clusterRes }) => { ))} + + { - const { method, batchSize, joinThreshold } = opts; + const { method, batchSize, minBlur, minScore, joinThreshold } = opts; const t = Date.now(); // A flattened array of faces. - const faces = [...enumerateFaces(faceIndexes)].filter((f) => f.blur > 99); + const faces = [...enumerateFaces(faceIndexes)] + .filter((f) => f.blur > minBlur) + .filter((f) => f.score > minScore); // For fast reverse lookup - map from face ids to the face. const faceForFaceID = new Map(faces.map((f) => [f.faceID, f])); @@ -439,7 +443,7 @@ const clusterLinear = ( } } - // Prune singletone clusters. + // Prune singleton clusters. const validClusters = clusters.filter((cs) => cs.length > 1); return { clusters: validClusters }; From e4149fa55ef42fddef9db342a335031a2cc11954 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Fri, 30 Aug 2024 19:59:05 +0530 Subject: [PATCH 150/275] [mob][photos] Chore --- mobile/lib/ui/viewer/file/file_app_bar.dart | 2 +- .../play_pause_button.dart | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/mobile/lib/ui/viewer/file/file_app_bar.dart b/mobile/lib/ui/viewer/file/file_app_bar.dart index 04df35146c..8913790766 100644 --- a/mobile/lib/ui/viewer/file/file_app_bar.dart +++ b/mobile/lib/ui/viewer/file/file_app_bar.dart @@ -336,7 +336,7 @@ class FileAppBarState extends State { shouldLoopVideo ? const SizedBox.shrink() : Transform.rotate( - angle: (3.14 / 4) * 1, + angle: 3.14 / 4, child: Container( width: 2, height: 24, diff --git a/mobile/lib/ui/viewer/file/native_video_player_controls/play_pause_button.dart b/mobile/lib/ui/viewer/file/native_video_player_controls/play_pause_button.dart index 887b98db47..06a1d40708 100644 --- a/mobile/lib/ui/viewer/file/native_video_player_controls/play_pause_button.dart +++ b/mobile/lib/ui/viewer/file/native_video_player_controls/play_pause_button.dart @@ -20,18 +20,6 @@ class _PlayPauseButtonState extends State { .addListener(_onPlaybackStatusChanged); } - _onPlaybackStatusChanged() { - if (_playbackStatus == PlaybackStatus.playing) { - setState(() { - _isPlaying = true; - }); - } else { - setState(() { - _isPlaying = false; - }); - } - } - @override void dispose() { widget.controller?.onPlaybackStatusChanged @@ -88,4 +76,16 @@ class _PlayPauseButtonState extends State { PlaybackStatus? get _playbackStatus => widget.controller?.playbackInfo?.status; + + void _onPlaybackStatusChanged() { + if (_playbackStatus == PlaybackStatus.playing) { + setState(() { + _isPlaying = true; + }); + } else { + setState(() { + _isPlaying = false; + }); + } + } } From c147ec10673294e38554ac87930679e415e14e99 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 30 Aug 2024 20:53:47 +0530 Subject: [PATCH 151/275] Ensure nums There's a better way, just debugging code for now --- web/apps/photos/src/pages/cluster-debug.tsx | 190 ++++++++++++-------- 1 file changed, 118 insertions(+), 72 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index d0788500de..48162a8f1c 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -25,16 +25,39 @@ import { TextField, Typography, } from "@mui/material"; -import { useFormik, type FormikProps } from "formik"; +import { useFormik } from "formik"; import { useRouter } from "next/router"; import { AppContext } from "pages/_app"; -import React, { useContext, useEffect, useMemo, useRef, useState } from "react"; +import React, { + useCallback, + useContext, + useEffect, + useMemo, + useRef, + useState, +} from "react"; import AutoSizer from "react-virtualized-auto-sizer"; import { VariableSizeList } from "react-window"; // TODO-Cluster Temporary component for debugging export default function ClusterDebug() { - const { showNavBar } = useContext(AppContext); + const { startLoading, finishLoading, showNavBar } = useContext(AppContext); + + const [clusterRes, setClusterRes] = useState< + ClusterDebugPageContents | undefined + >(); + + const cluster = useCallback((opts: ClusteringOpts) => { + return new Promise((resolve) => { + setClusterRes(undefined); + startLoading(); + wipClusterDebugPageContents(opts).then((v) => { + setClusterRes(v); + finishLoading(); + resolve(true); + }); + }); + }, []); useEffect(() => { showNavBar(true); @@ -45,7 +68,10 @@ export default function ClusterDebug() { {({ height, width }) => ( - + )} @@ -82,43 +108,29 @@ const Container = styled("div")` } `; -interface ClusterListProps { - height: number; - width: number; -} - -const ClusterList: React.FC = ({ height, width }) => { - const { startLoading, finishLoading } = useContext(AppContext); - - const [clusterRes, setClusterRes] = useState< - ClusterDebugPageContents | undefined - >(); - const [items, setItems] = useState([]); - const listRef = useRef(null); - - const cluster = async (opts: ClusteringOpts) => { - setClusterRes(undefined); - startLoading(); - setClusterRes(await wipClusterDebugPageContents(opts)); - finishLoading(); +type ClusterListProps = Header1Props & + Header2Props & { + height: number; + width: number; }; - const formik = useFormik({ - initialValues: { - method: "hdbscan", - minBlur: 99, - minScore: 0, - joinThreshold: 0.7, - batchSize: 2500, - }, - onSubmit: cluster, - }); +const ClusterList: React.FC = ({ + width, + height, + onCluster, + clusterRes, +}) => { + const [items, setItems] = useState([]); + const listRef = useRef(null); const columns = useMemo( () => Math.max(Math.floor(getFractionFittableColumns(width)), 4), [width], ); + const Header1Memo = React.memo(Header1); + const Header2Memo = React.memo(Header2); + const shrinkRatio = getShrinkRatio(width, columns); const listItemHeight = 120 * shrinkRatio + 24 + 4; @@ -130,19 +142,25 @@ const ClusterList: React.FC = ({ height, width }) => { listRef.current?.resetAfterIndex(0); }, [items]); + const itemKey = (index: number) => + index === 0 || index === 1 ? `header-${index}` : `item-${index}`; + const getItemSize = (index: number) => index === 0 - ? 270 - : Array.isArray(items[index - 1]) - ? listItemHeight - : 36; + ? 140 + : index === 1 + ? 130 + : Array.isArray(items[index - 1 - 1]) + ? listItemHeight + : 36; return ( @@ -150,11 +168,18 @@ const ClusterList: React.FC = ({ height, width }) => { if (index === 0) return (
-
+
); - const item = items[index - 1]; + if (index === 1) + return ( +
+ +
+ ); + + const item = items[index - 2]; return ( ; - clusterRes: ClusterDebugPageContents | undefined; +interface Header1Props { + onCluster: (opts: ClusteringOpts) => Promise; } -const Header: React.FC = ({ formik, clusterRes }) => { - const { values, handleSubmit, handleChange, isSubmitting } = formik; - const form = ( +const Header1: React.FC = ({ onCluster }) => { + const toFloat = (n: number | string) => + typeof n == "string" ? parseFloat(n) : n; + const { values, handleSubmit, handleChange, isSubmitting } = + useFormik({ + initialValues: { + method: "linear", + minBlur: 10, + minScore: 0.8, + joinThreshold: 0.7, + batchSize: 12500, + }, + onSubmit: (values) => + onCluster({ + method: values.method, + minBlur: toFloat(values.minBlur), + minScore: toFloat(values.minScore), + joinThreshold: toFloat(values.joinThreshold), + batchSize: toFloat(values.batchSize), + }), + }); + + return ( Parameters @@ -316,38 +360,40 @@ const Header: React.FC = ({ formik, clusterRes }) => { Cluster + {isSubmitting && } ); +}; - const clusterInfo = clusterRes && ( - - - {`${clusterRes.clusters.length} clusters from ${clusterRes.clusteredFaceCount} faces in ${(clusterRes.timeTakenMs / 1000).toFixed(0)} seconds. ${clusterRes.unclusteredFaceCount} unclustered faces.`} - - - Showing only top 30 and bottom 30 clusters. - - - For each cluster showing only up to 50 faces, sorted by cosine - similarity to highest scoring face in the cluster. - - - Below each face is its{" "} - blur - score - cosineSimilarity - direction. - - - Faces added to the cluster as a result of merging are outlined. - - - ); +interface Header2Props { + clusterRes: ClusterDebugPageContents | undefined; +} +const Header2: React.FC = ({ clusterRes }) => { return ( -
- {form} - {isSubmitting && } - {clusterInfo} -
+ clusterRes && ( + + + {`${clusterRes.clusters.length} clusters from ${clusterRes.clusteredFaceCount} faces in ${(clusterRes.timeTakenMs / 1000).toFixed(0)} seconds. ${clusterRes.unclusteredFaceCount} unclustered faces.`} + + + Showing only top 30 and bottom 30 clusters. + + + For each cluster showing only up to 50 faces, sorted by + cosine similarity to highest scoring face in the cluster. + + + Below each face is its{" "} + blur - score - cosineSimilarity - direction. + + + Faces added to the cluster as a result of merging are + outlined. + + + ) ); }; From 0da8f45084af13d9011af840f88da78543fc916e Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 30 Aug 2024 21:09:42 +0530 Subject: [PATCH 152/275] Fix form reset --- web/apps/photos/src/pages/cluster-debug.tsx | 33 ++++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 48162a8f1c..65d66087fa 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -43,12 +43,20 @@ import { VariableSizeList } from "react-window"; export default function ClusterDebug() { const { startLoading, finishLoading, showNavBar } = useContext(AppContext); + const [clusteringOptions, setClusteringOptions] = useState({ + method: "linear", + minBlur: 10, + minScore: 0.8, + joinThreshold: 0.7, + batchSize: 12500, + }); const [clusterRes, setClusterRes] = useState< ClusterDebugPageContents | undefined >(); const cluster = useCallback((opts: ClusteringOpts) => { return new Promise((resolve) => { + setClusteringOptions(opts); setClusterRes(undefined); startLoading(); wipClusterDebugPageContents(opts).then((v) => { @@ -69,8 +77,13 @@ export default function ClusterDebug() { {({ height, width }) => ( )} @@ -117,6 +130,7 @@ type ClusterListProps = Header1Props & const ClusterList: React.FC = ({ width, height, + clusteringOptions, onCluster, clusterRes, }) => { @@ -168,7 +182,9 @@ const ClusterList: React.FC = ({ if (index === 0) return (
- +
); @@ -277,21 +293,16 @@ const ListItem = styled("div")` `; interface Header1Props { + clusteringOptions: ClusteringOpts; onCluster: (opts: ClusteringOpts) => Promise; } -const Header1: React.FC = ({ onCluster }) => { +const Header1: React.FC = ({ clusteringOptions, onCluster }) => { const toFloat = (n: number | string) => typeof n == "string" ? parseFloat(n) : n; const { values, handleSubmit, handleChange, isSubmitting } = useFormik({ - initialValues: { - method: "linear", - minBlur: 10, - minScore: 0.8, - joinThreshold: 0.7, - batchSize: 12500, - }, + initialValues: clusteringOptions, onSubmit: (values) => onCluster({ method: values.method, From 1e1ef7f94b689c043719e53b98078b72693a28d4 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Sat, 31 Aug 2024 07:22:48 +0530 Subject: [PATCH 153/275] Live photo changelog https://github.com/ente-io/ente/pull/2865 --- desktop/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/desktop/CHANGELOG.md b/desktop/CHANGELOG.md index 9a32cd383f..e55fa1e3e9 100644 --- a/desktop/CHANGELOG.md +++ b/desktop/CHANGELOG.md @@ -4,6 +4,7 @@ - Improved date search, including support for day of week and hour of day. - Fix video thumbnail generation and upload on Intel macOS. +- Club a photo and video into a live photo only if both are within 2 minutes. - . ## v1.7.3 From 854198f2156a607bbfcfaf3ac42e54e2ce14b238 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Sat, 31 Aug 2024 09:25:17 +0530 Subject: [PATCH 154/275] [web] Indicate that hash comparision is also used in the detail message Context: https://github.com/ente-io/ente/discussions/3070 --- web/packages/base/locales/en-US/translation.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/packages/base/locales/en-US/translation.json b/web/packages/base/locales/en-US/translation.json index 3adb4f3673..5585253915 100644 --- a/web/packages/base/locales/en-US/translation.json +++ b/web/packages/base/locales/en-US/translation.json @@ -301,7 +301,7 @@ "THUMBNAIL_GENERATION_FAILED_UPLOADS": "Thumbnail generation failed", "UNSUPPORTED_FILES": "Unsupported files", "SUCCESSFUL_UPLOADS": "Successful uploads", - "SKIPPED_INFO": "Skipped these as there are files with matching names in the same album", + "SKIPPED_INFO": "Skipped these as there are files with matching name and content in the same album", "UNSUPPORTED_INFO": "Ente does not support these file formats yet", "BLOCKED_UPLOADS": "Blocked uploads", "INPROGRESS_METADATA_EXTRACTION": "In progress", From 14a4398a14219ab87df3cc9e926f3cbd25eada8a Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Sat, 31 Aug 2024 09:45:43 +0530 Subject: [PATCH 155/275] Restructure to avoid unnecessary rerenders --- web/apps/photos/src/pages/cluster-debug.tsx | 242 ++++++++++---------- 1 file changed, 120 insertions(+), 122 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 65d66087fa..2ad6327b5f 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -43,24 +43,18 @@ import { VariableSizeList } from "react-window"; export default function ClusterDebug() { const { startLoading, finishLoading, showNavBar } = useContext(AppContext); - const [clusteringOptions, setClusteringOptions] = useState({ - method: "linear", - minBlur: 10, - minScore: 0.8, - joinThreshold: 0.7, - batchSize: 12500, - }); + const Header1Memo = React.memo(Header1); + const [clusterRes, setClusterRes] = useState< ClusterDebugPageContents | undefined >(); const cluster = useCallback((opts: ClusteringOpts) => { return new Promise((resolve) => { - setClusteringOptions(opts); - setClusterRes(undefined); startLoading(); - wipClusterDebugPageContents(opts).then((v) => { - setClusterRes(v); + // setClusterRes(undefined); + wipClusterDebugPageContents(opts).then((res) => { + setClusterRes(res); finishLoading(); resolve(true); }); @@ -71,20 +65,16 @@ export default function ClusterDebug() { showNavBar(true); }, []); + console.log("rendering Top", clusterRes); + return ( <> {({ height, width }) => ( - + + + )} @@ -121,18 +111,117 @@ const Container = styled("div")` } `; -type ClusterListProps = Header1Props & - Header2Props & { - height: number; - width: number; - }; +interface Header1Props { + onCluster: (opts: ClusteringOpts) => Promise; +} -const ClusterList: React.FC = ({ +const Header1: React.FC = ({ onCluster }) => { + const toFloat = (n: number | string) => + typeof n == "string" ? parseFloat(n) : n; + const { values, handleSubmit, handleChange, isSubmitting } = + useFormik({ + initialValues: { + method: "linear", + minBlur: 10, + minScore: 0.8, + joinThreshold: 0.7, + batchSize: 12500, + }, + // onSubmit1: (values) => { + // console.log("onSubmit"); + // return new Promise((resolve) => { + // console.log("onSubmit will resolve promise", { + // isSubmitting, + // }); + // setTimeout(resolve, 2000); + // }); + // }, + onSubmit: (values) => + onCluster({ + method: values.method, + minBlur: toFloat(values.minBlur), + minScore: toFloat(values.minScore), + joinThreshold: toFloat(values.joinThreshold), + batchSize: toFloat(values.batchSize), + }), + }); + + console.log("rendering form", { isSubmitting }); + + return ( +
+ + Parameters + + + {["hdbscan", "linear"].map((v) => ( + + {v} + + ))} + + + + + + + + + + {isSubmitting && } + +
+ ); +}; + +type ClusterListProps = Header2Props & { + height: number; + width: number; +}; + +const ClusterList: React.FC> = ({ width, height, - clusteringOptions, - onCluster, clusterRes, + children, }) => { const [items, setItems] = useState([]); const listRef = useRef(null); @@ -142,7 +231,6 @@ const ClusterList: React.FC = ({ [width], ); - const Header1Memo = React.memo(Header1); const Header2Memo = React.memo(Header2); const shrinkRatio = getShrinkRatio(width, columns); @@ -168,6 +256,8 @@ const ClusterList: React.FC = ({ ? listItemHeight : 36; + console.log("rendering Within AutoSizer", clusterRes, listRef); + return ( = ({ overscanCount={3} > {({ index, style }) => { - if (index === 0) - return ( -
- -
- ); + if (index === 0) return
{children}
; if (index === 1) return ( @@ -292,91 +375,6 @@ const ListItem = styled("div")` justify-content: center; `; -interface Header1Props { - clusteringOptions: ClusteringOpts; - onCluster: (opts: ClusteringOpts) => Promise; -} - -const Header1: React.FC = ({ clusteringOptions, onCluster }) => { - const toFloat = (n: number | string) => - typeof n == "string" ? parseFloat(n) : n; - const { values, handleSubmit, handleChange, isSubmitting } = - useFormik({ - initialValues: clusteringOptions, - onSubmit: (values) => - onCluster({ - method: values.method, - minBlur: toFloat(values.minBlur), - minScore: toFloat(values.minScore), - joinThreshold: toFloat(values.joinThreshold), - batchSize: toFloat(values.batchSize), - }), - }); - - return ( -
- - Parameters - - - {["hdbscan", "linear"].map((v) => ( - - {v} - - ))} - - - - - - - - - - {isSubmitting && } - -
- ); -}; - interface Header2Props { clusterRes: ClusterDebugPageContents | undefined; } From 067ba8ea85232aeed0539622c6c71bd51f0e9fb4 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Sat, 31 Aug 2024 10:37:56 +0530 Subject: [PATCH 156/275] Fix form rerendering The item renderer should not be defined inline otherwise it will get re-created each time the parent component (list) gets rerendered. https://github.com/bvaughn/react-window/issues/413#issuecomment-597876562 --- web/apps/photos/src/pages/cluster-debug.tsx | 105 ++++++++++---------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 2ad6327b5f..b20350147f 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -37,14 +37,12 @@ import React, { useState, } from "react"; import AutoSizer from "react-virtualized-auto-sizer"; -import { VariableSizeList } from "react-window"; +import { areEqual, VariableSizeList } from "react-window"; // TODO-Cluster Temporary component for debugging export default function ClusterDebug() { const { startLoading, finishLoading, showNavBar } = useContext(AppContext); - const Header1Memo = React.memo(Header1); - const [clusterRes, setClusterRes] = useState< ClusterDebugPageContents | undefined >(); @@ -52,7 +50,7 @@ export default function ClusterDebug() { const cluster = useCallback((opts: ClusteringOpts) => { return new Promise((resolve) => { startLoading(); - // setClusterRes(undefined); + setClusterRes(undefined); wipClusterDebugPageContents(opts).then((res) => { setClusterRes(res); finishLoading(); @@ -73,7 +71,9 @@ export default function ClusterDebug() { {({ height, width }) => ( - + + + )} @@ -127,15 +127,6 @@ const Header1: React.FC = ({ onCluster }) => { joinThreshold: 0.7, batchSize: 12500, }, - // onSubmit1: (values) => { - // console.log("onSubmit"); - // return new Promise((resolve) => { - // console.log("onSubmit will resolve promise", { - // isSubmitting, - // }); - // setTimeout(resolve, 2000); - // }); - // }, onSubmit: (values) => onCluster({ method: values.method, @@ -212,6 +203,21 @@ const Header1: React.FC = ({ onCluster }) => { ); }; +const Header1Memo = React.memo(Header1); + +const Row = React.memo( + (props) => { + const { style, children } = props; + console.log("Rendering row", props); + return
{children}
; + }, + // areEqual, + (...args) => { + console.log("areEqual called", args); + return true; + }, +); + type ClusterListProps = Header2Props & { height: number; width: number; @@ -231,8 +237,6 @@ const ClusterList: React.FC> = ({ [width], ); - const Header2Memo = React.memo(Header2); - const shrinkRatio = getShrinkRatio(width, columns); const listItemHeight = 120 * shrinkRatio + 24 + 4; @@ -244,9 +248,6 @@ const ClusterList: React.FC> = ({ listRef.current?.resetAfterIndex(0); }, [items]); - const itemKey = (index: number) => - index === 0 || index === 1 ? `header-${index}` : `item-${index}`; - const getItemSize = (index: number) => index === 0 ? 140 @@ -262,49 +263,45 @@ const ClusterList: React.FC> = ({ - {({ index, style }) => { - if (index === 0) return
{children}
; - - if (index === 1) - return ( -
- -
- ); - - const item = items[index - 2]; - return ( - - - {!Array.isArray(item) ? ( - - {item} - - ) : ( - item.map((f, i) => ( - - )) - )} - - - ); - }} + {DefineMeOutside}
); }; +const DefineMeOutside = React.memo(({ index, style, data }) => { + const { clusterRes, columns, shrinkRatio, items, children } = data; + + if (index === 0) return children; + + if (index === 1) + return ( +
+ +
+ ); + + const item = items[index - 2]; + return ( + + + {!Array.isArray(item) ? ( + {item} + ) : ( + item.map((f, i) => ( + + )) + )} + + + ); +}, areEqual); + type Item = string | FaceWithFile[]; const itemsFromClusterRes = ( @@ -406,6 +403,8 @@ const Header2: React.FC = ({ clusterRes }) => { ); }; +const Header2Memo = React.memo(Header2); + const Loader = () => ( From c3cfb7ae2f70a20d2ebb0c5812b450cc743dffd6 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Sat, 31 Aug 2024 11:09:07 +0530 Subject: [PATCH 157/275] Clean up --- web/apps/photos/src/pages/cluster-debug.tsx | 42 +++++++------------ .../new/photos/services/ml/cluster.ts | 3 +- 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index b20350147f..b253d061b4 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -49,8 +49,8 @@ export default function ClusterDebug() { const cluster = useCallback((opts: ClusteringOpts) => { return new Promise((resolve) => { - startLoading(); setClusterRes(undefined); + startLoading(); wipClusterDebugPageContents(opts).then((res) => { setClusterRes(res); finishLoading(); @@ -63,17 +63,13 @@ export default function ClusterDebug() { showNavBar(true); }, []); - console.log("rendering Top", clusterRes); - return ( <> {({ height, width }) => ( - - - + )} @@ -205,17 +201,9 @@ const Header1: React.FC = ({ onCluster }) => { const Header1Memo = React.memo(Header1); -const Row = React.memo( - (props) => { - const { style, children } = props; - console.log("Rendering row", props); - return
{children}
; - }, - // areEqual, - (...args) => { - console.log("areEqual called", args); - return true; - }, +const DivMemo = React.memo( + ({ style, children }) =>
{children}
, + areEqual, ); type ClusterListProps = Header2Props & { @@ -248,36 +236,36 @@ const ClusterList: React.FC> = ({ listRef.current?.resetAfterIndex(0); }, [items]); - const getItemSize = (index: number) => + const itemSize = (index: number) => index === 0 ? 140 : index === 1 ? 130 - : Array.isArray(items[index - 1 - 1]) + : Array.isArray(items[index - 2]) ? listItemHeight : 36; - console.log("rendering Within AutoSizer", clusterRes, listRef); - return ( - {DefineMeOutside} + {ClusterListItemRenderer} ); }; -const DefineMeOutside = React.memo(({ index, style, data }) => { +const ClusterListItemRenderer = React.memo(({ index, style, data }) => { const { clusterRes, columns, shrinkRatio, items, children } = data; - if (index === 0) return children; + if (index === 0) { + return {children}; + } if (index === 1) return ( diff --git a/web/packages/new/photos/services/ml/cluster.ts b/web/packages/new/photos/services/ml/cluster.ts index dad9e509c2..c39e0304c9 100644 --- a/web/packages/new/photos/services/ml/cluster.ts +++ b/web/packages/new/photos/services/ml/cluster.ts @@ -182,7 +182,8 @@ export const clusterFaces = ( // A flattened array of faces. const faces = [...enumerateFaces(faceIndexes)] .filter((f) => f.blur > minBlur) - .filter((f) => f.score > minScore); + .filter((f) => f.score > minScore) + .slice(0, 2000); // For fast reverse lookup - map from face ids to the face. const faceForFaceID = new Map(faces.map((f) => [f.faceID, f])); From 60cac291fff922d95faf75478d980d2d76155547 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Sat, 31 Aug 2024 11:13:23 +0530 Subject: [PATCH 158/275] Cleanup --- web/apps/photos/src/pages/cluster-debug.tsx | 30 +++++++-------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index b253d061b4..0595325458 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -28,14 +28,7 @@ import { import { useFormik } from "formik"; import { useRouter } from "next/router"; import { AppContext } from "pages/_app"; -import React, { - useCallback, - useContext, - useEffect, - useMemo, - useRef, - useState, -} from "react"; +import React, { useContext, useEffect, useMemo, useRef, useState } from "react"; import AutoSizer from "react-virtualized-auto-sizer"; import { areEqual, VariableSizeList } from "react-window"; @@ -47,17 +40,12 @@ export default function ClusterDebug() { ClusterDebugPageContents | undefined >(); - const cluster = useCallback((opts: ClusteringOpts) => { - return new Promise((resolve) => { - setClusterRes(undefined); - startLoading(); - wipClusterDebugPageContents(opts).then((res) => { - setClusterRes(res); - finishLoading(); - resolve(true); - }); - }); - }, []); + const cluster = async (opts: ClusteringOpts) => { + setClusterRes(undefined); + startLoading(); + setClusterRes(await wipClusterDebugPageContents(opts)); + finishLoading(); + }; useEffect(() => { showNavBar(true); @@ -69,7 +57,7 @@ export default function ClusterDebug() { {({ height, width }) => ( - + )} @@ -108,7 +96,7 @@ const Container = styled("div")` `; interface Header1Props { - onCluster: (opts: ClusteringOpts) => Promise; + onCluster: (opts: ClusteringOpts) => Promise; } const Header1: React.FC = ({ onCluster }) => { From cfcd41fc7eb22e3e8e3d43fb138830bbeb9c65d5 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Sat, 31 Aug 2024 11:26:48 +0530 Subject: [PATCH 159/275] Cleanup --- web/apps/photos/src/pages/cluster-debug.tsx | 170 ++++++++++---------- 1 file changed, 85 insertions(+), 85 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 0595325458..b5cd361fef 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -57,7 +57,7 @@ export default function ClusterDebug() { {({ height, width }) => ( - + )} @@ -95,11 +95,11 @@ const Container = styled("div")` } `; -interface Header1Props { +interface OptionsFormProps { onCluster: (opts: ClusteringOpts) => Promise; } -const Header1: React.FC = ({ onCluster }) => { +const OptionsForm: React.FC = ({ onCluster }) => { const toFloat = (n: number | string) => typeof n == "string" ? parseFloat(n) : n; const { values, handleSubmit, handleChange, isSubmitting } = @@ -187,14 +187,7 @@ const Header1: React.FC = ({ onCluster }) => { ); }; -const Header1Memo = React.memo(Header1); - -const DivMemo = React.memo( - ({ style, children }) =>
{children}
, - areEqual, -); - -type ClusterListProps = Header2Props & { +type ClusterListProps = ClusterResHeaderProps & { height: number; width: number; }; @@ -248,36 +241,6 @@ const ClusterList: React.FC> = ({ ); }; -const ClusterListItemRenderer = React.memo(({ index, style, data }) => { - const { clusterRes, columns, shrinkRatio, items, children } = data; - - if (index === 0) { - return {children}; - } - - if (index === 1) - return ( -
- -
- ); - - const item = items[index - 2]; - return ( - - - {!Array.isArray(item) ? ( - {item} - ) : ( - item.map((f, i) => ( - - )) - )} - - - ); -}, areEqual); - type Item = string | FaceWithFile[]; const itemsFromClusterRes = ( @@ -320,6 +283,87 @@ const getShrinkRatio = (width: number, columns: number) => (width - 2 * getGapFromScreenEdge(width) - (columns - 1) * 4) / (columns * 120); +const ClusterListItemRenderer = React.memo(({ index, style, data }) => { + const { clusterRes, columns, shrinkRatio, items, children } = data; + + if (index == 0) { + // It in necessary to memoize the div that contains the form otherwise + // the form loses its submitting state on unnecessary re-renders. + return {children}; + } + + if (index == 1) + return ( +
+ +
+ ); + + const item = items[index - 2]; + return ( + + + {!Array.isArray(item) ? ( + {item} + ) : ( + item.map((f, i) => ( + + )) + )} + + + ); +}, areEqual); + +const DivMemo = React.memo( + ({ style, children }) =>
{children}
, + areEqual, +); + +interface ClusterResHeaderProps { + clusterRes: ClusterDebugPageContents | undefined; +} + +const ClusterResHeader: React.FC = ({ clusterRes }) => { + if (!clusterRes) return null; + + const { clusteredFaceCount, unclusteredFaceCount, timeTakenMs, clusters } = + clusterRes; + + return ( + + + {`${clusters.length} clusters from ${clusteredFaceCount} faces in ${(timeTakenMs / 1000).toFixed(0)} seconds. ${unclusteredFaceCount} unclustered faces.`} + + + Showing only top 30 and bottom 30 clusters. + + + For each cluster showing only up to 50 faces, sorted by cosine + similarity to highest scoring face in the cluster. + + + Below each face is its{" "} + blur - score - cosineSimilarity - direction. + + + Faces added to the cluster as a result of merging are outlined. + + + ); +}; + +const Loader = () => ( + + + +); + +const ListItem = styled("div")` + display: flex; + justify-content: center; +`; + const ListContainer = styled(Box, { shouldForwardProp: (propName) => propName != "shrinkRatio", })<{ @@ -343,50 +387,6 @@ const LabelContainer = styled(ListItemContainer)` height: 32px; `; -const ListItem = styled("div")` - display: flex; - justify-content: center; -`; - -interface Header2Props { - clusterRes: ClusterDebugPageContents | undefined; -} - -const Header2: React.FC = ({ clusterRes }) => { - return ( - clusterRes && ( - - - {`${clusterRes.clusters.length} clusters from ${clusterRes.clusteredFaceCount} faces in ${(clusterRes.timeTakenMs / 1000).toFixed(0)} seconds. ${clusterRes.unclusteredFaceCount} unclustered faces.`} - - - Showing only top 30 and bottom 30 clusters. - - - For each cluster showing only up to 50 faces, sorted by - cosine similarity to highest scoring face in the cluster. - - - Below each face is its{" "} - blur - score - cosineSimilarity - direction. - - - Faces added to the cluster as a result of merging are - outlined. - - - ) - ); -}; - -const Header2Memo = React.memo(Header2); - -const Loader = () => ( - - - -); - interface FaceItemProps { faceWithFile: FaceWithFile; } From e36f081d96ac65ab9e276ff2cc5f96f0ef1cbdc1 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Sat, 31 Aug 2024 11:29:50 +0530 Subject: [PATCH 160/275] Cleanup --- web/apps/photos/src/pages/cluster-debug.tsx | 66 ++++++++++----------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index b5cd361fef..59d24b01ca 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -30,7 +30,11 @@ import { useRouter } from "next/router"; import { AppContext } from "pages/_app"; import React, { useContext, useEffect, useMemo, useRef, useState } from "react"; import AutoSizer from "react-virtualized-auto-sizer"; -import { areEqual, VariableSizeList } from "react-window"; +import { + areEqual, + VariableSizeList, + type ListChildComponentProps, +} from "react-window"; // TODO-Cluster Temporary component for debugging export default function ClusterDebug() { @@ -47,9 +51,7 @@ export default function ClusterDebug() { finishLoading(); }; - useEffect(() => { - showNavBar(true); - }, []); + useEffect(() => showNavBar(true), []); return ( <> @@ -283,40 +285,36 @@ const getShrinkRatio = (width: number, columns: number) => (width - 2 * getGapFromScreenEdge(width) - (columns - 1) * 4) / (columns * 120); -const ClusterListItemRenderer = React.memo(({ index, style, data }) => { - const { clusterRes, columns, shrinkRatio, items, children } = data; +// It in necessary to define the item renderer otherwise it gets recreated every +// time the parent rerenders, causing the form to lose its submitting state. +const ClusterListItemRenderer = React.memo( + ({ index, style, data }) => { + const { clusterRes, columns, shrinkRatio, items, children } = data; - if (index == 0) { - // It in necessary to memoize the div that contains the form otherwise - // the form loses its submitting state on unnecessary re-renders. - return {children}; - } + if (index == 0) return
{children}
; - if (index == 1) + if (index == 1) + return ( +
+ +
+ ); + + const item = items[index - 2]; return ( -
- -
+ + + {!Array.isArray(item) ? ( + {item} + ) : ( + item.map((f, i) => ( + + )) + )} + + ); - - const item = items[index - 2]; - return ( - - - {!Array.isArray(item) ? ( - {item} - ) : ( - item.map((f, i) => ( - - )) - )} - - - ); -}, areEqual); - -const DivMemo = React.memo( - ({ style, children }) =>
{children}
, + }, areEqual, ); From 1ec9dfea7f7a41cd1cdd22b7653c47b464cfd06d Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Sat, 31 Aug 2024 12:21:25 +0530 Subject: [PATCH 161/275] Equal sized buttons --- web/apps/photos/src/pages/cluster-debug.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 59d24b01ca..25dbc202a5 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -129,7 +129,11 @@ const OptionsForm: React.FC = ({ onCluster }) => {
Parameters - + Date: Sat, 31 Aug 2024 12:36:51 +0530 Subject: [PATCH 162/275] Without ID --- web/apps/photos/src/pages/cluster-debug.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 25dbc202a5..7f04c3ec0d 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -135,7 +135,6 @@ const OptionsForm: React.FC = ({ onCluster }) => { sx={{ ".MuiFormControl-root": { flex: "1" } }} > = ({ onCluster }) => { ))} = ({ onCluster }) => { onChange={handleChange} /> = ({ onCluster }) => { onChange={handleChange} /> = ({ onCluster }) => { onChange={handleChange} /> Date: Sat, 31 Aug 2024 13:01:06 +0530 Subject: [PATCH 163/275] More counts --- web/apps/photos/src/pages/cluster-debug.tsx | 18 +++++++++++++----- .../new/photos/services/ml/cluster.ts | 11 ++++++++--- web/packages/new/photos/services/ml/index.ts | 19 ++++++------------- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 7f04c3ec0d..ae2ea6b225 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -324,16 +324,23 @@ interface ClusterResHeaderProps { const ClusterResHeader: React.FC = ({ clusterRes }) => { if (!clusterRes) return null; - const { clusteredFaceCount, unclusteredFaceCount, timeTakenMs, clusters } = - clusterRes; + const { + totalFaceCount, + filteredFaceCount, + clusteredFaceCount, + unclusteredFaceCount, + timeTakenMs, + clusters, + } = clusterRes; return ( - {`${clusters.length} clusters from ${clusteredFaceCount} faces in ${(timeTakenMs / 1000).toFixed(0)} seconds. ${unclusteredFaceCount} unclustered faces.`} + {`${clusters.length} clusters in ${(timeTakenMs / 1000).toFixed(0)} seconds. Faces total ${totalFaceCount} filtered ${filteredFaceCount} clustered ${clusteredFaceCount} unclustered ${unclusteredFaceCount}.`} - Showing only top 30 and bottom 30 clusters. + Showing only top 30 clusters, bottom 30 clusters, and + unclustered faces. For each cluster showing only up to 50 faces, sorted by cosine @@ -344,7 +351,8 @@ const ClusterResHeader: React.FC = ({ clusterRes }) => { blur - score - cosineSimilarity - direction. - Faces added to the cluster as a result of merging are outlined. + Faces added to the cluster as a result of next batch merging are + outlined. ); diff --git a/web/packages/new/photos/services/ml/cluster.ts b/web/packages/new/photos/services/ml/cluster.ts index c39e0304c9..8d2607ff08 100644 --- a/web/packages/new/photos/services/ml/cluster.ts +++ b/web/packages/new/photos/services/ml/cluster.ts @@ -180,7 +180,8 @@ export const clusterFaces = ( const t = Date.now(); // A flattened array of faces. - const faces = [...enumerateFaces(faceIndexes)] + const allFaces = [...enumerateFaces(faceIndexes)]; + const faces = allFaces .filter((f) => f.blur > minBlur) .filter((f) => f.score > minScore) .slice(0, 2000); @@ -349,8 +350,10 @@ export const clusterFaces = ( }); } + const totalFaceCount = allFaces.length; + const filteredFaceCount = faces.length; const clusteredFaceCount = clusterIDForFaceID.size; - const unclusteredFaceCount = faces.length - clusteredFaceCount; + const unclusteredFaceCount = filteredFaceCount - clusteredFaceCount; const unclusteredFaces = faces.filter( ({ faceID }) => !clusterIDForFaceID.has(faceID), @@ -358,10 +361,12 @@ export const clusterFaces = ( const timeTakenMs = Date.now() - t; log.info( - `Clustered ${faces.length} faces into ${clusters.length} clusters, with ${faces.length - clusterIDForFaceID.size} faces remaining unclustered (${timeTakenMs} ms)`, + `Clustered ${faces.length} faces into ${clusters.length} clusters, ${faces.length - clusterIDForFaceID.size} faces remain unclustered (${timeTakenMs} ms)`, ); return { + totalFaceCount, + filteredFaceCount, clusteredFaceCount, unclusteredFaceCount, clusterPreviews, diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 6f8bb91a49..3bb6bb3eaf 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -358,15 +358,17 @@ export type ClusterPreviewFaceWithFile = ClusterPreviewFace & { }; export interface ClusterDebugPageContents { + totalFaceCount: number; + filteredFaceCount: number; clusteredFaceCount: number; unclusteredFaceCount: number; + timeTakenMs: number; clusters: FaceCluster[]; clusterPreviewsWithFile: ClusterPreviewWithFile[]; unclusteredFacesWithFile: { face: Face; enteFile: EnteFile; }[]; - timeTakenMs: number; } export const wipClusterDebugPageContents = async ( @@ -379,15 +381,8 @@ export const wipClusterDebugPageContents = async ( _wip_searchPersons = undefined; triggerStatusUpdate(); - const { - clusteredFaceCount, - unclusteredFaceCount, - clusterPreviews, - clusters, - cgroups, - unclusteredFaces, - timeTakenMs, - } = await worker().then((w) => w.clusterFaces(opts)); + const { clusterPreviews, clusters, cgroups, unclusteredFaces, ...rest } = + await worker().then((w) => w.clusterFaces(opts)); const localFiles = await getAllLocalFiles(); const localFileByID = new Map(localFiles.map((f) => [f.id, f])); @@ -441,12 +436,10 @@ export const wipClusterDebugPageContents = async ( triggerStatusUpdate(); return { - clusteredFaceCount, - unclusteredFaceCount, clusters, clusterPreviewsWithFile, unclusteredFacesWithFile, - timeTakenMs, + ...rest, }; }; From 72dc526724649826a023ff544cc569c438ae15e1 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Sat, 31 Aug 2024 13:29:24 +0530 Subject: [PATCH 164/275] Form tweaks --- web/apps/photos/src/pages/cluster-debug.tsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index ae2ea6b225..6337daffd1 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -102,8 +102,10 @@ interface OptionsFormProps { } const OptionsForm: React.FC = ({ onCluster }) => { + // Formik converts nums to a string on edit. const toFloat = (n: number | string) => typeof n == "string" ? parseFloat(n) : n; + const { values, handleSubmit, handleChange, isSubmitting } = useFormik({ initialValues: { @@ -123,8 +125,6 @@ const OptionsForm: React.FC = ({ onCluster }) => { }), }); - console.log("rendering form", { isSubmitting }); - return ( @@ -178,7 +178,11 @@ const OptionsForm: React.FC = ({ onCluster }) => { /> - @@ -335,8 +339,8 @@ const ClusterResHeader: React.FC = ({ clusterRes }) => { return ( - - {`${clusters.length} clusters in ${(timeTakenMs / 1000).toFixed(0)} seconds. Faces total ${totalFaceCount} filtered ${filteredFaceCount} clustered ${clusteredFaceCount} unclustered ${unclusteredFaceCount}.`} + + {`${clusters.length} clusters in ${(timeTakenMs / 1000).toFixed(0)} seconds • ${totalFaceCount} faces ${filteredFaceCount} filtered ${clusteredFaceCount} clustered ${unclusteredFaceCount} unclustered`} Showing only top 30 clusters, bottom 30 clusters, and From 7a7c8c02dec8f3797666812081908ea9e2bc81f0 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Sat, 31 Aug 2024 13:39:37 +0530 Subject: [PATCH 165/275] Remove debug code --- web/packages/new/photos/services/ml/cluster.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/packages/new/photos/services/ml/cluster.ts b/web/packages/new/photos/services/ml/cluster.ts index 8d2607ff08..271cd6d491 100644 --- a/web/packages/new/photos/services/ml/cluster.ts +++ b/web/packages/new/photos/services/ml/cluster.ts @@ -183,8 +183,8 @@ export const clusterFaces = ( const allFaces = [...enumerateFaces(faceIndexes)]; const faces = allFaces .filter((f) => f.blur > minBlur) - .filter((f) => f.score > minScore) - .slice(0, 2000); + .filter((f) => f.score > minScore); + // .slice(0, 2000); // For fast reverse lookup - map from face ids to the face. const faceForFaceID = new Map(faces.map((f) => [f.faceID, f])); From 22c5485b3bd2482303203fdc5b85cc0734a9e5ee Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Sat, 31 Aug 2024 15:43:18 +0530 Subject: [PATCH 166/275] [web] Make it more apparent what the create albums button does Change title of the button from "New album" to "Create albums" to indicate that it can be used to preserve albums. See: https://github.com/ente-io/ente/issues/3067 --- .../Collections/CollectionSelector/AddCollectionButton.tsx | 4 +--- web/packages/base/locales/en-US/translation.json | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/web/apps/photos/src/components/Collections/CollectionSelector/AddCollectionButton.tsx b/web/apps/photos/src/components/Collections/CollectionSelector/AddCollectionButton.tsx index 87e698361d..0b2245744c 100644 --- a/web/apps/photos/src/components/Collections/CollectionSelector/AddCollectionButton.tsx +++ b/web/apps/photos/src/components/Collections/CollectionSelector/AddCollectionButton.tsx @@ -23,9 +23,7 @@ export default function AddCollectionButton({ showNextModal }: Iprops) { onClick={() => showNextModal()} coverFile={null} > - - {t("CREATE_COLLECTION")} - + {t("create_albums")} + diff --git a/web/packages/base/locales/en-US/translation.json b/web/packages/base/locales/en-US/translation.json index 5585253915..2e984af93b 100644 --- a/web/packages/base/locales/en-US/translation.json +++ b/web/packages/base/locales/en-US/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "How did you hear about Ente? (optional)", "REFERRAL_INFO": "We don't track app installs, It'd help us if you told us where you found us!", "PASSPHRASE_MATCH_ERROR": "Passwords don't match", + "create_albums": "Create albums", "CREATE_COLLECTION": "New album", "ENTER_ALBUM_NAME": "Album name", "CLOSE_OPTION": "Close (Esc)", From 7dece286ec600cd3582e326c99e92e29b5786888 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Sat, 31 Aug 2024 10:18:47 +0000 Subject: [PATCH 167/275] New Crowdin translations by GitHub Action --- .../base/locales/ar-SA/translation.json | 357 +++++----- .../base/locales/bg-BG/translation.json | 1 + .../base/locales/ca-ES/translation.json | 1 + .../base/locales/de-DE/translation.json | 3 +- .../base/locales/el-GR/translation.json | 1 + .../base/locales/es-ES/translation.json | 3 +- .../base/locales/et-EE/translation.json | 1 + .../base/locales/fa-IR/translation.json | 1 + .../base/locales/fi-FI/translation.json | 1 + .../base/locales/fr-FR/translation.json | 3 +- .../base/locales/gu-IN/translation.json | 1 + .../base/locales/hi-IN/translation.json | 1 + .../base/locales/id-ID/translation.json | 1 + .../base/locales/is-IS/translation.json | 1 + .../base/locales/it-IT/translation.json | 1 + .../base/locales/ja-JP/translation.json | 1 + .../base/locales/km-KH/translation.json | 1 + .../base/locales/ko-KR/translation.json | 1 + .../base/locales/nl-NL/translation.json | 3 +- .../base/locales/pl-PL/translation.json | 3 +- .../base/locales/pt-BR/translation.json | 3 +- .../base/locales/pt-PT/translation.json | 1 + .../base/locales/ru-RU/translation.json | 3 +- .../base/locales/sv-SE/translation.json | 15 +- .../base/locales/ta-IN/translation.json | 659 ++++++++++++++++++ .../base/locales/te-IN/translation.json | 1 + .../base/locales/th-TH/translation.json | 1 + .../base/locales/ti-ER/translation.json | 1 + .../base/locales/tr-TR/translation.json | 1 + .../base/locales/zh-CN/translation.json | 5 +- 30 files changed, 882 insertions(+), 194 deletions(-) create mode 100644 web/packages/base/locales/ta-IN/translation.json diff --git a/web/packages/base/locales/ar-SA/translation.json b/web/packages/base/locales/ar-SA/translation.json index 968e1627bd..d4d7e31068 100644 --- a/web/packages/base/locales/ar-SA/translation.json +++ b/web/packages/base/locales/ar-SA/translation.json @@ -33,14 +33,15 @@ "ENTER_ENC_PASSPHRASE": "الرجاء إدخال كلمة المرور التي يمكننا استخدامها لتشفير بياناتك", "PASSPHRASE_DISCLAIMER": "نحن لا نخزن كلمة مرورك، لذا إذا نسيتها، لن نتمكن من مساعدتك في استرداد بياناتك دون مفتاح الاسترداد.", "WELCOME_TO_ENTE_HEADING": "مرحبا بك في ", - "WELCOME_TO_ENTE_SUBHEADING": "", - "WHERE_YOUR_BEST_PHOTOS_LIVE": "", + "WELCOME_TO_ENTE_SUBHEADING": "تخزين الصور ومشاركتها بشكل مشفر من طرف إلى طرف", + "WHERE_YOUR_BEST_PHOTOS_LIVE": "أين تعيش أفضل صورك", "KEY_GENERATION_IN_PROGRESS_MESSAGE": "جار توليد مفاتيح التشفير...", "PASSPHRASE_HINT": "كلمة المرور", "CONFIRM_PASSPHRASE": "تأكيد كلمة المرور", "REFERRAL_CODE_HINT": "كيف سمعت عن Ente؟ (اختياري)", - "REFERRAL_INFO": "", + "REFERRAL_INFO": "نحن لا نتتبع عمليات تثبيت التطبيق، سيكون من المفيد لنا أن تخبرنا أين وجدتنا!", "PASSPHRASE_MATCH_ERROR": "كلمات المرور غير متطابقة", + "create_albums": "", "CREATE_COLLECTION": "ألبوم جديد", "ENTER_ALBUM_NAME": "اسم الألبوم", "CLOSE_OPTION": "إغلاق (Esc)", @@ -58,10 +59,10 @@ "FILE_UPLOAD": "تحميل الملف", "UPLOAD_STAGE_MESSAGE": { "0": "الإعداد للتحميل", - "1": "", - "2": "", - "3": "", - "4": "", + "1": "قراءة ملفات بيانات تعريف جوجل", + "2": "{{uploadCounter.finished, number}} / {{uploadCounter.total, number}} البيانات الملفات الوصفية المستخرجة", + "3": "{{uploadCounter.finished, number}} / {{uploadCounter.total, number}} ملفات معالجة", + "4": "إلغاء التحميلات المتبقية", "5": "اكتمل النسخ الاحتياطي" }, "FILE_NOT_UPLOADED_LIST": "لم يتم تحميل الملفات التالية", @@ -71,227 +72,227 @@ "ACCOUNT_EXISTS": "لديك حساب بالفعل", "CREATE": "إنشاء", "DOWNLOAD": "تنزيل", - "DOWNLOAD_OPTION": "", - "DOWNLOAD_FAVORITES": "", - "DOWNLOAD_UNCATEGORIZED": "", - "DOWNLOAD_HIDDEN_ITEMS": "", - "COPY_OPTION": "", - "TOGGLE_FULLSCREEN": "", - "ZOOM_IN_OUT": "", - "PREVIOUS": "", - "NEXT": "", - "title_photos": "", - "title_auth": "", - "title_accounts": "", - "UPLOAD_FIRST_PHOTO": "", - "IMPORT_YOUR_FOLDERS": "", - "UPLOAD_DROPZONE_MESSAGE": "", + "DOWNLOAD_OPTION": "تنزيل (D)", + "DOWNLOAD_FAVORITES": "تنزيل المفضلات", + "DOWNLOAD_UNCATEGORIZED": "التنزيل غير المصنف", + "DOWNLOAD_HIDDEN_ITEMS": "تنزيل العناصر المخفية", + "COPY_OPTION": "نسخ كـ PNG (Ctrl/Cmd - C)", + "TOGGLE_FULLSCREEN": "تبديل ملء الشاشة (F)", + "ZOOM_IN_OUT": "تكبير/تصغير", + "PREVIOUS": "السابق (←)", + "NEXT": "التالي (→)", + "title_photos": "صور Ente", + "title_auth": "مصادقة Ente", + "title_accounts": "حسابات Ente", + "UPLOAD_FIRST_PHOTO": "تحميل صورتك الأولى", + "IMPORT_YOUR_FOLDERS": "استيراد مجلداتك", + "UPLOAD_DROPZONE_MESSAGE": "إسقاط للنسخ الاحتياطي للملفاتك", "WATCH_FOLDER_DROPZONE_MESSAGE": "", - "TRASH_FILES_TITLE": "", - "TRASH_FILE_TITLE": "", - "DELETE_FILES_TITLE": "", - "DELETE_FILES_MESSAGE": "", - "DELETE": "", - "DELETE_OPTION": "", - "FAVORITE_OPTION": "", - "UNFAVORITE_OPTION": "", - "MULTI_FOLDER_UPLOAD": "", - "UPLOAD_STRATEGY_CHOICE": "", - "UPLOAD_STRATEGY_SINGLE_COLLECTION": "", - "OR": "", - "UPLOAD_STRATEGY_COLLECTION_PER_FOLDER": "", - "SESSION_EXPIRED_MESSAGE": "", - "SESSION_EXPIRED": "", - "PASSWORD_GENERATION_FAILED": "", - "CHANGE_PASSWORD": "", - "password_changed_elsewhere": "", - "password_changed_elsewhere_message": "", - "GO_BACK": "", - "RECOVERY_KEY": "", - "SAVE_LATER": "", - "SAVE": "", + "TRASH_FILES_TITLE": "حذف الملفات؟", + "TRASH_FILE_TITLE": "حذف الملف؟", + "DELETE_FILES_TITLE": "حذف فورا؟", + "DELETE_FILES_MESSAGE": "سيتم حذف الملفات المحددة نهائيا من حساب Ente الخاص بك.", + "DELETE": "حذف", + "DELETE_OPTION": "حذف (DEL)", + "FAVORITE_OPTION": "مفضلة (L)", + "UNFAVORITE_OPTION": "غير مفضلة (L)", + "MULTI_FOLDER_UPLOAD": "تم اكتشاف مجلدات متعددة", + "UPLOAD_STRATEGY_CHOICE": "هل ترغب في تحميلهم إلى", + "UPLOAD_STRATEGY_SINGLE_COLLECTION": "ألبوم واحد", + "OR": "أو", + "UPLOAD_STRATEGY_COLLECTION_PER_FOLDER": "ألبومات منفصلة", + "SESSION_EXPIRED_MESSAGE": "لقد انتهت صلاحية جلستك، يرجى تسجيل الدخول مرة أخرى للمتابعة", + "SESSION_EXPIRED": "انتهت صلاحية الجلسة", + "PASSWORD_GENERATION_FAILED": "لم يتمكن متصفحك من إنشاء مفتاح قوي يفي بمعايير تشفير Ente، يرجى المحاولة باستخدام تطبيق الهاتف المحمول أو متصفح آخر", + "CHANGE_PASSWORD": "تغيير كلمة المرور", + "password_changed_elsewhere": "تم تغيير كلمة المرور في مكان آخر", + "password_changed_elsewhere_message": "يرجى تسجيل الدخول مرة أخرى على هذا الجهاز لاستخدام كلمة المرور الجديدة للمصادقة.", + "GO_BACK": "رجوع", + "RECOVERY_KEY": "مفتاح الاستعادة", + "SAVE_LATER": "قم بهذا لاحقا", + "SAVE": "حفظ المفتاح", "RECOVERY_KEY_DESCRIPTION": "", "RECOVER_KEY_GENERATION_FAILED": "", "KEY_NOT_STORED_DISCLAIMER": "", - "FORGOT_PASSWORD": "", - "RECOVER_ACCOUNT": "", - "RECOVERY_KEY_HINT": "", - "RECOVER": "", - "NO_RECOVERY_KEY": "", - "INCORRECT_RECOVERY_KEY": "", - "SORRY": "", + "FORGOT_PASSWORD": "نسيت كلمة المرور", + "RECOVER_ACCOUNT": "إستعادة الحساب", + "RECOVERY_KEY_HINT": "مفتاح الاستعادة", + "RECOVER": "استعادة", + "NO_RECOVERY_KEY": "ما من مفتاح استعادة؟", + "INCORRECT_RECOVERY_KEY": "مفتاح استعادة غير صحيح", + "SORRY": "عذرا", "NO_RECOVERY_KEY_MESSAGE": "", "NO_TWO_FACTOR_RECOVERY_KEY_MESSAGE": "", - "CONTACT_SUPPORT": "", - "REQUEST_FEATURE": "", - "SUPPORT": "", - "CONFIRM": "", - "cancel": "", - "LOGOUT": "", - "delete_account": "", + "CONTACT_SUPPORT": "الاتصال بالدعم", + "REQUEST_FEATURE": "طلب ميزة", + "SUPPORT": "الدعم", + "CONFIRM": "تأكيد", + "cancel": "إلغاء", + "LOGOUT": "تسجيل الخروج", + "delete_account": "حذف الحساب", "delete_account_manually_message": "", - "LOGOUT_MESSAGE": "", - "CHANGE_EMAIL": "", - "OK": "", - "SUCCESS": "", - "ERROR": "", - "MESSAGE": "", + "LOGOUT_MESSAGE": "هل أنت متأكد من أنك تريد تسجيل الخروج؟", + "CHANGE_EMAIL": "تغيير البريد الإلكتروني", + "OK": "حسنا", + "SUCCESS": "تم بنجاح", + "ERROR": "خطأ", + "MESSAGE": "رسالة", "OFFLINE_MSG": "", "INSTALL_MOBILE_APP": "", "DOWNLOAD_APP_MESSAGE": "", - "DOWNLOAD_APP": "", - "EXPORT": "", - "SUBSCRIPTION": "", - "SUBSCRIBE": "", - "MANAGEMENT_PORTAL": "", - "MANAGE_FAMILY_PORTAL": "", - "LEAVE_FAMILY_PLAN": "", - "LEAVE": "", - "LEAVE_FAMILY_CONFIRM": "", - "CHOOSE_PLAN": "", - "MANAGE_PLAN": "", - "CURRENT_USAGE": "", - "TWO_MONTHS_FREE": "", - "POPULAR": "", - "free_plan_option": "", - "free_plan_description": "", - "active": "", - "subscription_info_free": "", + "DOWNLOAD_APP": "تنزيل تطبيق سطح المكتب", + "EXPORT": "تصدير البيانات", + "SUBSCRIPTION": "اشتراك", + "SUBSCRIBE": "اشترك", + "MANAGEMENT_PORTAL": "إدارة طريقة الدفع", + "MANAGE_FAMILY_PORTAL": "إدارة العائلة", + "LEAVE_FAMILY_PLAN": "مغادرة خطة العائلة", + "LEAVE": "مغادرة", + "LEAVE_FAMILY_CONFIRM": "هل أنت متأكد من أنك تريد مغادرة الخطة العائلية؟", + "CHOOSE_PLAN": "اختر خطتك", + "MANAGE_PLAN": "إدارة اشتراكك", + "CURRENT_USAGE": "الاستخدام الحالي هو {{usage}}", + "TWO_MONTHS_FREE": "احصل على شهرين مجانا في الخطط السنوية", + "POPULAR": "رائج", + "free_plan_option": "المتابعة مع الخطة المجانية", + "free_plan_description": "{{storage}} مجاني للأبد", + "active": "نشط", + "subscription_info_free": "أنت في الخطة المجانية", "subscription_info_family": "", "subscription_info_expired": "", "subscription_info_renewal_cancelled": "", "subscription_info_storage_quota_exceeded": "", "subscription_status_renewal_active": "", - "subscription_status_renewal_cancelled": "", + "subscription_status_renewal_cancelled": "ينتهي في {{date, date}}", "add_on_valid_till": "", - "subscription_expired": "", - "storage_quota_exceeded": "", - "SUBSCRIPTION_PURCHASE_SUCCESS": "", + "subscription_expired": "إنتهت صلاحية الاشتراك", + "storage_quota_exceeded": "تم تجاوز حد التخزين", + "SUBSCRIPTION_PURCHASE_SUCCESS": "

لقد تلقينا دفعتك

اشتراكك صالح حتى {{date, date}}

", "SUBSCRIPTION_PURCHASE_CANCELLED": "", "SUBSCRIPTION_PURCHASE_FAILED": "", "SUBSCRIPTION_UPDATE_FAILED": "", "UPDATE_PAYMENT_METHOD_MESSAGE": "", "STRIPE_AUTHENTICATION_FAILED": "", "UPDATE_PAYMENT_METHOD": "", - "MONTHLY": "", - "YEARLY": "", - "MONTH_SHORT": "", - "YEAR": "", - "update_subscription_title": "", - "UPDATE_SUBSCRIPTION_MESSAGE": "", - "UPDATE_SUBSCRIPTION": "", - "CANCEL_SUBSCRIPTION": "", + "MONTHLY": "شهريا", + "YEARLY": "سنويا", + "MONTH_SHORT": "شهر", + "YEAR": "سنة", + "update_subscription_title": "تأكيد تغيير الخطة", + "UPDATE_SUBSCRIPTION_MESSAGE": "هل أنت متأكد من أنك تريد تغيير خطتك؟", + "UPDATE_SUBSCRIPTION": "تغيير الخطة", + "CANCEL_SUBSCRIPTION": "إلغاء الاشتراك", "CANCEL_SUBSCRIPTION_MESSAGE": "", "CANCEL_SUBSCRIPTION_WITH_ADDON_MESSAGE": "", - "SUBSCRIPTION_CANCEL_FAILED": "", - "SUBSCRIPTION_CANCEL_SUCCESS": "", - "REACTIVATE_SUBSCRIPTION": "", + "SUBSCRIPTION_CANCEL_FAILED": "فشل في إلغاء الاشتراك", + "SUBSCRIPTION_CANCEL_SUCCESS": "تم إلغاء الاشتراك بنجاح", + "REACTIVATE_SUBSCRIPTION": "إعادة تنشيط الاشتراك", "REACTIVATE_SUBSCRIPTION_MESSAGE": "", "SUBSCRIPTION_ACTIVATE_SUCCESS": "", "SUBSCRIPTION_ACTIVATE_FAILED": "", - "SUBSCRIPTION_PURCHASE_SUCCESS_TITLE": "", + "SUBSCRIPTION_PURCHASE_SUCCESS_TITLE": "شكرا لك", "CANCEL_SUBSCRIPTION_ON_MOBILE": "", "CANCEL_SUBSCRIPTION_ON_MOBILE_MESSAGE": "", "MAIL_TO_MANAGE_SUBSCRIPTION": "", - "RENAME": "", - "RENAME_FILE": "", - "RENAME_COLLECTION": "", - "DELETE_COLLECTION_TITLE": "", - "DELETE_COLLECTION": "", + "RENAME": "اعادة تسمية", + "RENAME_FILE": "إعادة تسمية ملف", + "RENAME_COLLECTION": "إعادة تسمية ألبوم", + "DELETE_COLLECTION_TITLE": "حذف ألبوم؟", + "DELETE_COLLECTION": "حذف ألبوم", "DELETE_COLLECTION_MESSAGE": "", - "DELETE_PHOTOS": "", - "KEEP_PHOTOS": "", - "SHARE_COLLECTION": "", - "SHARE_WITH_SELF": "", + "DELETE_PHOTOS": "حذف الصور", + "KEEP_PHOTOS": "الاحتفاظ بالصور", + "SHARE_COLLECTION": "مشاركة الألبوم", + "SHARE_WITH_SELF": "عفوا، لا يمكنك المشاركة مع نفسك", "ALREADY_SHARED": "", - "SHARING_BAD_REQUEST_ERROR": "", - "SHARING_DISABLED_FOR_FREE_ACCOUNTS": "", - "DOWNLOAD_COLLECTION": "", + "SHARING_BAD_REQUEST_ERROR": "لا يسمح بمشاركة الألبوم", + "SHARING_DISABLED_FOR_FREE_ACCOUNTS": "المشاركة معطلة للحسابات المجانية", + "DOWNLOAD_COLLECTION": "تنزيل الألبوم", "CREATE_ALBUM_FAILED": "", - "SEARCH": "", - "SEARCH_RESULTS": "", - "NO_RESULTS": "", - "SEARCH_HINT": "", + "SEARCH": "بحث", + "SEARCH_RESULTS": "نتائج البحث", + "NO_RESULTS": "لا توجد نتائج", + "SEARCH_HINT": "البحث عن الألبومات، التواريخ، والأوصاف...", "SEARCH_TYPE": { - "COLLECTION": "", - "LOCATION": "", - "CITY": "", - "DATE": "", - "FILE_NAME": "", - "THING": "", - "FILE_CAPTION": "", - "FILE_TYPE": "", - "CLIP": "" + "COLLECTION": "ألبوم", + "LOCATION": "الموقع", + "CITY": "الموقع", + "DATE": "تاريخ", + "FILE_NAME": "إسم الملف", + "THING": "المحتوى", + "FILE_CAPTION": "وصف", + "FILE_TYPE": "نوع الملف", + "CLIP": "سحر" }, - "photos_count_zero": "", - "photos_count_one": "", - "photos_count": "", - "TERMS_AND_CONDITIONS": "", - "ADD_TO_COLLECTION": "", - "SELECTED": "", + "photos_count_zero": "لا توجد ذكريات", + "photos_count_one": "ذكرى واحدة", + "photos_count": "{{count, number}} ذكريات", + "TERMS_AND_CONDITIONS": "أوافق على
شروط الخدمة وسياسة الخصوصية", + "ADD_TO_COLLECTION": "إضافة إلى الألبوم", + "SELECTED": "محدد", "PEOPLE": "", - "indexing_scheduled": "", + "indexing_scheduled": "الفهرسة مجدولة...", "indexing_photos": "", "indexing_fetching": "", "indexing_people": "", "indexing_done": "", - "UNIDENTIFIED_FACES": "", + "UNIDENTIFIED_FACES": "وجوه غير محددة", "OBJECTS": "", - "TEXT": "", - "INFO": "", - "INFO_OPTION": "", - "FILE_NAME": "", - "CAPTION_PLACEHOLDER": "", - "LOCATION": "", - "SHOW_ON_MAP": "", - "MAP": "", - "MAP_SETTINGS": "", - "ENABLE_MAPS": "", - "ENABLE_MAP": "", - "DISABLE_MAPS": "", + "TEXT": "نص", + "INFO": "معلومات ", + "INFO_OPTION": "معلومات (I)", + "FILE_NAME": "إسم الملف", + "CAPTION_PLACEHOLDER": "إضافة وصف", + "LOCATION": "الموقع", + "SHOW_ON_MAP": "عرض على OpenStreetMap", + "MAP": "خريطة", + "MAP_SETTINGS": "إعدادات الخريطة", + "ENABLE_MAPS": "تمكين الخرائط ؟", + "ENABLE_MAP": "تمكين الخريطة", + "DISABLE_MAPS": "تعطيل الخرائط؟", "ENABLE_MAP_DESCRIPTION": "", "DISABLE_MAP_DESCRIPTION": "", - "DISABLE_MAP": "", - "DETAILS": "", - "view_exif": "", - "no_exif": "", - "exif": "", - "ISO": "", + "DISABLE_MAP": "تعطيل الخريطة", + "DETAILS": "تفاصيل", + "view_exif": "عرض جميع بيانات Exif", + "no_exif": "لا توجد بيانات Exif", + "exif": "Exif", + "ISO": "ISO", "TWO_FACTOR": "", - "TWO_FACTOR_AUTHENTICATION": "", + "TWO_FACTOR_AUTHENTICATION": "المصادقة الثنائية", "TWO_FACTOR_QR_INSTRUCTION": "", - "ENTER_CODE_MANUALLY": "", + "ENTER_CODE_MANUALLY": "أدخل الرمز يدويا", "TWO_FACTOR_MANUAL_CODE_INSTRUCTION": "", - "SCAN_QR_CODE": "", + "SCAN_QR_CODE": "مسح رمز QR بدلاً من ذلك", "ENABLE_TWO_FACTOR": "", - "enable": "", - "enabled": "", + "enable": "تفعيل", + "enabled": "مفعل", "LOST_DEVICE": "", - "INCORRECT_CODE": "", + "INCORRECT_CODE": "رمز غير صحيح", "TWO_FACTOR_INFO": "", "DISABLE_TWO_FACTOR_LABEL": "", "UPDATE_TWO_FACTOR_LABEL": "", - "disable": "", - "reconfigure": "", + "disable": "تعطيل", + "reconfigure": "إعادة التهيئة", "UPDATE_TWO_FACTOR": "", "UPDATE_TWO_FACTOR_MESSAGE": "", - "UPDATE": "", + "UPDATE": "تحديث", "DISABLE_TWO_FACTOR": "", "DISABLE_TWO_FACTOR_MESSAGE": "", "TWO_FACTOR_DISABLE_FAILED": "", - "EXPORT_DATA": "", + "EXPORT_DATA": "تصدير البيانات", "select_folder": "", "select_zips": "", - "faq": "", + "faq": "الأسئلة الشائعة", "takeout_hint": "", - "DESTINATION": "", - "START": "", - "LAST_EXPORT_TIME": "", + "DESTINATION": "الوجهة", + "START": "بدء", + "LAST_EXPORT_TIME": "آخر وقت تصدير", "EXPORT_AGAIN": "", - "LOCAL_STORAGE_NOT_ACCESSIBLE": "", + "LOCAL_STORAGE_NOT_ACCESSIBLE": "التخزين المحلي غير قابل للوصول", "LOCAL_STORAGE_NOT_ACCESSIBLE_MESSAGE": "", "SEND_OTT": "", - "EMAIl_ALREADY_OWNED": "", + "EMAIl_ALREADY_OWNED": "البريد الإلكتروني مأخوذ بالفعل", "ETAGS_BLOCKED": "", "LIVE_PHOTOS_DETECTED": "", "RETRY_FAILED": "", @@ -321,22 +322,22 @@ "MOVE_TO_COLLECTION": "", "UNARCHIVE": "", "UNARCHIVE_COLLECTION": "", - "HIDE_COLLECTION": "", - "UNHIDE_COLLECTION": "", - "MOVE": "", - "ADD": "", - "REMOVE": "", - "YES_REMOVE": "", + "HIDE_COLLECTION": "إخفاء الألبوم", + "UNHIDE_COLLECTION": "إلغاء إخفاء الألبوم", + "MOVE": "نقل", + "ADD": "إضافة", + "REMOVE": "ازالة", + "YES_REMOVE": "نعم، إزالة", "REMOVE_FROM_COLLECTION": "", - "TRASH": "", - "MOVE_TO_TRASH": "", + "TRASH": "سلة المهملات", + "MOVE_TO_TRASH": "نقل إلى سلة المهملات", "TRASH_FILES_MESSAGE": "", "TRASH_FILE_MESSAGE": "", - "DELETE_PERMANENTLY": "", - "RESTORE": "", + "DELETE_PERMANENTLY": "حذف بشكل دائم", + "RESTORE": "استعادة", "RESTORE_TO_COLLECTION": "", - "EMPTY_TRASH": "", - "EMPTY_TRASH_TITLE": "", + "EMPTY_TRASH": "إفراغ سلة المهملات", + "EMPTY_TRASH_TITLE": "إفراغ سلة المهملات؟", "EMPTY_TRASH_MESSAGE": "", "LEAVE_SHARED_ALBUM": "", "LEAVE_ALBUM": "", diff --git a/web/packages/base/locales/bg-BG/translation.json b/web/packages/base/locales/bg-BG/translation.json index 7df973eb83..787567c446 100644 --- a/web/packages/base/locales/bg-BG/translation.json +++ b/web/packages/base/locales/bg-BG/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "", "REFERRAL_INFO": "", "PASSPHRASE_MATCH_ERROR": "", + "create_albums": "", "CREATE_COLLECTION": "", "ENTER_ALBUM_NAME": "", "CLOSE_OPTION": "", diff --git a/web/packages/base/locales/ca-ES/translation.json b/web/packages/base/locales/ca-ES/translation.json index 2f7b02d9ee..f90267b710 100644 --- a/web/packages/base/locales/ca-ES/translation.json +++ b/web/packages/base/locales/ca-ES/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "", "REFERRAL_INFO": "", "PASSPHRASE_MATCH_ERROR": "", + "create_albums": "", "CREATE_COLLECTION": "", "ENTER_ALBUM_NAME": "", "CLOSE_OPTION": "", diff --git a/web/packages/base/locales/de-DE/translation.json b/web/packages/base/locales/de-DE/translation.json index 6c83a4dd72..fdad284a60 100644 --- a/web/packages/base/locales/de-DE/translation.json +++ b/web/packages/base/locales/de-DE/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "Wie hast du von Ente erfahren? (optional)", "REFERRAL_INFO": "Wir tracken keine App-Installationen. Es würde uns jedoch helfen, wenn du uns mitteilst, wie du von uns erfahren hast!", "PASSPHRASE_MATCH_ERROR": "Die Passwörter stimmen nicht überein", + "create_albums": "", "CREATE_COLLECTION": "Neues Album", "ENTER_ALBUM_NAME": "Albumname", "CLOSE_OPTION": "Schließen (Esc)", @@ -301,7 +302,7 @@ "THUMBNAIL_GENERATION_FAILED_UPLOADS": "Das Vorschaubild konnte nicht erzeugt werden", "UNSUPPORTED_FILES": "Nicht unterstützte Dateien", "SUCCESSFUL_UPLOADS": "Erfolgreiche Uploads", - "SKIPPED_INFO": "Diese wurden übersprungen, da es Dateien mit gleichen Namen im selben Album gibt", + "SKIPPED_INFO": "", "UNSUPPORTED_INFO": "Ente unterstützt diese Dateiformate noch nicht", "BLOCKED_UPLOADS": "Blockierte Uploads", "INPROGRESS_METADATA_EXTRACTION": "In Bearbeitung", diff --git a/web/packages/base/locales/el-GR/translation.json b/web/packages/base/locales/el-GR/translation.json index 5f93899450..9ecc3b137f 100644 --- a/web/packages/base/locales/el-GR/translation.json +++ b/web/packages/base/locales/el-GR/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "Πώς ακούσατε για το Ente; (προαιρετικό)", "REFERRAL_INFO": "Δεν παρακολουθούμε τις εγκαταστάσεις εφαρμογών. Θα μας βοηθούσε αν μας λέγατε που μας βρήκατε!", "PASSPHRASE_MATCH_ERROR": "Οι κωδικοί πρόσβασης δεν ταιριάζουν", + "create_albums": "", "CREATE_COLLECTION": "Νέο άλμπουμ", "ENTER_ALBUM_NAME": "Όνομα άλμπουμ", "CLOSE_OPTION": "Κλείσιμο (Esc)", diff --git a/web/packages/base/locales/es-ES/translation.json b/web/packages/base/locales/es-ES/translation.json index 6fee153eb7..3254dc154c 100644 --- a/web/packages/base/locales/es-ES/translation.json +++ b/web/packages/base/locales/es-ES/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "¿Cómo escuchaste acerca de Ente? (opcional)", "REFERRAL_INFO": "", "PASSPHRASE_MATCH_ERROR": "Las contraseñas no coinciden", + "create_albums": "", "CREATE_COLLECTION": "Nuevo álbum", "ENTER_ALBUM_NAME": "Nombre del álbum", "CLOSE_OPTION": "Cerrar (Esc)", @@ -301,7 +302,7 @@ "THUMBNAIL_GENERATION_FAILED_UPLOADS": "Generación de miniaturas fallida", "UNSUPPORTED_FILES": "Archivos no soportados", "SUCCESSFUL_UPLOADS": "Subidas exitosas", - "SKIPPED_INFO": "Se han omitido ya que hay archivos con nombres coincidentes en el mismo álbum", + "SKIPPED_INFO": "", "UNSUPPORTED_INFO": "ente no soporta estos formatos de archivo aún", "BLOCKED_UPLOADS": "Subidas bloqueadas", "INPROGRESS_METADATA_EXTRACTION": "En proceso", diff --git a/web/packages/base/locales/et-EE/translation.json b/web/packages/base/locales/et-EE/translation.json index 2f7b02d9ee..f90267b710 100644 --- a/web/packages/base/locales/et-EE/translation.json +++ b/web/packages/base/locales/et-EE/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "", "REFERRAL_INFO": "", "PASSPHRASE_MATCH_ERROR": "", + "create_albums": "", "CREATE_COLLECTION": "", "ENTER_ALBUM_NAME": "", "CLOSE_OPTION": "", diff --git a/web/packages/base/locales/fa-IR/translation.json b/web/packages/base/locales/fa-IR/translation.json index c3d6c8159a..b6d481c36a 100644 --- a/web/packages/base/locales/fa-IR/translation.json +++ b/web/packages/base/locales/fa-IR/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "", "REFERRAL_INFO": "", "PASSPHRASE_MATCH_ERROR": "", + "create_albums": "", "CREATE_COLLECTION": "", "ENTER_ALBUM_NAME": "", "CLOSE_OPTION": "", diff --git a/web/packages/base/locales/fi-FI/translation.json b/web/packages/base/locales/fi-FI/translation.json index d0f899abef..8794455ddc 100644 --- a/web/packages/base/locales/fi-FI/translation.json +++ b/web/packages/base/locales/fi-FI/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "Miten kuulit Entestä? (valinnainen)", "REFERRAL_INFO": "Emme seuraa sovelluksen asennuksia. Se auttaisi meitä, jos kertoisit mistä löysit meidät!", "PASSPHRASE_MATCH_ERROR": "Salasanat eivät täsmää", + "create_albums": "", "CREATE_COLLECTION": "Uusi albumi", "ENTER_ALBUM_NAME": "Albumin nimi", "CLOSE_OPTION": "Sulje (Esc)", diff --git a/web/packages/base/locales/fr-FR/translation.json b/web/packages/base/locales/fr-FR/translation.json index b315c99929..639b8a29b6 100644 --- a/web/packages/base/locales/fr-FR/translation.json +++ b/web/packages/base/locales/fr-FR/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "Comment avez-vous entendu parler de Ente? (facultatif)", "REFERRAL_INFO": "Nous ne suivons pas les installations d'applications. Il serait utile que vous nous disiez comment vous nous avez trouvés !", "PASSPHRASE_MATCH_ERROR": "Les mots de passe ne correspondent pas", + "create_albums": "", "CREATE_COLLECTION": "Nouvel album", "ENTER_ALBUM_NAME": "Nom de l'album", "CLOSE_OPTION": "Fermer (Échap)", @@ -301,7 +302,7 @@ "THUMBNAIL_GENERATION_FAILED_UPLOADS": "Échec de création d'une miniature", "UNSUPPORTED_FILES": "Fichiers non supportés", "SUCCESSFUL_UPLOADS": "Chargements réussis", - "SKIPPED_INFO": "Ignorés car il y a des fichiers avec des noms identiques dans le même album", + "SKIPPED_INFO": "", "UNSUPPORTED_INFO": "Ente ne supporte pas encore ces formats de fichiers", "BLOCKED_UPLOADS": "Chargements bloqués", "INPROGRESS_METADATA_EXTRACTION": "En cours", diff --git a/web/packages/base/locales/gu-IN/translation.json b/web/packages/base/locales/gu-IN/translation.json index 2f7b02d9ee..f90267b710 100644 --- a/web/packages/base/locales/gu-IN/translation.json +++ b/web/packages/base/locales/gu-IN/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "", "REFERRAL_INFO": "", "PASSPHRASE_MATCH_ERROR": "", + "create_albums": "", "CREATE_COLLECTION": "", "ENTER_ALBUM_NAME": "", "CLOSE_OPTION": "", diff --git a/web/packages/base/locales/hi-IN/translation.json b/web/packages/base/locales/hi-IN/translation.json index 2f7b02d9ee..f90267b710 100644 --- a/web/packages/base/locales/hi-IN/translation.json +++ b/web/packages/base/locales/hi-IN/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "", "REFERRAL_INFO": "", "PASSPHRASE_MATCH_ERROR": "", + "create_albums": "", "CREATE_COLLECTION": "", "ENTER_ALBUM_NAME": "", "CLOSE_OPTION": "", diff --git a/web/packages/base/locales/id-ID/translation.json b/web/packages/base/locales/id-ID/translation.json index 9bf887d7be..3f0ae89793 100644 --- a/web/packages/base/locales/id-ID/translation.json +++ b/web/packages/base/locales/id-ID/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "Dari mana Anda menemukan Ente? (opsional)", "REFERRAL_INFO": "Kami tidak melacak pemasangan aplikasi, Ini akan membantu kami jika Anda memberi tahu kami di mana Anda menemukan kami!", "PASSPHRASE_MATCH_ERROR": "Kata sandi tidak cocok", + "create_albums": "", "CREATE_COLLECTION": "Album baru", "ENTER_ALBUM_NAME": "Nama album", "CLOSE_OPTION": "Tutup (Esc)", diff --git a/web/packages/base/locales/is-IS/translation.json b/web/packages/base/locales/is-IS/translation.json index 609dff0ef7..326ed688ec 100644 --- a/web/packages/base/locales/is-IS/translation.json +++ b/web/packages/base/locales/is-IS/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "", "REFERRAL_INFO": "", "PASSPHRASE_MATCH_ERROR": "", + "create_albums": "", "CREATE_COLLECTION": "", "ENTER_ALBUM_NAME": "", "CLOSE_OPTION": "", diff --git a/web/packages/base/locales/it-IT/translation.json b/web/packages/base/locales/it-IT/translation.json index e32e814fda..63d1d3fee1 100644 --- a/web/packages/base/locales/it-IT/translation.json +++ b/web/packages/base/locales/it-IT/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "Come hai conosciuto Ente? (opzionale)", "REFERRAL_INFO": "", "PASSPHRASE_MATCH_ERROR": "Le password non corrispondono", + "create_albums": "", "CREATE_COLLECTION": "Nuovo album", "ENTER_ALBUM_NAME": "Nome album", "CLOSE_OPTION": "Chiudi (Esc)", diff --git a/web/packages/base/locales/ja-JP/translation.json b/web/packages/base/locales/ja-JP/translation.json index 2f7b02d9ee..f90267b710 100644 --- a/web/packages/base/locales/ja-JP/translation.json +++ b/web/packages/base/locales/ja-JP/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "", "REFERRAL_INFO": "", "PASSPHRASE_MATCH_ERROR": "", + "create_albums": "", "CREATE_COLLECTION": "", "ENTER_ALBUM_NAME": "", "CLOSE_OPTION": "", diff --git a/web/packages/base/locales/km-KH/translation.json b/web/packages/base/locales/km-KH/translation.json index 2f7b02d9ee..f90267b710 100644 --- a/web/packages/base/locales/km-KH/translation.json +++ b/web/packages/base/locales/km-KH/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "", "REFERRAL_INFO": "", "PASSPHRASE_MATCH_ERROR": "", + "create_albums": "", "CREATE_COLLECTION": "", "ENTER_ALBUM_NAME": "", "CLOSE_OPTION": "", diff --git a/web/packages/base/locales/ko-KR/translation.json b/web/packages/base/locales/ko-KR/translation.json index 0afc0224fd..0a973ce7ae 100644 --- a/web/packages/base/locales/ko-KR/translation.json +++ b/web/packages/base/locales/ko-KR/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "어떻게 Ente에 대해 들으셨나요? (선택사항)", "REFERRAL_INFO": "우리는 앱 설치를 추적하지 않습니다. 우리를 알게 된 곳을 남겨주시면 우리에게 도움이 될꺼에요!", "PASSPHRASE_MATCH_ERROR": "비밀번호가 일치하지 않습니다", + "create_albums": "", "CREATE_COLLECTION": "새 앨범", "ENTER_ALBUM_NAME": "앨범 이름", "CLOSE_OPTION": "닫기 (Esc)", diff --git a/web/packages/base/locales/nl-NL/translation.json b/web/packages/base/locales/nl-NL/translation.json index 1dd8934a3c..d8cba2d986 100644 --- a/web/packages/base/locales/nl-NL/translation.json +++ b/web/packages/base/locales/nl-NL/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "Hoe hoorde je over Ente? (optioneel)", "REFERRAL_INFO": "Wij gebruiken geen tracking. Het zou helpen als je ons vertelt waar je ons gevonden hebt!", "PASSPHRASE_MATCH_ERROR": "Wachtwoorden komen niet overeen", + "create_albums": "", "CREATE_COLLECTION": "Nieuw album", "ENTER_ALBUM_NAME": "Albumnaam", "CLOSE_OPTION": "Sluiten (Esc)", @@ -301,7 +302,7 @@ "THUMBNAIL_GENERATION_FAILED_UPLOADS": "Thumbnail generatie mislukt", "UNSUPPORTED_FILES": "Niet-ondersteunde bestanden", "SUCCESSFUL_UPLOADS": "Succesvolle uploads", - "SKIPPED_INFO": "Deze zijn overgeslagen omdat er bestanden zijn met overeenkomende namen in hetzelfde album", + "SKIPPED_INFO": "", "UNSUPPORTED_INFO": "Ente ondersteunt deze bestandsformaten nog niet", "BLOCKED_UPLOADS": "Geblokkeerde uploads", "INPROGRESS_METADATA_EXTRACTION": "In behandeling", diff --git a/web/packages/base/locales/pl-PL/translation.json b/web/packages/base/locales/pl-PL/translation.json index 2bf6775c9a..33a6a9ba1a 100644 --- a/web/packages/base/locales/pl-PL/translation.json +++ b/web/packages/base/locales/pl-PL/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "Jak usłyszałeś/aś o Ente? (opcjonalnie)", "REFERRAL_INFO": "Nie śledzimy instalacji aplikacji. Pomogłyby nam, gdybyś powiedział/a nam, gdzie nas znalazłeś/aś!", "PASSPHRASE_MATCH_ERROR": "Hasła nie pasują do siebie", + "create_albums": "", "CREATE_COLLECTION": "Nowy album", "ENTER_ALBUM_NAME": "Nazwa albumu", "CLOSE_OPTION": "Zamknij (Esc)", @@ -301,7 +302,7 @@ "THUMBNAIL_GENERATION_FAILED_UPLOADS": "Generowanie miniatur nie powiodło się", "UNSUPPORTED_FILES": "Nieobsługiwane pliki", "SUCCESSFUL_UPLOADS": "Pomyślne przesłania", - "SKIPPED_INFO": "Pominięto te pliki, ponieważ są pliki z pasującymi nazwami w tym samym albumie", + "SKIPPED_INFO": "", "UNSUPPORTED_INFO": "Ente nie obsługuje jeszcze tych formatów plików", "BLOCKED_UPLOADS": "Zablokowane przesłania", "INPROGRESS_METADATA_EXTRACTION": "W toku", diff --git a/web/packages/base/locales/pt-BR/translation.json b/web/packages/base/locales/pt-BR/translation.json index 7cb8e2e3ca..4b9245dfcd 100644 --- a/web/packages/base/locales/pt-BR/translation.json +++ b/web/packages/base/locales/pt-BR/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "Como você ouviu sobre o Ente? (opcional)", "REFERRAL_INFO": "Não rastreamos instalações do aplicativo. Seria útil se você nos contasse onde nos encontrou!", "PASSPHRASE_MATCH_ERROR": "As senhas não coincidem", + "create_albums": "", "CREATE_COLLECTION": "Novo álbum", "ENTER_ALBUM_NAME": "Nome do álbum", "CLOSE_OPTION": "Fechar (Esc)", @@ -301,7 +302,7 @@ "THUMBNAIL_GENERATION_FAILED_UPLOADS": "Falha ao gerar miniaturas", "UNSUPPORTED_FILES": "Arquivos não suportados", "SUCCESSFUL_UPLOADS": "Envios bem sucedidos", - "SKIPPED_INFO": "Ignorar estes como existem arquivos com nomes correspondentes no mesmo álbum", + "SKIPPED_INFO": "", "UNSUPPORTED_INFO": "ente ainda não suporta estes formatos de arquivo", "BLOCKED_UPLOADS": "Envios bloqueados", "INPROGRESS_METADATA_EXTRACTION": "Em andamento", diff --git a/web/packages/base/locales/pt-PT/translation.json b/web/packages/base/locales/pt-PT/translation.json index b1d4f2f26e..e5f318a3be 100644 --- a/web/packages/base/locales/pt-PT/translation.json +++ b/web/packages/base/locales/pt-PT/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "", "REFERRAL_INFO": "", "PASSPHRASE_MATCH_ERROR": "", + "create_albums": "", "CREATE_COLLECTION": "Novo álbum", "ENTER_ALBUM_NAME": "Nome do álbum", "CLOSE_OPTION": "Fechar (Esc)", diff --git a/web/packages/base/locales/ru-RU/translation.json b/web/packages/base/locales/ru-RU/translation.json index f15cc4a8f0..e8aa1eb726 100644 --- a/web/packages/base/locales/ru-RU/translation.json +++ b/web/packages/base/locales/ru-RU/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "Как вы узнали о Ente? (необязательно)", "REFERRAL_INFO": "Будет полезно, если вы укажете, где нашли нас, так как мы не отслеживаем установки приложения!", "PASSPHRASE_MATCH_ERROR": "Пароли не совпадают", + "create_albums": "", "CREATE_COLLECTION": "Новый альбом", "ENTER_ALBUM_NAME": "Название альбома", "CLOSE_OPTION": "Закрыть (Esc)", @@ -301,7 +302,7 @@ "THUMBNAIL_GENERATION_FAILED_UPLOADS": "Не удалось создать миниатюру", "UNSUPPORTED_FILES": "Неподдерживаемые файлы", "SUCCESSFUL_UPLOADS": "Успешные загрузки", - "SKIPPED_INFO": "Пропустил их, так как в одном альбоме есть файлы с одинаковыми названиями", + "SKIPPED_INFO": "", "UNSUPPORTED_INFO": "Ente пока не поддерживает эти форматы файлов", "BLOCKED_UPLOADS": "Заблокированные загрузки", "INPROGRESS_METADATA_EXTRACTION": "В процессе", diff --git a/web/packages/base/locales/sv-SE/translation.json b/web/packages/base/locales/sv-SE/translation.json index 42cdf3e79a..59aaf3dc88 100644 --- a/web/packages/base/locales/sv-SE/translation.json +++ b/web/packages/base/locales/sv-SE/translation.json @@ -7,7 +7,7 @@ "HERO_SLIDE_3": "Android, iOS, webb, skrivbord", "LOGIN": "Logga in", "SIGN_UP": "Registrera", - "NEW_USER": "", + "NEW_USER": "Ny hos Ente", "EXISTING_USER": "Befintlig användare", "ENTER_NAME": "Ange namn", "PUBLIC_UPLOADER_NAME_MESSAGE": "Lägg till ett namn så att dina vänner vet vem de ska tacka för dessa fantastiska bilder!", @@ -26,7 +26,7 @@ "SENT": "Skickat!", "password": "Lösenord", "link_password_description": "Ange lösenord för att låsa upp albumet", - "unlock": "", + "unlock": "Lås upp", "SET_PASSPHRASE": "Välj lösenord", "VERIFY_PASSPHRASE": "Logga in", "INCORRECT_PASSPHRASE": "Felaktigt lösenord", @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "Hur hörde du talas om Ente? (valfritt)", "REFERRAL_INFO": "Vi spårar inte appinstallationer, Det skulle hjälpa oss om du berättade var du hittade oss!", "PASSPHRASE_MATCH_ERROR": "Lösenorden matchar inte", + "create_albums": "", "CREATE_COLLECTION": "Nytt album", "ENTER_ALBUM_NAME": "Albumnamn", "CLOSE_OPTION": "Stäng (Esc)", @@ -60,11 +61,11 @@ "0": "Förbereder att ladda upp", "1": "Läser Google metadatafiler", "2": "Metadata för {{uploadCounter.finished, number}} / {{uploadCounter.total, number}} filer extraherat", - "3": "", - "4": "", - "5": "" + "3": "{{uploadCounter.finished, number}} / {{uploadCounter.total, number}} filer behandlade", + "4": "Avbryter återstående uppladdningar", + "5": "Säkerhetskopiering slutförd" }, - "FILE_NOT_UPLOADED_LIST": "", + "FILE_NOT_UPLOADED_LIST": "Följande filer laddades ej upp", "INITIAL_LOAD_DELAY_WARNING": "", "USER_DOES_NOT_EXIST": "", "NO_ACCOUNT": "", @@ -650,7 +651,7 @@ "redirect_close_instructions": "", "redirect_again": "", "autogenerated_first_album_name": "", - "autogenerated_default_album_name": "", + "autogenerated_default_album_name": "Nytt album", "developer_settings": "Utvecklarinställningar", "server_endpoint": "", "more_information": "", diff --git a/web/packages/base/locales/ta-IN/translation.json b/web/packages/base/locales/ta-IN/translation.json new file mode 100644 index 0000000000..f90267b710 --- /dev/null +++ b/web/packages/base/locales/ta-IN/translation.json @@ -0,0 +1,659 @@ +{ + "HERO_SLIDE_1_TITLE": "", + "HERO_SLIDE_1": "", + "HERO_SLIDE_2_TITLE": "", + "HERO_SLIDE_2": "", + "HERO_SLIDE_3_TITLE": "", + "HERO_SLIDE_3": "", + "LOGIN": "", + "SIGN_UP": "", + "NEW_USER": "", + "EXISTING_USER": "", + "ENTER_NAME": "", + "PUBLIC_UPLOADER_NAME_MESSAGE": "", + "ENTER_EMAIL": "", + "EMAIL_ERROR": "", + "REQUIRED": "", + "EMAIL_SENT": "", + "CHECK_INBOX": "", + "ENTER_OTT": "", + "RESEND_MAIL": "", + "VERIFY": "", + "UNKNOWN_ERROR": "", + "INVALID_CODE": "", + "EXPIRED_CODE": "", + "SENDING": "", + "SENT": "", + "password": "", + "link_password_description": "", + "unlock": "", + "SET_PASSPHRASE": "", + "VERIFY_PASSPHRASE": "", + "INCORRECT_PASSPHRASE": "", + "ENTER_ENC_PASSPHRASE": "", + "PASSPHRASE_DISCLAIMER": "", + "WELCOME_TO_ENTE_HEADING": "", + "WELCOME_TO_ENTE_SUBHEADING": "", + "WHERE_YOUR_BEST_PHOTOS_LIVE": "", + "KEY_GENERATION_IN_PROGRESS_MESSAGE": "", + "PASSPHRASE_HINT": "", + "CONFIRM_PASSPHRASE": "", + "REFERRAL_CODE_HINT": "", + "REFERRAL_INFO": "", + "PASSPHRASE_MATCH_ERROR": "", + "create_albums": "", + "CREATE_COLLECTION": "", + "ENTER_ALBUM_NAME": "", + "CLOSE_OPTION": "", + "ENTER_FILE_NAME": "", + "CLOSE": "", + "NO": "", + "NOTHING_HERE": "", + "upload": "", + "import": "", + "ADD_PHOTOS": "", + "ADD_MORE_PHOTOS": "", + "add_photos_count_one": "", + "add_photos_count": "", + "select_photos": "", + "FILE_UPLOAD": "", + "UPLOAD_STAGE_MESSAGE": { + "0": "", + "1": "", + "2": "", + "3": "", + "4": "", + "5": "" + }, + "FILE_NOT_UPLOADED_LIST": "", + "INITIAL_LOAD_DELAY_WARNING": "", + "USER_DOES_NOT_EXIST": "", + "NO_ACCOUNT": "", + "ACCOUNT_EXISTS": "", + "CREATE": "", + "DOWNLOAD": "", + "DOWNLOAD_OPTION": "", + "DOWNLOAD_FAVORITES": "", + "DOWNLOAD_UNCATEGORIZED": "", + "DOWNLOAD_HIDDEN_ITEMS": "", + "COPY_OPTION": "", + "TOGGLE_FULLSCREEN": "", + "ZOOM_IN_OUT": "", + "PREVIOUS": "", + "NEXT": "", + "title_photos": "", + "title_auth": "", + "title_accounts": "", + "UPLOAD_FIRST_PHOTO": "", + "IMPORT_YOUR_FOLDERS": "", + "UPLOAD_DROPZONE_MESSAGE": "", + "WATCH_FOLDER_DROPZONE_MESSAGE": "", + "TRASH_FILES_TITLE": "", + "TRASH_FILE_TITLE": "", + "DELETE_FILES_TITLE": "", + "DELETE_FILES_MESSAGE": "", + "DELETE": "", + "DELETE_OPTION": "", + "FAVORITE_OPTION": "", + "UNFAVORITE_OPTION": "", + "MULTI_FOLDER_UPLOAD": "", + "UPLOAD_STRATEGY_CHOICE": "", + "UPLOAD_STRATEGY_SINGLE_COLLECTION": "", + "OR": "", + "UPLOAD_STRATEGY_COLLECTION_PER_FOLDER": "", + "SESSION_EXPIRED_MESSAGE": "", + "SESSION_EXPIRED": "", + "PASSWORD_GENERATION_FAILED": "", + "CHANGE_PASSWORD": "", + "password_changed_elsewhere": "", + "password_changed_elsewhere_message": "", + "GO_BACK": "", + "RECOVERY_KEY": "", + "SAVE_LATER": "", + "SAVE": "", + "RECOVERY_KEY_DESCRIPTION": "", + "RECOVER_KEY_GENERATION_FAILED": "", + "KEY_NOT_STORED_DISCLAIMER": "", + "FORGOT_PASSWORD": "", + "RECOVER_ACCOUNT": "", + "RECOVERY_KEY_HINT": "", + "RECOVER": "", + "NO_RECOVERY_KEY": "", + "INCORRECT_RECOVERY_KEY": "", + "SORRY": "", + "NO_RECOVERY_KEY_MESSAGE": "", + "NO_TWO_FACTOR_RECOVERY_KEY_MESSAGE": "", + "CONTACT_SUPPORT": "", + "REQUEST_FEATURE": "", + "SUPPORT": "", + "CONFIRM": "", + "cancel": "", + "LOGOUT": "", + "delete_account": "", + "delete_account_manually_message": "", + "LOGOUT_MESSAGE": "", + "CHANGE_EMAIL": "", + "OK": "", + "SUCCESS": "", + "ERROR": "", + "MESSAGE": "", + "OFFLINE_MSG": "", + "INSTALL_MOBILE_APP": "", + "DOWNLOAD_APP_MESSAGE": "", + "DOWNLOAD_APP": "", + "EXPORT": "", + "SUBSCRIPTION": "", + "SUBSCRIBE": "", + "MANAGEMENT_PORTAL": "", + "MANAGE_FAMILY_PORTAL": "", + "LEAVE_FAMILY_PLAN": "", + "LEAVE": "", + "LEAVE_FAMILY_CONFIRM": "", + "CHOOSE_PLAN": "", + "MANAGE_PLAN": "", + "CURRENT_USAGE": "", + "TWO_MONTHS_FREE": "", + "POPULAR": "", + "free_plan_option": "", + "free_plan_description": "", + "active": "", + "subscription_info_free": "", + "subscription_info_family": "", + "subscription_info_expired": "", + "subscription_info_renewal_cancelled": "", + "subscription_info_storage_quota_exceeded": "", + "subscription_status_renewal_active": "", + "subscription_status_renewal_cancelled": "", + "add_on_valid_till": "", + "subscription_expired": "", + "storage_quota_exceeded": "", + "SUBSCRIPTION_PURCHASE_SUCCESS": "", + "SUBSCRIPTION_PURCHASE_CANCELLED": "", + "SUBSCRIPTION_PURCHASE_FAILED": "", + "SUBSCRIPTION_UPDATE_FAILED": "", + "UPDATE_PAYMENT_METHOD_MESSAGE": "", + "STRIPE_AUTHENTICATION_FAILED": "", + "UPDATE_PAYMENT_METHOD": "", + "MONTHLY": "", + "YEARLY": "", + "MONTH_SHORT": "", + "YEAR": "", + "update_subscription_title": "", + "UPDATE_SUBSCRIPTION_MESSAGE": "", + "UPDATE_SUBSCRIPTION": "", + "CANCEL_SUBSCRIPTION": "", + "CANCEL_SUBSCRIPTION_MESSAGE": "", + "CANCEL_SUBSCRIPTION_WITH_ADDON_MESSAGE": "", + "SUBSCRIPTION_CANCEL_FAILED": "", + "SUBSCRIPTION_CANCEL_SUCCESS": "", + "REACTIVATE_SUBSCRIPTION": "", + "REACTIVATE_SUBSCRIPTION_MESSAGE": "", + "SUBSCRIPTION_ACTIVATE_SUCCESS": "", + "SUBSCRIPTION_ACTIVATE_FAILED": "", + "SUBSCRIPTION_PURCHASE_SUCCESS_TITLE": "", + "CANCEL_SUBSCRIPTION_ON_MOBILE": "", + "CANCEL_SUBSCRIPTION_ON_MOBILE_MESSAGE": "", + "MAIL_TO_MANAGE_SUBSCRIPTION": "", + "RENAME": "", + "RENAME_FILE": "", + "RENAME_COLLECTION": "", + "DELETE_COLLECTION_TITLE": "", + "DELETE_COLLECTION": "", + "DELETE_COLLECTION_MESSAGE": "", + "DELETE_PHOTOS": "", + "KEEP_PHOTOS": "", + "SHARE_COLLECTION": "", + "SHARE_WITH_SELF": "", + "ALREADY_SHARED": "", + "SHARING_BAD_REQUEST_ERROR": "", + "SHARING_DISABLED_FOR_FREE_ACCOUNTS": "", + "DOWNLOAD_COLLECTION": "", + "CREATE_ALBUM_FAILED": "", + "SEARCH": "", + "SEARCH_RESULTS": "", + "NO_RESULTS": "", + "SEARCH_HINT": "", + "SEARCH_TYPE": { + "COLLECTION": "", + "LOCATION": "", + "CITY": "", + "DATE": "", + "FILE_NAME": "", + "THING": "", + "FILE_CAPTION": "", + "FILE_TYPE": "", + "CLIP": "" + }, + "photos_count_zero": "", + "photos_count_one": "", + "photos_count": "", + "TERMS_AND_CONDITIONS": "", + "ADD_TO_COLLECTION": "", + "SELECTED": "", + "PEOPLE": "", + "indexing_scheduled": "", + "indexing_photos": "", + "indexing_fetching": "", + "indexing_people": "", + "indexing_done": "", + "UNIDENTIFIED_FACES": "", + "OBJECTS": "", + "TEXT": "", + "INFO": "", + "INFO_OPTION": "", + "FILE_NAME": "", + "CAPTION_PLACEHOLDER": "", + "LOCATION": "", + "SHOW_ON_MAP": "", + "MAP": "", + "MAP_SETTINGS": "", + "ENABLE_MAPS": "", + "ENABLE_MAP": "", + "DISABLE_MAPS": "", + "ENABLE_MAP_DESCRIPTION": "", + "DISABLE_MAP_DESCRIPTION": "", + "DISABLE_MAP": "", + "DETAILS": "", + "view_exif": "", + "no_exif": "", + "exif": "", + "ISO": "", + "TWO_FACTOR": "", + "TWO_FACTOR_AUTHENTICATION": "", + "TWO_FACTOR_QR_INSTRUCTION": "", + "ENTER_CODE_MANUALLY": "", + "TWO_FACTOR_MANUAL_CODE_INSTRUCTION": "", + "SCAN_QR_CODE": "", + "ENABLE_TWO_FACTOR": "", + "enable": "", + "enabled": "", + "LOST_DEVICE": "", + "INCORRECT_CODE": "", + "TWO_FACTOR_INFO": "", + "DISABLE_TWO_FACTOR_LABEL": "", + "UPDATE_TWO_FACTOR_LABEL": "", + "disable": "", + "reconfigure": "", + "UPDATE_TWO_FACTOR": "", + "UPDATE_TWO_FACTOR_MESSAGE": "", + "UPDATE": "", + "DISABLE_TWO_FACTOR": "", + "DISABLE_TWO_FACTOR_MESSAGE": "", + "TWO_FACTOR_DISABLE_FAILED": "", + "EXPORT_DATA": "", + "select_folder": "", + "select_zips": "", + "faq": "", + "takeout_hint": "", + "DESTINATION": "", + "START": "", + "LAST_EXPORT_TIME": "", + "EXPORT_AGAIN": "", + "LOCAL_STORAGE_NOT_ACCESSIBLE": "", + "LOCAL_STORAGE_NOT_ACCESSIBLE_MESSAGE": "", + "SEND_OTT": "", + "EMAIl_ALREADY_OWNED": "", + "ETAGS_BLOCKED": "", + "LIVE_PHOTOS_DETECTED": "", + "RETRY_FAILED": "", + "FAILED_UPLOADS": "", + "failed_uploads_hint": "", + "SKIPPED_FILES": "", + "THUMBNAIL_GENERATION_FAILED_UPLOADS": "", + "UNSUPPORTED_FILES": "", + "SUCCESSFUL_UPLOADS": "", + "SKIPPED_INFO": "", + "UNSUPPORTED_INFO": "", + "BLOCKED_UPLOADS": "", + "INPROGRESS_METADATA_EXTRACTION": "", + "INPROGRESS_UPLOADS": "", + "TOO_LARGE_UPLOADS": "", + "LARGER_THAN_AVAILABLE_STORAGE_UPLOADS": "", + "LARGER_THAN_AVAILABLE_STORAGE_INFO": "", + "TOO_LARGE_INFO": "", + "THUMBNAIL_GENERATION_FAILED_INFO": "", + "UPLOAD_TO_COLLECTION": "", + "UNCATEGORIZED": "", + "ARCHIVE": "", + "FAVORITES": "", + "ARCHIVE_COLLECTION": "", + "ARCHIVE_SECTION_NAME": "", + "ALL_SECTION_NAME": "", + "MOVE_TO_COLLECTION": "", + "UNARCHIVE": "", + "UNARCHIVE_COLLECTION": "", + "HIDE_COLLECTION": "", + "UNHIDE_COLLECTION": "", + "MOVE": "", + "ADD": "", + "REMOVE": "", + "YES_REMOVE": "", + "REMOVE_FROM_COLLECTION": "", + "TRASH": "", + "MOVE_TO_TRASH": "", + "TRASH_FILES_MESSAGE": "", + "TRASH_FILE_MESSAGE": "", + "DELETE_PERMANENTLY": "", + "RESTORE": "", + "RESTORE_TO_COLLECTION": "", + "EMPTY_TRASH": "", + "EMPTY_TRASH_TITLE": "", + "EMPTY_TRASH_MESSAGE": "", + "LEAVE_SHARED_ALBUM": "", + "LEAVE_ALBUM": "", + "LEAVE_SHARED_ALBUM_TITLE": "", + "LEAVE_SHARED_ALBUM_MESSAGE": "", + "NOT_FILE_OWNER": "", + "CONFIRM_SELF_REMOVE_MESSAGE": "", + "CONFIRM_SELF_AND_OTHER_REMOVE_MESSAGE": "", + "SORT_BY_CREATION_TIME_ASCENDING": "", + "SORT_BY_UPDATION_TIME_DESCENDING": "", + "SORT_BY_NAME": "", + "FIX_CREATION_TIME": "", + "FIX_CREATION_TIME_IN_PROGRESS": "", + "CREATION_TIME_UPDATED": "", + "UPDATE_CREATION_TIME_NOT_STARTED": "", + "UPDATE_CREATION_TIME_COMPLETED": "", + "UPDATE_CREATION_TIME_COMPLETED_WITH_ERROR": "", + "CAPTION_CHARACTER_LIMIT": "", + "DATE_TIME_ORIGINAL": "", + "DATE_TIME_DIGITIZED": "", + "METADATA_DATE": "", + "CUSTOM_TIME": "", + "REOPEN_PLAN_SELECTOR_MODAL": "", + "OPEN_PLAN_SELECTOR_MODAL_FAILED": "", + "INSTALL": "", + "SHARING_DETAILS": "", + "MODIFY_SHARING": "", + "ADD_COLLABORATORS": "", + "ADD_NEW_EMAIL": "", + "shared_with_people_count_zero": "", + "shared_with_people_count_one": "", + "shared_with_people_count": "", + "participants_count_zero": "", + "participants_count_one": "", + "participants_count": "", + "ADD_VIEWERS": "", + "CHANGE_PERMISSIONS_TO_VIEWER": "", + "CHANGE_PERMISSIONS_TO_COLLABORATOR": "", + "CONVERT_TO_VIEWER": "", + "CONVERT_TO_COLLABORATOR": "", + "CHANGE_PERMISSION": "", + "REMOVE_PARTICIPANT": "", + "CONFIRM_REMOVE": "", + "MANAGE": "", + "ADDED_AS": "", + "COLLABORATOR_RIGHTS": "", + "REMOVE_PARTICIPANT_HEAD": "", + "OWNER": "", + "COLLABORATORS": "", + "ADD_MORE": "", + "VIEWERS": "", + "OR_ADD_EXISTING": "", + "REMOVE_PARTICIPANT_MESSAGE": "", + "NOT_FOUND": "", + "LINK_EXPIRED": "", + "LINK_EXPIRED_MESSAGE": "", + "MANAGE_LINK": "", + "LINK_TOO_MANY_REQUESTS": "", + "FILE_DOWNLOAD": "", + "link_password_lock": "", + "PUBLIC_COLLECT": "", + "LINK_DEVICE_LIMIT": "", + "NO_DEVICE_LIMIT": "", + "LINK_EXPIRY": "", + "NEVER": "", + "DISABLE_FILE_DOWNLOAD": "", + "DISABLE_FILE_DOWNLOAD_MESSAGE": "", + "SHARED_USING": "", + "SHARING_REFERRAL_CODE": "", + "LIVE": "", + "DISABLE_PASSWORD": "", + "DISABLE_PASSWORD_MESSAGE": "", + "PASSWORD_LOCK": "", + "LOCK": "", + "DOWNLOAD_UPLOAD_LOGS": "", + "file": "", + "folder": "", + "google_takeout": "", + "DEDUPLICATE_FILES": "", + "NO_DUPLICATES_FOUND": "", + "FILES": "", + "EACH": "", + "DEDUPLICATE_BASED_ON_SIZE": "", + "STOP_ALL_UPLOADS_MESSAGE": "", + "STOP_UPLOADS_HEADER": "", + "YES_STOP_UPLOADS": "", + "STOP_DOWNLOADS_HEADER": "", + "YES_STOP_DOWNLOADS": "", + "STOP_ALL_DOWNLOADS_MESSAGE": "", + "albums_count_one": "", + "albums_count": "", + "ALL_ALBUMS": "", + "ALBUMS": "", + "ALL_HIDDEN_ALBUMS": "", + "HIDDEN_ALBUMS": "", + "HIDDEN_ITEMS": "", + "ENTER_TWO_FACTOR_OTP": "", + "CREATE_ACCOUNT": "", + "COPIED": "", + "WATCH_FOLDERS": "", + "upgrade_now": "", + "renew_now": "", + "STORAGE": "", + "USED": "", + "YOU": "", + "FAMILY": "", + "FREE": "", + "OF": "", + "WATCHED_FOLDERS": "", + "NO_FOLDERS_ADDED": "", + "FOLDERS_AUTOMATICALLY_MONITORED": "", + "UPLOAD_NEW_FILES_TO_ENTE": "", + "REMOVE_DELETED_FILES_FROM_ENTE": "", + "ADD_FOLDER": "", + "STOP_WATCHING": "", + "STOP_WATCHING_FOLDER": "", + "STOP_WATCHING_DIALOG_MESSAGE": "", + "YES_STOP": "", + "CHANGE_FOLDER": "", + "FAMILY_PLAN": "", + "DOWNLOAD_LOGS": "", + "DOWNLOAD_LOGS_MESSAGE": "", + "WEAK_DEVICE": "", + "drag_and_drop_hint": "", + "AUTHENTICATE": "", + "UPLOADED_TO_SINGLE_COLLECTION": "", + "UPLOADED_TO_SEPARATE_COLLECTIONS": "", + "NEVERMIND": "", + "UPDATE_AVAILABLE": "", + "UPDATE_INSTALLABLE_MESSAGE": "", + "INSTALL_NOW": "", + "INSTALL_ON_NEXT_LAUNCH": "", + "UPDATE_AVAILABLE_MESSAGE": "", + "DOWNLOAD_AND_INSTALL": "", + "IGNORE_THIS_VERSION": "", + "TODAY": "", + "YESTERDAY": "", + "NAME_PLACEHOLDER": "", + "ROOT_LEVEL_FILE_WITH_FOLDER_NOT_ALLOWED": "", + "ROOT_LEVEL_FILE_WITH_FOLDER_NOT_ALLOWED_MESSAGE": "", + "CHOSE_THEME": "", + "more_details": "", + "ml_search": "", + "ml_search_description": "", + "ml_search_footnote": "", + "indexing": "", + "processed": "", + "indexing_status_running": "", + "indexing_status_fetching": "", + "indexing_status_scheduled": "", + "indexing_status_done": "", + "ml_search_disable": "", + "ml_search_disable_confirm": "", + "ml_consent": "", + "ml_consent_title": "", + "ml_consent_description": "", + "ml_consent_confirmation": "", + "labs": "", + "YOURS": "", + "passphrase_strength_weak": "", + "passphrase_strength_moderate": "", + "passphrase_strength_strong": "", + "preferences": "", + "language": "", + "advanced": "", + "EXPORT_DIRECTORY_DOES_NOT_EXIST": "", + "EXPORT_DIRECTORY_DOES_NOT_EXIST_MESSAGE": "", + "SUBSCRIPTION_VERIFICATION_ERROR": "", + "storage_unit": { + "b": "", + "kb": "", + "mb": "", + "gb": "", + "tb": "" + }, + "AFTER_TIME": { + "HOUR": "", + "DAY": "", + "WEEK": "", + "MONTH": "", + "YEAR": "" + }, + "COPY_LINK": "", + "DONE": "", + "LINK_SHARE_TITLE": "", + "REMOVE_LINK": "", + "CREATE_PUBLIC_SHARING": "", + "PUBLIC_LINK_CREATED": "", + "PUBLIC_LINK_ENABLED": "", + "COLLECT_PHOTOS": "", + "PUBLIC_COLLECT_SUBTEXT": "", + "STOP_EXPORT": "", + "EXPORT_PROGRESS": "", + "MIGRATING_EXPORT": "", + "RENAMING_COLLECTION_FOLDERS": "", + "TRASHING_DELETED_FILES": "", + "TRASHING_DELETED_COLLECTIONS": "", + "CONTINUOUS_EXPORT": "", + "PENDING_ITEMS": "", + "EXPORT_STARTING": "", + "delete_account_reason_label": "", + "delete_account_reason_placeholder": "", + "delete_reason": { + "missing_feature": "", + "behaviour": "", + "found_another_service": "", + "not_listed": "" + }, + "delete_account_feedback_label": "", + "delete_account_feedback_placeholder": "", + "delete_account_confirm_checkbox_label": "", + "delete_account_confirm": "", + "delete_account_confirm_message": "", + "feedback_required": "", + "feedback_required_found_another_service": "", + "RECOVER_TWO_FACTOR": "", + "at": "", + "AUTH_NEXT": "", + "AUTH_DOWNLOAD_MOBILE_APP": "", + "HIDDEN": "", + "HIDE": "", + "UNHIDE": "", + "UNHIDE_TO_COLLECTION": "", + "SORT_BY": "", + "NEWEST_FIRST": "", + "OLDEST_FIRST": "", + "CONVERSION_FAILED_NOTIFICATION_MESSAGE": "", + "SELECT_COLLECTION": "", + "PIN_ALBUM": "", + "UNPIN_ALBUM": "", + "DOWNLOAD_COMPLETE": "", + "DOWNLOADING_COLLECTION": "", + "DOWNLOAD_FAILED": "", + "DOWNLOAD_PROGRESS": "", + "CHRISTMAS": "", + "CHRISTMAS_EVE": "", + "NEW_YEAR": "", + "NEW_YEAR_EVE": "", + "IMAGE": "", + "VIDEO": "", + "LIVE_PHOTO": "", + "editor": { + "crop": "" + }, + "CONVERT": "", + "CONFIRM_EDITOR_CLOSE_MESSAGE": "", + "CONFIRM_EDITOR_CLOSE_DESCRIPTION": "", + "BRIGHTNESS": "", + "CONTRAST": "", + "SATURATION": "", + "BLUR": "", + "INVERT_COLORS": "", + "ASPECT_RATIO": "", + "SQUARE": "", + "ROTATE_LEFT": "", + "ROTATE_RIGHT": "", + "FLIP_VERTICALLY": "", + "FLIP_HORIZONTALLY": "", + "DOWNLOAD_EDITED": "", + "SAVE_A_COPY_TO_ENTE": "", + "RESTORE_ORIGINAL": "", + "TRANSFORM": "", + "COLORS": "", + "FLIP": "", + "ROTATION": "", + "RESET": "", + "PHOTO_EDITOR": "", + "FASTER_UPLOAD": "", + "FASTER_UPLOAD_DESCRIPTION": "", + "CAST_ALBUM_TO_TV": "", + "ENTER_CAST_PIN_CODE": "", + "PAIR_DEVICE_TO_TV": "", + "TV_NOT_FOUND": "", + "AUTO_CAST_PAIR": "", + "AUTO_CAST_PAIR_DESC": "", + "PAIR_WITH_PIN": "", + "CHOOSE_DEVICE_FROM_BROWSER": "", + "PAIR_WITH_PIN_DESC": "", + "VISIT_CAST_ENTE_IO": "", + "CAST_AUTO_PAIR_FAILED": "", + "FREEHAND": "", + "APPLY_CROP": "", + "PHOTO_EDIT_REQUIRED_TO_SAVE": "", + "passkeys": "", + "passkey_fetch_failed": "", + "manage_passkey": "", + "delete_passkey": "", + "delete_passkey_confirmation": "", + "rename_passkey": "", + "add_passkey": "", + "enter_passkey_name": "", + "passkeys_description": "", + "CREATED_AT": "", + "passkey_add_failed": "", + "passkey_login_failed": "", + "passkey_login_invalid_url": "", + "passkey_login_already_claimed_session": "", + "passkey_login_generic_error": "", + "passkey_login_credential_hint": "", + "passkeys_not_supported": "", + "try_again": "", + "check_status": "", + "passkey_login_instructions": "", + "passkey_login": "", + "passkey": "", + "passkey_verify_description": "", + "waiting_for_verification": "", + "verification_still_pending": "", + "passkey_verified": "", + "redirecting_back_to_app": "", + "redirect_close_instructions": "", + "redirect_again": "", + "autogenerated_first_album_name": "", + "autogenerated_default_album_name": "", + "developer_settings": "", + "server_endpoint": "", + "more_information": "", + "save": "" +} diff --git a/web/packages/base/locales/te-IN/translation.json b/web/packages/base/locales/te-IN/translation.json index 2f7b02d9ee..f90267b710 100644 --- a/web/packages/base/locales/te-IN/translation.json +++ b/web/packages/base/locales/te-IN/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "", "REFERRAL_INFO": "", "PASSPHRASE_MATCH_ERROR": "", + "create_albums": "", "CREATE_COLLECTION": "", "ENTER_ALBUM_NAME": "", "CLOSE_OPTION": "", diff --git a/web/packages/base/locales/th-TH/translation.json b/web/packages/base/locales/th-TH/translation.json index 2f7b02d9ee..f90267b710 100644 --- a/web/packages/base/locales/th-TH/translation.json +++ b/web/packages/base/locales/th-TH/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "", "REFERRAL_INFO": "", "PASSPHRASE_MATCH_ERROR": "", + "create_albums": "", "CREATE_COLLECTION": "", "ENTER_ALBUM_NAME": "", "CLOSE_OPTION": "", diff --git a/web/packages/base/locales/ti-ER/translation.json b/web/packages/base/locales/ti-ER/translation.json index 2f7b02d9ee..f90267b710 100644 --- a/web/packages/base/locales/ti-ER/translation.json +++ b/web/packages/base/locales/ti-ER/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "", "REFERRAL_INFO": "", "PASSPHRASE_MATCH_ERROR": "", + "create_albums": "", "CREATE_COLLECTION": "", "ENTER_ALBUM_NAME": "", "CLOSE_OPTION": "", diff --git a/web/packages/base/locales/tr-TR/translation.json b/web/packages/base/locales/tr-TR/translation.json index 2f7b02d9ee..f90267b710 100644 --- a/web/packages/base/locales/tr-TR/translation.json +++ b/web/packages/base/locales/tr-TR/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "", "REFERRAL_INFO": "", "PASSPHRASE_MATCH_ERROR": "", + "create_albums": "", "CREATE_COLLECTION": "", "ENTER_ALBUM_NAME": "", "CLOSE_OPTION": "", diff --git a/web/packages/base/locales/zh-CN/translation.json b/web/packages/base/locales/zh-CN/translation.json index 6064de6295..8e5cb95bea 100644 --- a/web/packages/base/locales/zh-CN/translation.json +++ b/web/packages/base/locales/zh-CN/translation.json @@ -41,6 +41,7 @@ "REFERRAL_CODE_HINT": "您是如何知道Ente的? (可选的)", "REFERRAL_INFO": "我们不跟踪应用程序安装情况,如果您告诉我们您是在哪里找到我们的,将会有所帮助!", "PASSPHRASE_MATCH_ERROR": "两次输入的密码不一致", + "create_albums": "", "CREATE_COLLECTION": "新建相册", "ENTER_ALBUM_NAME": "相册名称", "CLOSE_OPTION": "关闭 (或按Esc键)", @@ -98,7 +99,7 @@ "MULTI_FOLDER_UPLOAD": "检测到多个文件夹", "UPLOAD_STRATEGY_CHOICE": "你想要上传他们到", "UPLOAD_STRATEGY_SINGLE_COLLECTION": "单个相册", - "OR": "或者", + "OR": "还是", "UPLOAD_STRATEGY_COLLECTION_PER_FOLDER": "独立相册", "SESSION_EXPIRED_MESSAGE": "您的会话已过期,请重新登录以继续", "SESSION_EXPIRED": "会话已过期", @@ -301,7 +302,7 @@ "THUMBNAIL_GENERATION_FAILED_UPLOADS": "缩略图生成失败", "UNSUPPORTED_FILES": "不支持的文件", "SUCCESSFUL_UPLOADS": "上传成功", - "SKIPPED_INFO": "跳过这些,因为在同一相册中有具有匹配名称的文件", + "SKIPPED_INFO": "跳过这些文件,因为同一相册中有名称和内容相匹配的文件", "UNSUPPORTED_INFO": "Ente 尚不支持这些文件格式", "BLOCKED_UPLOADS": "已阻止上传", "INPROGRESS_METADATA_EXTRACTION": "进行中", From 823196402395292aba798a172b255bfbb0000485 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Sat, 31 Aug 2024 17:16:02 +0530 Subject: [PATCH 168/275] [desktop] Fix flakiness in reading zip files I'm not sure what was the issue in the existing code, but I happened to chance on a setup that reproduced the flakiness that some customers have reported (that reading the zips sometimes fails). There wasn't anything specific in the setup - I was reading a 50 MB zip file, a file which I'd read multiple times before, except this time it seemed to invariably result in failures during read. Replacing the node stream to web stream conversion with this new approach fixes the flakiness, at least in the reproducible scenario that I was encountering. --- desktop/src/main/stream.ts | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/desktop/src/main/stream.ts b/desktop/src/main/stream.ts index d32eecc627..49e20cdff5 100644 --- a/desktop/src/main/stream.ts +++ b/desktop/src/main/stream.ts @@ -4,8 +4,6 @@ import { net, protocol } from "electron/main"; import { randomUUID } from "node:crypto"; import fs from "node:fs/promises"; -import { Readable } from "node:stream"; -import { ReadableStream } from "node:stream/web"; import { pathToFileURL } from "node:url"; import log from "./log"; import { ffmpegConvertToMP4 } from "./services/ffmpeg"; @@ -17,6 +15,7 @@ import { deleteTempFileIgnoringErrors, makeTempFilePath, } from "./utils/temp"; +const { Readable } = require("node:stream"); /** * Register a protocol handler that we use for streaming large files between the @@ -120,20 +119,21 @@ const handleReadZip = async (zipPath: string, entryName: string) => { return new Response("", { status: 404 }); } - // This returns an "old style" NodeJS.ReadableStream. - const stream = await zip.stream(entry); - // Convert it into a new style NodeJS.Readable. - const nodeReadable = new Readable({ emitClose: true }).wrap(stream); - // Then convert it into a Web stream. - const webReadableStreamAny = Readable.toWeb(nodeReadable); - // However, we get a ReadableStream now. This doesn't go into the - // `BodyInit` expected by the Response constructor, which wants a - // ReadableStream. Force a cast. - const webReadableStream = - webReadableStreamAny as ReadableStream; + const { writable, readable } = new TransformStream(); + const writer = writable.getWriter(); - // Let go of the zip handle when the underlying stream closes. - nodeReadable.on("close", () => markClosableZip(zipPath)); + // zip.stream returns an "old style" NodeJS.ReadableStream. We then write it + // to the writable end of the web stream pipe, the readable end of which is + // relayed back to the renderer as the response. + const stream = await zip.stream(entry); + + stream.on("data", (chunk: Buffer) => { + void writer.write(chunk); + }); + + stream.on("end", () => { + void writer.close(); + }); // While it is documented that entry.time is the modification time, // the units are not mentioned. By seeing the source code, we can @@ -142,8 +142,7 @@ const handleReadZip = async (zipPath: string, entryName: string) => { // https://github.com/antelle/node-stream-zip/blob/master/node_stream_zip.js const modifiedMs = entry.time; - // @ts-expect-error [Note: Node and web stream type mismatch] - return new Response(webReadableStream, { + return new Response(readable, { headers: { // We don't know the exact type, but it doesn't really matter, just // set it to a generic binary content-type so that the browser From 138dcf3d2a59e1e081518627700015ac9114a121 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Sat, 31 Aug 2024 17:58:35 +0530 Subject: [PATCH 169/275] Simplify --- desktop/src/main/stream.ts | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/desktop/src/main/stream.ts b/desktop/src/main/stream.ts index 49e20cdff5..118587603b 100644 --- a/desktop/src/main/stream.ts +++ b/desktop/src/main/stream.ts @@ -4,6 +4,7 @@ import { net, protocol } from "electron/main"; import { randomUUID } from "node:crypto"; import fs from "node:fs/promises"; +import { Writable } from "node:stream"; import { pathToFileURL } from "node:url"; import log from "./log"; import { ffmpegConvertToMP4 } from "./services/ffmpeg"; @@ -15,7 +16,6 @@ import { deleteTempFileIgnoringErrors, makeTempFilePath, } from "./utils/temp"; -const { Readable } = require("node:stream"); /** * Register a protocol handler that we use for streaming large files between the @@ -119,21 +119,15 @@ const handleReadZip = async (zipPath: string, entryName: string) => { return new Response("", { status: 404 }); } - const { writable, readable } = new TransformStream(); - const writer = writable.getWriter(); - // zip.stream returns an "old style" NodeJS.ReadableStream. We then write it // to the writable end of the web stream pipe, the readable end of which is // relayed back to the renderer as the response. + const { writable, readable } = new TransformStream(); const stream = await zip.stream(entry); - stream.on("data", (chunk: Buffer) => { - void writer.write(chunk); - }); + stream.pipe(Writable.fromWeb(writable)); + - stream.on("end", () => { - void writer.close(); - }); // While it is documented that entry.time is the modification time, // the units are not mentioned. By seeing the source code, we can From 027e3425bbbadf2878b19513f9d7c29d9c86f8d3 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Sat, 31 Aug 2024 18:17:38 +0530 Subject: [PATCH 170/275] Gracefully handle aborts --- desktop/src/main/stream.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/desktop/src/main/stream.ts b/desktop/src/main/stream.ts index 118587603b..41c71285a9 100644 --- a/desktop/src/main/stream.ts +++ b/desktop/src/main/stream.ts @@ -125,9 +125,17 @@ const handleReadZip = async (zipPath: string, entryName: string) => { const { writable, readable } = new TransformStream(); const stream = await zip.stream(entry); - stream.pipe(Writable.fromWeb(writable)); - + const nodeWritable = Writable.fromWeb(writable); + stream.pipe(nodeWritable); + nodeWritable.on("error", (e: unknown) => { + // If the renderer process closes the network connection (say when it + // only needs the content-length and doesn't care about the body), we + // get an AbortError. Handle them here otherwise they litter the logs + // with unhandled exceptions. + if (e instanceof Error && e.name == "AbortError") return; + log.error("Error event for the writable end of zip stream", e); + }); // While it is documented that entry.time is the modification time, // the units are not mentioned. By seeing the source code, we can From 171a8670a469ab215b42dfeb902a3449226e37a2 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Sat, 31 Aug 2024 18:19:38 +0530 Subject: [PATCH 171/275] Balance ref counts --- desktop/src/main/services/zip.ts | 4 ++-- desktop/src/main/stream.ts | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/desktop/src/main/services/zip.ts b/desktop/src/main/services/zip.ts index 5a7f4242f0..17a7205bce 100644 --- a/desktop/src/main/services/zip.ts +++ b/desktop/src/main/services/zip.ts @@ -65,9 +65,9 @@ export const markClosableZip = (zipPath: string) => { */ export const clearOpenZipCache = () => { if (_refCount.size > 0) { - const keys = JSON.stringify([..._refCount.keys()]); + const kvs = JSON.stringify([..._refCount.entries()]); throw new Error( - `Attempting to clear zip file cache when some items are still in use: ${keys}`, + `Attempting to clear zip file cache when some items are still in use: ${kvs}`, ); } _cache.clear(); diff --git a/desktop/src/main/stream.ts b/desktop/src/main/stream.ts index 41c71285a9..261ab32a21 100644 --- a/desktop/src/main/stream.ts +++ b/desktop/src/main/stream.ts @@ -137,6 +137,10 @@ const handleReadZip = async (zipPath: string, entryName: string) => { log.error("Error event for the writable end of zip stream", e); }); + nodeWritable.on("close", () => { + markClosableZip(zipPath); + }); + // While it is documented that entry.time is the modification time, // the units are not mentioned. By seeing the source code, we can // verify that it is indeed epoch milliseconds. See `parseZipTime` From 33c843e5d8f1192a6133b58e1572e1dca82cde45 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Fri, 30 Aug 2024 16:57:45 +0530 Subject: [PATCH 172/275] [auth][perf] Reduce redundant painting --- auth/lib/ui/code_timer_progress.dart | 67 ++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/auth/lib/ui/code_timer_progress.dart b/auth/lib/ui/code_timer_progress.dart index a215f0ca02..98538788ed 100644 --- a/auth/lib/ui/code_timer_progress.dart +++ b/auth/lib/ui/code_timer_progress.dart @@ -1,48 +1,45 @@ import 'package:ente_auth/theme/ente_theme.dart'; -import 'package:ente_auth/ui/linear_progress_widget.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; class CodeTimerProgress extends StatefulWidget { final int period; - CodeTimerProgress({ + const CodeTimerProgress({ super.key, required this.period, }); @override - State createState() => _CodeTimerProgressState(); + State createState() => _CodeTimerProgressState(); } class _CodeTimerProgressState extends State with SingleTickerProviderStateMixin { late final Ticker _ticker; - double _progress = 0.0; + late final ValueNotifier _progress; late final int _microSecondsInPeriod; @override void initState() { super.initState(); _microSecondsInPeriod = widget.period * 1000000; - _ticker = createTicker((elapsed) { - _updateTimeRemaining(); - }); + _progress = ValueNotifier(0.0); + _ticker = createTicker(_updateTimeRemaining); _ticker.start(); - _updateTimeRemaining(); + _updateTimeRemaining(Duration.zero); } - void _updateTimeRemaining() { - int timeRemaining = (_microSecondsInPeriod) - + void _updateTimeRemaining(Duration elapsed) { + int timeRemaining = _microSecondsInPeriod - (DateTime.now().microsecondsSinceEpoch % _microSecondsInPeriod); - setState(() { - _progress = (timeRemaining / _microSecondsInPeriod); - }); + _progress.value = timeRemaining / _microSecondsInPeriod; } @override void dispose() { _ticker.dispose(); + _progress.dispose(); super.dispose(); } @@ -50,12 +47,46 @@ class _CodeTimerProgressState extends State Widget build(BuildContext context) { return SizedBox( height: 3, - child: LinearProgressWidget( - color: _progress > 0.4 - ? getEnteColorScheme(context).primary700 - : Colors.orange, - fractionOfStorage: _progress, + child: ValueListenableBuilder( + valueListenable: _progress, + builder: (context, progress, _) { + return CustomPaint( + painter: _ProgressPainter( + progress: progress, + color: progress > 0.4 + ? getEnteColorScheme(context).primary700 + : Colors.orange, + ), + size: Size.infinite, + ); + }, ), ); } } + +class _ProgressPainter extends CustomPainter { + final double progress; + final Color color; + + _ProgressPainter({required this.progress, required this.color}); + + @override + void paint(Canvas canvas, Size size) { + final paint = Paint() + ..color = color + ..style = PaintingStyle.fill; + + final rect = RRect.fromRectAndRadius( + Rect.fromLTWH(0, 0, size.width * progress, size.height), + const Radius.circular(2), + ); + + canvas.drawRRect(rect, paint); + } + + @override + bool shouldRepaint(_ProgressPainter oldDelegate) { + return oldDelegate.progress != progress || oldDelegate.color != color; + } +} From 815dd6b4b657bacf6db456183457456a8df6f88b Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Fri, 30 Aug 2024 17:24:58 +0530 Subject: [PATCH 173/275] [auth][perf] Cache timer progress widget --- auth/lib/ui/code_timer_progress.dart | 11 +++++++++++ auth/lib/ui/code_widget.dart | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/auth/lib/ui/code_timer_progress.dart b/auth/lib/ui/code_timer_progress.dart index 98538788ed..a825a6ca43 100644 --- a/auth/lib/ui/code_timer_progress.dart +++ b/auth/lib/ui/code_timer_progress.dart @@ -2,6 +2,17 @@ import 'package:ente_auth/theme/ente_theme.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; +class CodeTimerProgressCache { + static final Map _cache = {}; + + static CodeTimerProgress getCachedWidget(int period) { + if (!_cache.containsKey(period)) { + _cache[period] = CodeTimerProgress(period: period); + } + return _cache[period]!; + } +} + class CodeTimerProgress extends StatefulWidget { final int period; diff --git a/auth/lib/ui/code_widget.dart b/auth/lib/ui/code_widget.dart index 4cd263be5a..cb073e5dea 100644 --- a/auth/lib/ui/code_widget.dart +++ b/auth/lib/ui/code_widget.dart @@ -111,8 +111,8 @@ class _CodeWidgetState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ if (widget.code.type.isTOTPCompatible) - CodeTimerProgress( - period: widget.code.period, + CodeTimerProgressCache.getCachedWidget( + widget.code.period, ), const SizedBox(height: 28), Row( From 7354f69dc3a7a6d73c95701438c181e7d37d8f0d Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Fri, 30 Aug 2024 17:25:22 +0530 Subject: [PATCH 174/275] [auth][perf] Avoid redundant totp computation --- auth/lib/ui/code_widget.dart | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/auth/lib/ui/code_widget.dart b/auth/lib/ui/code_widget.dart index cb073e5dea..4c3e748e3a 100644 --- a/auth/lib/ui/code_widget.dart +++ b/auth/lib/ui/code_widget.dart @@ -49,6 +49,7 @@ class _CodeWidgetState extends State { late bool _shouldShowLargeIcon; late bool _hideCode; bool isMaskingEnabled = false; + int _codeTimeStep = -1; @override void initState() { @@ -57,11 +58,22 @@ class _CodeWidgetState extends State { _hideCode = isMaskingEnabled; _everySecondTimer = Timer.periodic(const Duration(milliseconds: 500), (Timer t) { - String newCode = _getCurrentOTP(); - if (newCode != _currentCode.value) { - _currentCode.value = newCode; - if (widget.code.type.isTOTPCompatible) { - _nextCode.value = _getNextTotp(); + int newStep = 0; + if (widget.code.type != Type.hotp) { + newStep = (((DateTime.now().millisecondsSinceEpoch ~/ 1000).round()) ~/ + widget.code.period) + .floor(); + } else { + newStep = widget.code.counter; + } + if (_codeTimeStep != newStep) { + _codeTimeStep = newStep; + String newCode = _getCurrentOTP(); + if (newCode != _currentCode.value) { + _currentCode.value = newCode; + if (widget.code.type.isTOTPCompatible) { + _nextCode.value = _getNextTotp(); + } } } }); From d40dc0617147f5ac9709ec4ffb0a1d8cb49d48cb Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Sun, 1 Sep 2024 22:53:24 +0200 Subject: [PATCH 175/275] [mob][photos] MVP logs working in isolate --- .../core/error-reporting/isolate_logging.dart | 59 +++++++++++++++++++ .../core/error-reporting/super_logging.dart | 8 ++- .../face_clustering_service.dart | 7 ++- .../machine_learning/ml_computer.dart | 31 +++++++++- .../machine_learning/ml_indexing_isolate.dart | 5 +- .../ui/settings/ml/ml_user_dev_screen.dart | 11 ++++ 6 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 mobile/lib/core/error-reporting/isolate_logging.dart diff --git a/mobile/lib/core/error-reporting/isolate_logging.dart b/mobile/lib/core/error-reporting/isolate_logging.dart new file mode 100644 index 0000000000..0d686178f8 --- /dev/null +++ b/mobile/lib/core/error-reporting/isolate_logging.dart @@ -0,0 +1,59 @@ +import "dart:collection" show Queue; +import "dart:convert" show jsonEncode, jsonDecode; + +import "package:logging/logging.dart"; +import "package:photos/core/error-reporting/super_logging.dart"; + +class IsolateLogString { + final String logString; + final Object? error; + + IsolateLogString(this.logString, this.error); + + String toJsonString() => jsonEncode({ + 'logString': logString, + 'error': error, + }); + + static IsolateLogString fromJsonString(String jsonString) { + final json = jsonDecode(jsonString); + return IsolateLogString( + json['logString'] as String, + json['error'], + ); + } +} + +class IsolateLogger { + final Queue fileQueueEntries = Queue(); + + Future onLogRecordInIsolate(LogRecord rec) async { + final str = "[ISOLATE]" + rec.toPrettyString(); + + // write to stdout + SuperLogging.printLog(str); + + // push to log queue + fileQueueEntries.add(IsolateLogString(str, rec.error != null)); + } + + /// WARNING: only call this from the isolate + Queue getLogStringsAndClear() { + if (fileQueueEntries.isEmpty) return Queue(); + final result = Queue(); + while (fileQueueEntries.isNotEmpty) { + final entry = fileQueueEntries.removeFirst(); + result.add(entry.toJsonString()); + } + return result; + } + + /// WARNING: only call this from the main thread + static void handLogStringsToMainLogger(Queue logs) { + while (logs.isNotEmpty) { + final logString = logs.removeFirst(); + final log = IsolateLogString.fromJsonString(logString); + SuperLogging.saveLogString(log.logString, log.error); + } + } +} diff --git a/mobile/lib/core/error-reporting/super_logging.dart b/mobile/lib/core/error-reporting/super_logging.dart index 2a677b3fd3..f146b1b14c 100644 --- a/mobile/lib/core/error-reporting/super_logging.dart +++ b/mobile/lib/core/error-reporting/super_logging.dart @@ -270,6 +270,10 @@ class SuperLogging { // write to stdout printLog(str); + saveLogString(str, rec.error); + } + + static void saveLogString(String str, Object? error) { // push to log queue if (fileIsEnabled) { fileQueueEntries.add(str + '\n'); @@ -279,8 +283,8 @@ class SuperLogging { } // add error to sentry queue - if (sentryIsEnabled && rec.error != null) { - _sendErrorToSentry(rec.error!, null).ignore(); + if (sentryIsEnabled && error != null) { + _sendErrorToSentry(error, null).ignore(); } } diff --git a/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart b/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart index 66fa306dcd..fefe2910d2 100644 --- a/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart +++ b/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart @@ -4,7 +4,7 @@ import "dart:isolate"; import "dart:typed_data" show Uint8List; import "package:computer/computer.dart"; -import "package:flutter/foundation.dart" show kDebugMode; +import "package:flutter/foundation.dart" show debugPrint, kDebugMode; import "package:logging/logging.dart"; import "package:ml_linalg/dtype.dart"; import "package:ml_linalg/vector.dart"; @@ -120,7 +120,10 @@ class FaceClusteringService { /// The main execution function of the isolate. static void _isolateMain(SendPort mainSendPort) async { Logger.root.level = kDebugMode ? Level.ALL : Level.INFO; - Logger.root.onRecord.listen(SuperLogging.onLogRecord); + // TODO:lau move to right isolate logging + Logger.root.onRecord.listen((LogRecord rec) { + debugPrint('[MLIsolate] ${rec.toPrettyString()}'); + }); final receivePort = ReceivePort(); mainSendPort.send(receivePort.sendPort); diff --git a/mobile/lib/services/machine_learning/ml_computer.dart b/mobile/lib/services/machine_learning/ml_computer.dart index 78743bbd84..f027208758 100644 --- a/mobile/lib/services/machine_learning/ml_computer.dart +++ b/mobile/lib/services/machine_learning/ml_computer.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import "dart:collection" show Queue; import "dart:io" show File; import 'dart:isolate'; import 'dart:typed_data' show Uint8List; @@ -6,7 +7,7 @@ import 'dart:typed_data' show Uint8List; import "package:dart_ui_isolate/dart_ui_isolate.dart"; import "package:flutter/foundation.dart" show kDebugMode; import "package:logging/logging.dart"; -import "package:photos/core/error-reporting/super_logging.dart"; +import "package:photos/core/error-reporting/isolate_logging.dart"; import "package:photos/models/ml/face/box.dart"; import "package:photos/services/machine_learning/ml_model.dart"; import "package:photos/services/machine_learning/semantic_search/clip/clip_text_encoder.dart"; @@ -20,6 +21,7 @@ enum MLComputerOperation { loadModel, initializeClipTokenizer, runClipText, + testLogging, } class MLComputer { @@ -62,7 +64,8 @@ class MLComputer { @pragma('vm:entry-point') static void _isolateMain(SendPort mainSendPort) async { Logger.root.level = kDebugMode ? Level.ALL : Level.INFO; - Logger.root.onRecord.listen(SuperLogging.onLogRecord); + final IsolateLogger isolateLogger = IsolateLogger(); + Logger.root.onRecord.listen(isolateLogger.onLogRecordInIsolate); final receivePort = ReceivePort(); mainSendPort.send(receivePort.sendPort); @@ -106,6 +109,14 @@ class MLComputer { final textEmbedding = await ClipTextEncoder.predict(args); sendPort.send(List.from(textEmbedding, growable: false)); break; + case MLComputerOperation.testLogging: + final logger = Logger('XXX MLComputerTestLogging'); + logger.info("XXX logging from isolate is working!!!"); + final Queue logStrings = + isolateLogger.getLogStringsAndClear(); + final test = [List.from(logStrings)]; + sendPort.send(test); + break; } } catch (e, stackTrace) { sendPort @@ -221,4 +232,20 @@ class MLComputer { } }); } + + Future testLogging() async { + try { + final test = await _runInIsolate( + ( + MLComputerOperation.testLogging, + {}, + ), + ) as List>; + IsolateLogger.handLogStringsToMainLogger(Queue.from(test[0])); + return; + } catch (e, s) { + _logger.severe("XXX Could not test logging in isolate", e, s); + rethrow; + } + } } diff --git a/mobile/lib/services/machine_learning/ml_indexing_isolate.dart b/mobile/lib/services/machine_learning/ml_indexing_isolate.dart index 66772dd40b..996a766d64 100644 --- a/mobile/lib/services/machine_learning/ml_indexing_isolate.dart +++ b/mobile/lib/services/machine_learning/ml_indexing_isolate.dart @@ -67,7 +67,10 @@ class MLIndexingIsolate { @pragma('vm:entry-point') static void _isolateMain(SendPort mainSendPort) async { Logger.root.level = kDebugMode ? Level.ALL : Level.INFO; - Logger.root.onRecord.listen(SuperLogging.onLogRecord); + // TODO:lau move to right isolate logging + Logger.root.onRecord.listen((LogRecord rec) { + debugPrint('[MLIsolate] ${rec.toPrettyString()}'); + }); final receivePort = ReceivePort(); mainSendPort.send(receivePort.sendPort); receivePort.listen((message) async { diff --git a/mobile/lib/ui/settings/ml/ml_user_dev_screen.dart b/mobile/lib/ui/settings/ml/ml_user_dev_screen.dart index 8d70cee21b..7c4d808592 100644 --- a/mobile/lib/ui/settings/ml/ml_user_dev_screen.dart +++ b/mobile/lib/ui/settings/ml/ml_user_dev_screen.dart @@ -3,6 +3,7 @@ import "package:photos/core/event_bus.dart"; import "package:photos/db/ml/clip_db.dart"; import "package:photos/db/ml/db.dart"; import "package:photos/events/people_changed_event.dart"; +import "package:photos/services/machine_learning/ml_computer.dart"; import "package:photos/services/machine_learning/semantic_search/semantic_search_service.dart"; import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/components/buttons/button_widget.dart"; @@ -55,6 +56,16 @@ class MLUserDeveloperOptions extends StatelessWidget { await deleteAllLocalML(context); }, ), + // TODO:lau remove below code + const SizedBox(height: 24), + ButtonWidget( + buttonType: ButtonType.neutral, + labelText: "Log something in isolate", + onTap: () async { + await MLComputer.instance.testLogging(); + showShortToast(context, "Done"); + }, + ), const SafeArea( child: SizedBox( height: 12, From 746aa4cb9617e97881053a0eee5610e0a68fc5d6 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Mon, 2 Sep 2024 00:32:36 +0000 Subject: [PATCH 176/275] New Crowdin translations by GitHub Action --- .../base/locales/pl-PL/translation.json | 4 +-- .../base/locales/pt-BR/translation.json | 4 +-- .../base/locales/ru-RU/translation.json | 32 +++++++++---------- .../base/locales/sv-SE/translation.json | 2 +- .../base/locales/zh-CN/translation.json | 2 +- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/web/packages/base/locales/pl-PL/translation.json b/web/packages/base/locales/pl-PL/translation.json index 33a6a9ba1a..61e464e0af 100644 --- a/web/packages/base/locales/pl-PL/translation.json +++ b/web/packages/base/locales/pl-PL/translation.json @@ -41,7 +41,7 @@ "REFERRAL_CODE_HINT": "Jak usłyszałeś/aś o Ente? (opcjonalnie)", "REFERRAL_INFO": "Nie śledzimy instalacji aplikacji. Pomogłyby nam, gdybyś powiedział/a nam, gdzie nas znalazłeś/aś!", "PASSPHRASE_MATCH_ERROR": "Hasła nie pasują do siebie", - "create_albums": "", + "create_albums": "Utwórz albumy", "CREATE_COLLECTION": "Nowy album", "ENTER_ALBUM_NAME": "Nazwa albumu", "CLOSE_OPTION": "Zamknij (Esc)", @@ -302,7 +302,7 @@ "THUMBNAIL_GENERATION_FAILED_UPLOADS": "Generowanie miniatur nie powiodło się", "UNSUPPORTED_FILES": "Nieobsługiwane pliki", "SUCCESSFUL_UPLOADS": "Pomyślne przesłania", - "SKIPPED_INFO": "", + "SKIPPED_INFO": "Pominięto te pliki, ponieważ są pliki z pasującymi nazwami i zawartością w tym samym albumie", "UNSUPPORTED_INFO": "Ente nie obsługuje jeszcze tych formatów plików", "BLOCKED_UPLOADS": "Zablokowane przesłania", "INPROGRESS_METADATA_EXTRACTION": "W toku", diff --git a/web/packages/base/locales/pt-BR/translation.json b/web/packages/base/locales/pt-BR/translation.json index 4b9245dfcd..6e640539b1 100644 --- a/web/packages/base/locales/pt-BR/translation.json +++ b/web/packages/base/locales/pt-BR/translation.json @@ -41,7 +41,7 @@ "REFERRAL_CODE_HINT": "Como você ouviu sobre o Ente? (opcional)", "REFERRAL_INFO": "Não rastreamos instalações do aplicativo. Seria útil se você nos contasse onde nos encontrou!", "PASSPHRASE_MATCH_ERROR": "As senhas não coincidem", - "create_albums": "", + "create_albums": "Criar álbuns", "CREATE_COLLECTION": "Novo álbum", "ENTER_ALBUM_NAME": "Nome do álbum", "CLOSE_OPTION": "Fechar (Esc)", @@ -302,7 +302,7 @@ "THUMBNAIL_GENERATION_FAILED_UPLOADS": "Falha ao gerar miniaturas", "UNSUPPORTED_FILES": "Arquivos não suportados", "SUCCESSFUL_UPLOADS": "Envios bem sucedidos", - "SKIPPED_INFO": "", + "SKIPPED_INFO": "Estes foram pulados, pois há arquivos com nome e conteúdo correspondentes no mesmo álbum", "UNSUPPORTED_INFO": "ente ainda não suporta estes formatos de arquivo", "BLOCKED_UPLOADS": "Envios bloqueados", "INPROGRESS_METADATA_EXTRACTION": "Em andamento", diff --git a/web/packages/base/locales/ru-RU/translation.json b/web/packages/base/locales/ru-RU/translation.json index e8aa1eb726..26a8fb055c 100644 --- a/web/packages/base/locales/ru-RU/translation.json +++ b/web/packages/base/locales/ru-RU/translation.json @@ -1,11 +1,11 @@ { - "HERO_SLIDE_1_TITLE": "
Личные резервные копии
для твоих воспоминаний
", + "HERO_SLIDE_1_TITLE": "
Приватные резервные копии
для ваших воспоминаний
", "HERO_SLIDE_1": "Сквозное шифрование по умолчанию", "HERO_SLIDE_2_TITLE": "
Надежно хранится
в убежище от радиоактивных осадков
", "HERO_SLIDE_2": "Созданный для того, чтобы пережить", "HERO_SLIDE_3_TITLE": "
Доступно
везде
", "HERO_SLIDE_3": "Android, iOS, Веб, ПК", - "LOGIN": "Авторизоваться", + "LOGIN": "Войти", "SIGN_UP": "Регистрация", "NEW_USER": "Новенький в Ente", "EXISTING_USER": "Существующий пользователь", @@ -19,7 +19,7 @@ "ENTER_OTT": "Проверочный код", "RESEND_MAIL": "Отправить код еще раз", "VERIFY": "Подтвердить", - "UNKNOWN_ERROR": "Что-то пошло не так, Попробуйте еще раз", + "UNKNOWN_ERROR": "Что-то пошло не так, попробуйте еще раз", "INVALID_CODE": "Неверный код подтверждения", "EXPIRED_CODE": "Срок действия вашего проверочного кода истек", "SENDING": "Отправка...", @@ -28,7 +28,7 @@ "link_password_description": "Введите пароль, чтобы разблокировать альбом", "unlock": "Разблокировать", "SET_PASSPHRASE": "Установить пароль", - "VERIFY_PASSPHRASE": "Войти", + "VERIFY_PASSPHRASE": "Зарегистрироваться", "INCORRECT_PASSPHRASE": "Неверный пароль", "ENTER_ENC_PASSPHRASE": "Пожалуйста, введите пароль, который мы можем использовать для шифрования ваших данных", "PASSPHRASE_DISCLAIMER": "Мы не храним ваш пароль, поэтому, если вы его забудете,\nмы ничем не сможем вам помочь\nвосстановите ваши данные без ключа восстановления.", @@ -41,7 +41,7 @@ "REFERRAL_CODE_HINT": "Как вы узнали о Ente? (необязательно)", "REFERRAL_INFO": "Будет полезно, если вы укажете, где нашли нас, так как мы не отслеживаем установки приложения!", "PASSPHRASE_MATCH_ERROR": "Пароли не совпадают", - "create_albums": "", + "create_albums": "Создать альбомы", "CREATE_COLLECTION": "Новый альбом", "ENTER_ALBUM_NAME": "Название альбома", "CLOSE_OPTION": "Закрыть (Esc)", @@ -176,7 +176,7 @@ "UPDATE_PAYMENT_METHOD": "Обновить платёжную информацию", "MONTHLY": "Ежемесячно", "YEARLY": "Ежегодно", - "MONTH_SHORT": "мо", + "MONTH_SHORT": "мес", "YEAR": "год", "update_subscription_title": "Подтвердить изменение плана", "UPDATE_SUBSCRIPTION_MESSAGE": "Хотите сменить текущий план?", @@ -302,7 +302,7 @@ "THUMBNAIL_GENERATION_FAILED_UPLOADS": "Не удалось создать миниатюру", "UNSUPPORTED_FILES": "Неподдерживаемые файлы", "SUCCESSFUL_UPLOADS": "Успешные загрузки", - "SKIPPED_INFO": "", + "SKIPPED_INFO": "Пропущено, так как в альбоме есть файлы с совпадающими именем и содержимым", "UNSUPPORTED_INFO": "Ente пока не поддерживает эти форматы файлов", "BLOCKED_UPLOADS": "Заблокированные загрузки", "INPROGRESS_METADATA_EXTRACTION": "В процессе", @@ -336,8 +336,8 @@ "DELETE_PERMANENTLY": "Удалить навсегда", "RESTORE": "Восстанавливать", "RESTORE_TO_COLLECTION": "Восстановить в альбом", - "EMPTY_TRASH": "Пустой мусор", - "EMPTY_TRASH_TITLE": "Пустой мусор?", + "EMPTY_TRASH": "Очистить корзину", + "EMPTY_TRASH_TITLE": "Очистить корзину?", "EMPTY_TRASH_MESSAGE": "Эти файлы будут безвозвратно удалены из вашей учетной записи Ente.", "LEAVE_SHARED_ALBUM": "Да, уходи", "LEAVE_ALBUM": "Оставить альбом", @@ -486,15 +486,15 @@ "indexing": "Индексирование", "processed": "Обработано", "indexing_status_running": "Выполняется", - "indexing_status_fetching": "", + "indexing_status_fetching": "Получение", "indexing_status_scheduled": "Запланировано", "indexing_status_done": "Готово", "ml_search_disable": "Отключить машинное обучение", "ml_search_disable_confirm": "Вы хотите отключить машинное обучение на всех ваших устройствах?", - "ml_consent": "", - "ml_consent_title": "", - "ml_consent_description": "", - "ml_consent_confirmation": "", + "ml_consent": "Включить машинное обучение", + "ml_consent_title": "Включить машинное обучение?", + "ml_consent_description": "

Если вы включите машинное обучение, Ente будет извлекать информацию из файлов (например, геометрию лица), включая те, которыми с вами поделились.

Это будет происходить на вашем устройстве, и любая сгенерированная биометрическая информация будет зашифрована с использованием сквозного (End-to-End) шифрования

Пожалуйста нажмите здесь для получения дополнительной информации об этой функции в нашей политике конфиденциальности

", + "ml_consent_confirmation": "Я понимаю, и хочу разрешить машинное обучение", "labs": "Лаборатории", "YOURS": "твой", "passphrase_strength_weak": "Надежность пароля: слабая", @@ -533,8 +533,8 @@ "EXPORT_PROGRESS": "{{progress.success, number}} / {{progress.total, number}} синхронизированные элементы", "MIGRATING_EXPORT": "Подготовка...", "RENAMING_COLLECTION_FOLDERS": "Переименование папок альбомов...", - "TRASHING_DELETED_FILES": "Удаление удаленных файлов...", - "TRASHING_DELETED_COLLECTIONS": "Удаление удаленных альбомов...", + "TRASHING_DELETED_FILES": "Очистка удаленных файлов...", + "TRASHING_DELETED_COLLECTIONS": "Очистка удаленных альбомов...", "CONTINUOUS_EXPORT": "Непрерывная синхронизация", "PENDING_ITEMS": "Отложенные пункты", "EXPORT_STARTING": "Запуск экспорта...", diff --git a/web/packages/base/locales/sv-SE/translation.json b/web/packages/base/locales/sv-SE/translation.json index 59aaf3dc88..48bea6d012 100644 --- a/web/packages/base/locales/sv-SE/translation.json +++ b/web/packages/base/locales/sv-SE/translation.json @@ -41,7 +41,7 @@ "REFERRAL_CODE_HINT": "Hur hörde du talas om Ente? (valfritt)", "REFERRAL_INFO": "Vi spårar inte appinstallationer, Det skulle hjälpa oss om du berättade var du hittade oss!", "PASSPHRASE_MATCH_ERROR": "Lösenorden matchar inte", - "create_albums": "", + "create_albums": "Skapa album", "CREATE_COLLECTION": "Nytt album", "ENTER_ALBUM_NAME": "Albumnamn", "CLOSE_OPTION": "Stäng (Esc)", diff --git a/web/packages/base/locales/zh-CN/translation.json b/web/packages/base/locales/zh-CN/translation.json index 8e5cb95bea..66fc6fa6f9 100644 --- a/web/packages/base/locales/zh-CN/translation.json +++ b/web/packages/base/locales/zh-CN/translation.json @@ -41,7 +41,7 @@ "REFERRAL_CODE_HINT": "您是如何知道Ente的? (可选的)", "REFERRAL_INFO": "我们不跟踪应用程序安装情况,如果您告诉我们您是在哪里找到我们的,将会有所帮助!", "PASSPHRASE_MATCH_ERROR": "两次输入的密码不一致", - "create_albums": "", + "create_albums": "创建相册", "CREATE_COLLECTION": "新建相册", "ENTER_ALBUM_NAME": "相册名称", "CLOSE_OPTION": "关闭 (或按Esc键)", From 71644e255d3e28714d3478e11f22c87227f24fe9 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Mon, 2 Sep 2024 01:04:42 +0000 Subject: [PATCH 177/275] New Crowdin translations by GitHub Action --- mobile/lib/l10n/intl_da.arb | 1 - mobile/lib/l10n/intl_de.arb | 2 +- mobile/lib/l10n/intl_es.arb | 1 - mobile/lib/l10n/intl_fa.arb | 1 - mobile/lib/l10n/intl_fr.arb | 34 ++++++++++- mobile/lib/l10n/intl_he.arb | 1 - mobile/lib/l10n/intl_hi.arb | 1 - mobile/lib/l10n/intl_id.arb | 58 +++++++++++++++++- mobile/lib/l10n/intl_it.arb | 117 +++++++++++++++++++++++++++++++++++- mobile/lib/l10n/intl_nl.arb | 8 ++- mobile/lib/l10n/intl_no.arb | 1 - mobile/lib/l10n/intl_pl.arb | 4 +- mobile/lib/l10n/intl_pt.arb | 4 +- mobile/lib/l10n/intl_ru.arb | 24 +++++--- mobile/lib/l10n/intl_sv.arb | 2 +- mobile/lib/l10n/intl_ta.arb | 19 ++++++ mobile/lib/l10n/intl_th.arb | 1 - mobile/lib/l10n/intl_tr.arb | 1 - mobile/lib/l10n/intl_zh.arb | 4 +- 19 files changed, 257 insertions(+), 27 deletions(-) create mode 100644 mobile/lib/l10n/intl_ta.arb diff --git a/mobile/lib/l10n/intl_da.arb b/mobile/lib/l10n/intl_da.arb index 49c26657f9..e4b2cc656b 100644 --- a/mobile/lib/l10n/intl_da.arb +++ b/mobile/lib/l10n/intl_da.arb @@ -12,7 +12,6 @@ "deleteAccountFeedbackPrompt": "Vi er kede af at du forlader os. Forklar venligst hvorfor, så vi kan forbedre os.", "feedback": "Feedback", "kindlyHelpUsWithThisInformation": "Hjælp os venligst med disse oplysninger", - "confirmDeletePrompt": "Ja, jeg ønsker at slette denne konto og alle dens data permanent.", "confirmAccountDeletion": "Bekræft Sletning Af Konto", "deleteAccountPermanentlyButton": "Slet konto permanent", "yourAccountHasBeenDeleted": "Din konto er blevet slettet", diff --git a/mobile/lib/l10n/intl_de.arb b/mobile/lib/l10n/intl_de.arb index aa50482f8d..50f0248d40 100644 --- a/mobile/lib/l10n/intl_de.arb +++ b/mobile/lib/l10n/intl_de.arb @@ -12,7 +12,7 @@ "deleteAccountFeedbackPrompt": "Wir bedauern sehr, dass du dein Konto löschen möchtest. Du würdest uns sehr helfen, wenn du uns kurz einige Gründe hierfür nennen könntest.", "feedback": "Rückmeldung", "kindlyHelpUsWithThisInformation": "Bitte gib diese Daten ein", - "confirmDeletePrompt": "Ja, ich möchte dieses Konto und alle enthaltenen Daten endgültig und unwiderruflich löschen.", + "confirmDeletePrompt": "Ja, ich möchte dieses Konto und alle enthaltenen Daten über alle Apps endgültig und unwiderruflich löschen.", "confirmAccountDeletion": "Kontolöschung bestätigen", "deleteAccountPermanentlyButton": "Konto unwiderruflich löschen", "yourAccountHasBeenDeleted": "Dein Benutzerkonto wurde gelöscht", diff --git a/mobile/lib/l10n/intl_es.arb b/mobile/lib/l10n/intl_es.arb index 238f61095f..3131fb37eb 100644 --- a/mobile/lib/l10n/intl_es.arb +++ b/mobile/lib/l10n/intl_es.arb @@ -12,7 +12,6 @@ "deleteAccountFeedbackPrompt": "Lamentamos que te vayas. Por favor, explícanos el motivo para ayudarnos a mejorar.", "feedback": "Sugerencias", "kindlyHelpUsWithThisInformation": "Por favor ayúdanos con esta información", - "confirmDeletePrompt": "Sí, quiero eliminar permanentemente esta cuenta y todos sus datos.", "confirmAccountDeletion": "Confirmar borrado de cuenta", "deleteAccountPermanentlyButton": "Eliminar cuenta permanentemente", "yourAccountHasBeenDeleted": "Tu cuenta ha sido eliminada", diff --git a/mobile/lib/l10n/intl_fa.arb b/mobile/lib/l10n/intl_fa.arb index d5dbe63862..8d957cf574 100644 --- a/mobile/lib/l10n/intl_fa.arb +++ b/mobile/lib/l10n/intl_fa.arb @@ -12,7 +12,6 @@ "deleteAccountFeedbackPrompt": "ما متاسفیم که می‌بینیم شما می‌روید. لطفا نظرات خود را برای کمک به بهبود ما به اشتراک بگذارید.", "feedback": "بازخورد", "kindlyHelpUsWithThisInformation": "لطفا با این اطلاعات به ما کمک کنید", - "confirmDeletePrompt": "بله، من می‌خواهم برای همیشه این حساب کاربری و تمام اطلاعات آن را حذف کنم.", "confirmAccountDeletion": "تایید حذف حساب کاربری", "deleteAccountPermanentlyButton": "حذف دائمی حساب کاربری", "yourAccountHasBeenDeleted": "حساب کاربری شما حذف شده است", diff --git a/mobile/lib/l10n/intl_fr.arb b/mobile/lib/l10n/intl_fr.arb index 8f4b1e375e..01cf3c930d 100644 --- a/mobile/lib/l10n/intl_fr.arb +++ b/mobile/lib/l10n/intl_fr.arb @@ -12,7 +12,7 @@ "deleteAccountFeedbackPrompt": "Nous sommes désolés de vous voir partir. N'hésitez pas à partager vos commentaires pour nous aider à améliorer le service.", "feedback": "Commentaires", "kindlyHelpUsWithThisInformation": "Merci de nous aider avec cette information", - "confirmDeletePrompt": "Oui, je veux supprimer définitivement ce compte et toutes ses données.", + "confirmDeletePrompt": "Oui, je veux supprimer définitivement ce compte et ses données dans toutes les applications.", "confirmAccountDeletion": "Confirmer la suppression du compte", "deleteAccountPermanentlyButton": "Supprimer définitivement le compte", "yourAccountHasBeenDeleted": "Votre compte a été supprimé", @@ -277,6 +277,7 @@ "change": "Modifier", "unavailableReferralCode": "Désolé, ce code n'est pas disponible.", "codeChangeLimitReached": "Désolé, vous avez atteint la limite de changements de code.", + "onlyFamilyAdminCanChangeCode": "Veuillez contacter {familyAdminEmail} pour modifier votre code.", "storageInGB": "{storageAmountInGB} Go", "claimed": "Réclamée", "@claimed": { @@ -413,7 +414,13 @@ "photoGridSize": "Taille de la grille photo", "manageDeviceStorage": "Gérer le stockage de l'appareil", "machineLearning": "Apprentissage automatique", + "mlConsent": "Activer l'apprentissage automatique", + "mlConsentTitle": "Activer l'apprentissage automatique ?", + "mlConsentDescription": "Si vous activez l'apprentissage automatique, Ente extraira des informations comme la géométrie des visages, incluant les photos partagées avec vous. \nCela se fera sur votre appareil, avec un cryptage de bout-en-bout de toutes les données biométriques générées.", + "mlConsentPrivacy": "Veuillez cliquer ici pour plus de détails sur cette fonctionnalité dans notre politique de confidentialité", + "mlConsentConfirmation": "Je comprends, et souhaite activer l'apprentissage automatique", "magicSearch": "Recherche magique", + "mlIndexingDescription": "Veuillez noter que l'apprentissage automatique entraînera une augmentation de l'utilisation de la bande passante et de la batterie, jusqu'à ce que tous les éléments soient indexés. \nEnvisagez d'utiliser l'application de bureau pour une indexation plus rapide, tous les résultats seront automatiquement synchronisés.", "loadingModel": "Téléchargement des modèles...", "waitingForWifi": "En attente de connexion Wi-Fi...", "status": "État", @@ -489,6 +496,7 @@ "removeDuplicates": "Supprimer les doublons", "removeDuplicatesDesc": "Examiner et supprimer les fichiers qui sont des doublons exacts.", "viewLargeFiles": "Fichiers volumineux", + "viewLargeFilesDesc": "Afficher les fichiers qui consomment le plus de stockage.", "noDuplicates": "✨ Aucun doublon", "youveNoDuplicateFilesThatCanBeCleared": "Vous n'avez aucun fichier dédupliqué pouvant être nettoyé", "success": "Succès", @@ -1145,6 +1153,7 @@ "successfullyHid": "Masquage réussi", "successfullyUnhid": "Masquage réussi", "crashReporting": "Rapports d'erreurs", + "resumableUploads": "Chargements à poursuivre", "addToHiddenAlbum": "Ajouter à un album masqué", "moveToHiddenAlbum": "Déplacer vers un album masqué", "fileTypes": "Types de fichiers", @@ -1247,12 +1256,29 @@ "foundFaces": "Visages trouvés", "clusteringProgress": "Progression du regroupement", "indexingIsPaused": "L'indexation est en pause. Elle reprendra automatiquement lorsque l'appareil sera prêt.", + "trim": "Recadrer", + "crop": "Rogner", "rotate": "Pivoter", "left": "Gauche", "right": "Droite", "whatsNew": "Nouveautés", "reviewSuggestions": "Consulter les suggestions", "useAsCover": "Utiliser comme couverture", + "notPersonLabel": "Pas {name}?", + "@notPersonLabel": { + "description": "Label to indicate that the person in the photo is not the person whose name is mentioned", + "placeholders": { + "name": { + "content": "{name}", + "type": "String" + } + } + }, + "enable": "Activer", + "enabled": "Activé", + "moreDetails": "Plus de détails", + "enableMLIndexingDesc": "Ente prend en charge l'apprentissage automatique sur l'appareil pour la reconnaissance faciale, la recherche magique et d'autres fonctionnalités de recherche avancée", + "magicSearchHint": "La recherche magique permet de rechercher des photos par leur contenu, par exemple 'fleur', 'voiture rouge', 'documents d'identité'", "panorama": "Panorama", "reenterPassword": "Ressaisir le mot de passe", "reenterPin": "Ressaisir le code PIN", @@ -1278,6 +1304,8 @@ "pleaseSelectQuickLinksToRemove": "Veuillez sélectionner les liens rapides à supprimer", "removePublicLinks": "Supprimer les liens publics", "thisWillRemovePublicLinksOfAllSelectedQuickLinks": "Ceci supprimera les liens publics de tous les liens rapides sélectionnés.", + "guestView": "Vue invité", + "guestViewEnablePreSteps": "Pour activer la vue invité, veuillez configurer le code d'accès de l'appareil ou le verrouillage de l'écran dans les paramètres de votre système.", "cl_guest_view_title": "Vue invité", "cl_guest_view_description": "Montrer des photos à un ami en les transmettant sur votre téléphone ? Ne vous inquiétez pas si vous les faites glisser trop loin.\nLa vue \"invité\" les verrouillera dans les photos que vous avez sélectionnées.", "cl_guest_view_call_to_action": "Sélectionnez les photos et fixez les en \"Vue Invité\".", @@ -1285,5 +1313,7 @@ "cl_panorama_viewer_description": "Nous avons ajouté le support pour visionner des photos panoramiques avec des vues à 360 degrés. L'expérience est immersive avec la navigation basée sur les mouvements !", "cl_video_player_title": "Lecteur vidéo", "cl_video_player_description": "Intégration d'un nouveau lecteur vidéo, avec de meilleurs contrôles de lecture et la prise en charge des vidéos HDR.", - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Pour activer le verrouillage d'application, veuillez configurer le code d'accès de l'appareil ou le verrouillage de l'écran dans les paramètres de votre système." + "appLockDescriptions": "Choisissez entre l'écran de verrouillage par défaut de votre appareil et un écran de verrouillage personnalisé avec un code PIN ou un mot de passe.", + "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Pour activer le verrouillage d'application, veuillez configurer le code d'accès de l'appareil ou le verrouillage de l'écran dans les paramètres de votre système.", + "authToViewPasskey": "Veuillez vous authentifier pour afficher votre clé de récupération" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_he.arb b/mobile/lib/l10n/intl_he.arb index ad713b19d7..9342d8cf07 100644 --- a/mobile/lib/l10n/intl_he.arb +++ b/mobile/lib/l10n/intl_he.arb @@ -12,7 +12,6 @@ "deleteAccountFeedbackPrompt": "אנחנו מצטערים לראות שאתה עוזב. אנא תחלוק את המשוב שלך כדי לעזור לנו להשתפר.", "feedback": "משוב", "kindlyHelpUsWithThisInformation": "אנא עזור לנו עם המידע הזה", - "confirmDeletePrompt": "כן, אני רוצה למחוק לצמיתות את החשבון הזה וכל המידע שלו.", "confirmAccountDeletion": "אשר את מחיקת החשבון", "deleteAccountPermanentlyButton": "מחק את החשבון לצמיתות", "yourAccountHasBeenDeleted": "החשבון שלך נמחק", diff --git a/mobile/lib/l10n/intl_hi.arb b/mobile/lib/l10n/intl_hi.arb index 35f1e866b4..b79d9682f2 100644 --- a/mobile/lib/l10n/intl_hi.arb +++ b/mobile/lib/l10n/intl_hi.arb @@ -12,7 +12,6 @@ "deleteAccountFeedbackPrompt": "आपको जाता हुए देख कर हमें खेद है। कृपया हमें बेहतर बनने में सहायता के लिए अपनी प्रतिक्रिया साझा करें।", "feedback": "प्रतिपुष्टि", "kindlyHelpUsWithThisInformation": "कृपया हमें इस जानकारी के लिए सहायता करें", - "confirmDeletePrompt": "हां, मैं इस अकाउंट और इसके सभी डेटा को स्थायी रूप से हटाना चाहता/चाहती हूं।", "confirmAccountDeletion": "अकाउंट डिलीट करने की पुष्टि करें", "deleteAccountPermanentlyButton": "अकाउंट स्थायी रूप से डिलीट करें", "yourAccountHasBeenDeleted": "आपका अकाउंट डिलीट कर दिया गया है", diff --git a/mobile/lib/l10n/intl_id.arb b/mobile/lib/l10n/intl_id.arb index 0768a2d798..2a5c73f456 100644 --- a/mobile/lib/l10n/intl_id.arb +++ b/mobile/lib/l10n/intl_id.arb @@ -12,7 +12,7 @@ "deleteAccountFeedbackPrompt": "Kami sedih kamu pergi. Silakan bagikan masukanmu agar kami bisa jadi lebih baik.", "feedback": "Masukan", "kindlyHelpUsWithThisInformation": "Harap bantu kami dengan informasi ini", - "confirmDeletePrompt": "Ya, saya ingin menghapus akun ini dan seluruh data yang terkait secara permanen.", + "confirmDeletePrompt": "Ya, saya ingin menghapus akun ini dan seluruh datanya secara permanen di semua aplikasi.", "confirmAccountDeletion": "Konfirmasi Penghapusan Akun", "deleteAccountPermanentlyButton": "Hapus Akun Secara Permanen", "yourAccountHasBeenDeleted": "Akunmu telah dihapus", @@ -426,6 +426,7 @@ "status": "Status", "indexedItems": "Item terindeks", "pendingItems": "Item menunggu", + "clearIndexes": "Hapus indeks", "selectFoldersForBackup": "Pilih folder yang perlu dicadangkan", "selectedFoldersWillBeEncryptedAndBackedUp": "Folder yang terpilih akan dienkripsi dan dicadangkan", "unselectAll": "Batalkan semua pilihan", @@ -437,11 +438,18 @@ "showMemories": "Lihat kenangan", "yearsAgo": "{count, plural, other{{count} tahun lalu}}", "backupSettings": "Pengaturan pencadangan", + "backupStatus": "Status pencadangan", + "backupStatusDescription": "Item yang sudah dicadangkan akan terlihat di sini", "backupOverMobileData": "Cadangkan dengan data seluler", "backupVideos": "Cadangkan video", "disableAutoLock": "Nonaktifkan kunci otomatis", + "deviceLockExplanation": "Nonaktfikan kunci layar perangkat saat Ente berada di latar depan dan ada pencadangan yang sedang berlangsung. Hal ini biasanya tidak diperlukan, namun dapat membantu unggahan dan import awal berkas berkas besar selesai lebih cepat.", + "about": "Tentang", + "weAreOpenSource": "Kode kami sumber terbuka!", "privacy": "Privasi", "terms": "Ketentuan", + "checkForUpdates": "Periksa pembaruan", + "checkStatus": "Periksa status", "checking": "Memeriksa...", "youAreOnTheLatestVersion": "Kamu menggunakan versi terbaru", "account": "Akun", @@ -458,10 +466,13 @@ "yesLogout": "Ya, keluar", "aNewVersionOfEnteIsAvailable": "Versi baru dari Ente telah tersedia.", "update": "Perbarui", + "installManually": "Instal secara manual", "criticalUpdateAvailable": "Pembaruan penting tersedia", "updateAvailable": "Pembaruan tersedia", "ignoreUpdate": "Abaikan", "downloading": "Mengunduh...", + "cannotDeleteSharedFiles": "Tidak dapat menghapus file berbagi", + "theDownloadCouldNotBeCompleted": "Unduhan tidak dapat diselesaikan", "retry": "Coba lagi", "backedUpFolders": "Folder yang dicadangkan", "backup": "Pencadangan", @@ -472,8 +483,12 @@ "removeDuplicates": "Hapus duplikat", "removeDuplicatesDesc": "Lihat dan hapus file yang sama persis.", "viewLargeFiles": "File berukuran besar", + "viewLargeFilesDesc": "Tampilkan file yang banyak mengkonsumsi ruang penyimpanan.", "noDuplicates": "✨ Tak ada file duplikat", + "youveNoDuplicateFilesThatCanBeCleared": "Kamu tidak memiliki file duplikat yang dapat di hapus", "success": "Berhasil", + "rateUs": "Beri kami nilai", + "remindToEmptyDeviceTrash": "Kosongkan juga “Baru Saja Dihapus” dari “Pengaturan” -> “Penyimpanan” untuk mengklaim ruang yang baru dikosongkan", "youHaveSuccessfullyFreedUp": "Kamu telah berhasil membersihkan {storageSaved}!", "@youHaveSuccessfullyFreedUp": { "description": "The text to display when the user has successfully freed up storage", @@ -485,6 +500,7 @@ } } }, + "remindToEmptyEnteTrash": "Kosongkan juga \"Sampah\" untuk mendapatkan ruang yang baru dikosongkan", "sparkleSuccess": "✨ Berhasil", "duplicateFileCountWithStorageSaved": "Kamu telah menghapus {count, plural, other{{count} file duplikat}} dan membersihkan ({storageSaved}!)", "@duplicateFileCountWithStorageSaved": { @@ -502,14 +518,18 @@ } }, "familyPlans": "Paket keluarga", + "referrals": "Referensi", "notifications": "Notifikasi", "sharedPhotoNotifications": "Foto terbagi baru", + "sharedPhotoNotificationsExplanation": "Terima notifikasi apabila seseorang menambahkan foto ke album bersama yang kamu ikuti", "advanced": "Lanjutan", "general": "Umum", "security": "Keamanan", "authToViewYourRecoveryKey": "Harap autentikasi untuk melihat kunci pemulihan kamu", "twofactor": "Autentikasi dua langkah", "authToConfigureTwofactorAuthentication": "Harap autentikasi untuk mengatur autentikasi dua langkah", + "lockscreen": "Kunci layar", + "authToChangeLockscreenSetting": "Lakukan autentikasi untuk mengubah pengaturan kunci layar", "viewActiveSessions": "Lihat sesi aktif", "authToViewYourActiveSessions": "Harap autentikasi untuk melihat sesi aktif kamu", "disableTwofactor": "Nonaktifkan autentikasi dua langkah", @@ -519,6 +539,7 @@ "social": "Sosial", "rateUsOnStore": "Beri nilai di {storeName}", "blog": "Blog", + "merchandise": "Barang Dagangan", "twitter": "Twitter", "mastodon": "Mastodon", "matrix": "Matrix", @@ -549,6 +570,7 @@ "renewsOn": "Langganan akan diperpanjang pada {endDate}", "freeTrialValidTill": "Percobaan gratis berlaku hingga {endDate}", "validTill": "Berlaku hingga {endDate}", + "addOnValidTill": "Add-on {storageAmount} kamu berlaku sampai {endDate}", "playStoreFreeTrialValidTill": "Percobaan gratis berlaku hingga {endDate}.\nKamu dapat memilih paket berbayar setelahnya.", "subWillBeCancelledOn": "Langganan kamu akan dibatalkan pada {endDate}", "subscription": "Langganan", @@ -576,18 +598,46 @@ }, "confirmPlanChange": "Konfirmasi perubahan paket", "areYouSureYouWantToChangeYourPlan": "Apakah kamu yakin ingin mengubah paket kamu?", + "youCannotDowngradeToThisPlan": "Anda tidak dapat turun ke paket ini", + "cancelOtherSubscription": "Harap batalkan langganan kamu dari {paymentProvider} terlebih dahulu", + "@cancelOtherSubscription": { + "description": "The text to display when the user has an existing subscription from a different payment provider", + "type": "text", + "placeholders": { + "paymentProvider": { + "example": "Apple", + "type": "String" + } + } + }, "optionalAsShortAsYouLike": "Opsional, pendek pun tak apa...", "send": "Kirim", "askCancelReason": "Langganan kamu telah dibatalkan. Apakah kamu ingin membagikan alasannya?", "thankYouForSubscribing": "Terima kasih telah berlangganan!", "yourPurchaseWasSuccessful": "Pembelianmu berhasil", + "yourPlanWasSuccessfullyUpgraded": "Paket kamu berhasil ditingkatkan", + "yourPlanWasSuccessfullyDowngraded": "Paket kamu berhasil di turunkan", "yourSubscriptionWasUpdatedSuccessfully": "Langgananmu telah berhasil diperbarui", "googlePlayId": "ID Google Play", "appleId": "ID Apple", + "playstoreSubscription": "Langganan PlayStore", + "appstoreSubscription": "Langganan AppStore", "subAlreadyLinkedErrMessage": "{id} kamu telah terhubung dengan akun Ente lain.\nJika kamu ingin menggunakan {id} kamu untuk akun ini, silahkan hubungi tim bantuan kami", "visitWebToManage": "Silakan buka web.ente.io untuk mengatur langgananmu", + "couldNotUpdateSubscription": "Tidak dapat memperbarui langganan", "pleaseContactSupportAndWeWillBeHappyToHelp": "Silakan hubungi support@ente.io dan kami akan dengan senang hati membantu!", "paymentFailed": "Pembayaran gagal", + "paymentFailedTalkToProvider": "Harap hubungi dukungan {providerName} jika kamu dikenai biaya", + "@paymentFailedTalkToProvider": { + "description": "The text to display when the payment failed", + "type": "text", + "placeholders": { + "providerName": { + "example": "AppStore|PlayStore", + "type": "String" + } + } + }, "continueOnFreeTrial": "Lanjut dengan percobaan gratis", "areYouSureYouWantToExit": "Apakah kamu yakin ingin keluar?", "thankYou": "Terima kasih", @@ -601,8 +651,10 @@ "leave": "Tinggalkan", "rateTheApp": "Nilai app ini", "startBackup": "Mulai pencadangan", + "noPhotosAreBeingBackedUpRightNow": "Tidak ada foto yang sedang dicadangkan sekarang", "grantFullAccessPrompt": "Harap berikan akses ke semua foto di app Pengaturan", "openSettings": "Buka Pengaturan", + "selectMorePhotos": "Pilih lebih banyak foto", "existingUser": "Masuk", "privateBackups": "Cadangan pribadi", "forYourMemories": "untuk kenanganmu", @@ -614,6 +666,7 @@ "everywhere": "di mana saja", "androidIosWebDesktop": "Android, iOS, Web, Desktop", "mobileWebDesktop": "Seluler, Web, Desktop", + "newToEnte": "Baru di Ente", "pleaseLoginAgain": "Silakan masuk akun lagi", "autoLogoutMessage": "Akibat kesalahan teknis, kamu telah keluar dari akunmu. Kami mohon maaf atas ketidaknyamanannya.", "yourSubscriptionHasExpired": "Langgananmu telah berakhir", @@ -848,6 +901,9 @@ "networkHostLookUpErr": "Tidak dapat terhubung dengan Ente, harap periksa pengaturan jaringan kamu dan hubungi dukungan jika masalah berlanjut.", "networkConnectionRefusedErr": "Tidak dapat terhubung dengan Ente, silakan coba lagi setelah beberapa saat. Jika masalah berlanjut, harap hubungi dukungan.", "cachedData": "Data cache", + "remoteThumbnails": "Thumbnail jarak jauh", + "pendingSync": "Sinkronisasi yang tertunda", + "localGallery": "Galeri lokal", "todaysLogs": "Log hari ini", "viewLogs": "Lihat log", "preparingLogs": "Menyiapkan log...", diff --git a/mobile/lib/l10n/intl_it.arb b/mobile/lib/l10n/intl_it.arb index ac66ecca17..37ac274bda 100644 --- a/mobile/lib/l10n/intl_it.arb +++ b/mobile/lib/l10n/intl_it.arb @@ -12,7 +12,7 @@ "deleteAccountFeedbackPrompt": "Ci dispiace vederti andare via. Facci sapere se hai bisogno di aiuto o se vuoi aiutarci a migliorare.", "feedback": "Suggerimenti", "kindlyHelpUsWithThisInformation": "Aiutaci con queste informazioni", - "confirmDeletePrompt": "Sì, voglio eliminare definitivamente questo account e tutti i suoi dati.", + "confirmDeletePrompt": "Sì, voglio eliminare definitivamente questo account e i dati associati a esso su tutte le applicazioni.", "confirmAccountDeletion": "Conferma eliminazione account", "deleteAccountPermanentlyButton": "Cancella definitivamente il tuo account", "yourAccountHasBeenDeleted": "Il tuo account è stato eliminato", @@ -24,6 +24,7 @@ "sendEmail": "Invia email", "deleteRequestSLAText": "La tua richiesta verrà elaborata entro 72 ore.", "deleteEmailRequest": "Invia un'email a account-deletion@ente.io dal tuo indirizzo email registrato.", + "entePhotosPerm": "Ente necessita del permesso per preservare le tue foto", "ok": "Ok", "createAccount": "Crea account", "createNewAccount": "Crea un nuovo account", @@ -225,14 +226,17 @@ }, "description": "Number of participants in an album, including the album owner." }, + "collabLinkSectionDescription": "Crea un link per consentire alle persone di aggiungere e visualizzare foto nel tuo album condiviso senza bisogno di un'applicazione o di un account Ente. Ottimo per raccogliere foto di un evento.", "collectPhotos": "Raccogli le foto", "collaborativeLink": "Link collaborativo", + "shareWithNonenteUsers": "Condividi con utenti che non hanno un account Ente", "createPublicLink": "Crea link pubblico", "sendLink": "Invia link", "copyLink": "Copia link", "linkHasExpired": "Il link è scaduto", "publicLinkEnabled": "Link pubblico abilitato", "shareALink": "Condividi un link", + "sharedAlbumSectionDescription": "Crea album condivisi e collaborativi con altri utenti di Ente, inclusi gli utenti con piani gratuiti.", "shareWithPeopleSectionTitle": "{numberOfPeople, plural, =0 {Condividi con persone specifiche} =1 {Condividi con una persona} other {Condividi con {numberOfPeople} persone}}", "@shareWithPeopleSectionTitle": { "placeholders": { @@ -256,10 +260,12 @@ }, "verificationId": "ID di verifica", "verifyEmailID": "Verifica {email}", + "emailNoEnteAccount": "{email} non ha un account Ente.\n\nInvia un invito per condividere foto.", "shareMyVerificationID": "Ecco il mio ID di verifica: {verificationID} per ente.io.", "shareTextConfirmOthersVerificationID": "Hey, puoi confermare che questo è il tuo ID di verifica: {verificationID} su ente.io", "somethingWentWrong": "Qualcosa è andato storto", "sendInvite": "Invita", + "shareTextRecommendUsingEnte": "Scarica Ente in modo da poter facilmente condividere foto e video in qualità originale\n\nhttps://ente.io", "done": "Completato", "applyCodeTitle": "Applica codice", "enterCodeDescription": "Inserisci il codice fornito dal tuo amico per richiedere spazio gratuito per entrambi", @@ -267,6 +273,11 @@ "failedToApplyCode": "Impossibile applicare il codice", "enterReferralCode": "Inserisci il codice di invito", "codeAppliedPageTitle": "Codice applicato", + "changeYourReferralCode": "Cambia il tuo codice invito", + "change": "Cambia", + "unavailableReferralCode": "Siamo spiacenti, questo codice non è disponibile.", + "codeChangeLimitReached": "Siamo spiacenti, hai raggiunto il limite di modifiche del codice.", + "onlyFamilyAdminCanChangeCode": "Per favore contatta {familyAdminEmail} per cambiare il tuo codice.", "storageInGB": "{storageAmountInGB} GB", "claimed": "Riscattato", "@claimed": { @@ -276,6 +287,7 @@ "claimMore": "Richiedine di più!", "theyAlsoGetXGb": "Anche loro riceveranno {storageAmountInGB} GB", "freeStorageOnReferralSuccess": "{storageAmountInGB} GB ogni volta che qualcuno si iscrive a un piano a pagamento e applica il tuo codice", + "shareTextReferralCode": "Codice invito Ente: {referralCode} \n\nInseriscilo in Impostazioni → Generali → Inviti per ottenere {referralStorageInGB} GB gratis dopo la sottoscrizione a un piano a pagamento\n\nhttps://ente.io", "claimFreeStorage": "Richiedi spazio gratuito", "inviteYourFriends": "Invita i tuoi amici", "failedToFetchReferralDetails": "Impossibile recuperare i dettagli. Per favore, riprova più tardi.", @@ -298,6 +310,7 @@ } }, "faq": "FAQ", + "help": "Aiuto", "oopsSomethingWentWrong": "Oops! Qualcosa è andato storto", "peopleUsingYourCode": "Persone che hanno usato il tuo codice", "eligible": "idoneo", @@ -327,6 +340,7 @@ "removeParticipantBody": "{userEmail} verrà rimosso da questo album condiviso\n\nQualsiasi foto aggiunta dall'utente verrà rimossa dall'album", "keepPhotos": "Mantieni foto", "deletePhotos": "Elimina foto", + "inviteToEnte": "Invita su Ente", "removePublicLink": "Rimuovi link pubblico", "disableLinkMessage": "Questo rimuoverà il link pubblico per accedere a \"{albumName}\".", "sharing": "Condivisione in corso...", @@ -342,7 +356,10 @@ "videoSmallCase": "video", "photoSmallCase": "foto", "singleFileDeleteHighlight": "Verrà eliminato da tutti gli album.", + "singleFileInBothLocalAndRemote": "Questo {fileType} è sia su Ente che sul tuo dispositivo.", + "singleFileInRemoteOnly": "Questo {fileType} verrà eliminato da Ente.", "singleFileDeleteFromDevice": "Questo {fileType} verrà eliminato dal tuo dispositivo.", + "deleteFromEnte": "Elimina da Ente", "yesDelete": "Sì, elimina", "movedToTrash": "Spostato nel cestino", "deleteFromDevice": "Elimina dal dispositivo", @@ -396,6 +413,10 @@ }, "photoGridSize": "Dimensione griglia foto", "manageDeviceStorage": "Gestisci memoria dispositivo", + "mlConsentDescription": "Se abiliti il Machine Learning, Ente estrarrà informazioni come la geometria del volto dai file, inclusi quelli condivisi con te.\n\nQuesto accadrà sul tuo dispositivo, e qualsiasi informazione biometrica generata sarà crittografata end-to-end.", + "mlConsentPrivacy": "Clicca qui per maggiori dettagli su questa funzione nella nostra informativa sulla privacy", + "mlIndexingDescription": "Si prega di notare che l'attivazione dell'apprendimento automatico si tradurrà in un maggior utilizzo della connessione e della batteria fino a quando tutti gli elementi non saranno indicizzati. Valuta di utilizzare l'applicazione desktop per un'indicizzazione più veloce, tutti i risultati verranno sincronizzati automaticamente.", + "loadingModel": "Scaricamento modelli...", "waitingForWifi": "In attesa del WiFi...", "status": "Stato", "indexedItems": "Elementi indicizzati", @@ -430,11 +451,13 @@ "backupOverMobileData": "Backup su dati mobili", "backupVideos": "Backup dei video", "disableAutoLock": "Disabilita blocco automatico", + "deviceLockExplanation": "Disabilita il blocco schermo del dispositivo quando Ente è in primo piano e c'è un backup in corso. Questo normalmente non è necessario ma può aiutare a completare più velocemente grossi caricamenti e l'importazione iniziale di grandi librerie.", "about": "Info", "weAreOpenSource": "Siamo open source!", "privacy": "Privacy", "terms": "Termini d'uso", "checkForUpdates": "Controlla aggiornamenti", + "checkStatus": "Verifica stato", "checking": "Controllo in corso...", "youAreOnTheLatestVersion": "Stai utilizzando l'ultima versione", "account": "Account", @@ -449,6 +472,7 @@ "authToInitiateAccountDeletion": "Autenticati per avviare l'eliminazione dell'account", "areYouSureYouWantToLogout": "Sei sicuro di volerti disconnettere?", "yesLogout": "Sì, disconnetti", + "aNewVersionOfEnteIsAvailable": "Una nuova versione di Ente è disponibile.", "update": "Aggiorna", "installManually": "Installa manualmente", "criticalUpdateAvailable": "Un aggiornamento importante è disponibile", @@ -461,9 +485,13 @@ "backedUpFolders": "Cartelle salvate", "backup": "Backup", "freeUpDeviceSpace": "Libera spazio", + "freeUpDeviceSpaceDesc": "Risparmia spazio sul tuo dispositivo cancellando i file che sono già stati salvati online.", "allClear": "✨ Tutto pulito", "noDeviceThatCanBeDeleted": "Non hai file su questo dispositivo che possono essere eliminati", "removeDuplicates": "Rimuovi i doppioni", + "removeDuplicatesDesc": "Verifica e rimuovi i file che sono esattamente duplicati.", + "viewLargeFiles": "File di grandi dimensioni", + "viewLargeFilesDesc": "Visualizza i file che stanno occupando la maggior parte dello spazio di archiviazione.", "noDuplicates": "✨ Nessun doppione", "youveNoDuplicateFilesThatCanBeCleared": "Non hai file duplicati che possono essere cancellati", "success": "Operazione riuscita", @@ -536,6 +564,7 @@ "systemTheme": "Sistema", "freeTrial": "Prova gratuita", "selectYourPlan": "Seleziona un piano", + "enteSubscriptionPitch": "Ente conserva i tuoi ricordi in modo che siano sempre a disposizione, anche se perdi il tuo dispositivo.", "enteSubscriptionShareWithFamily": "Aggiungi la tua famiglia al tuo piano.", "currentUsageIs": "Spazio attualmente utilizzato ", "@currentUsageIs": { @@ -549,6 +578,8 @@ "renewsOn": "Si rinnova il {endDate}", "freeTrialValidTill": "La prova gratuita termina il {endDate}", "validTill": "Valido fino al {endDate}", + "addOnValidTill": "Il tuo spazio aggiuntivo di {storageAmount} è valido fino al {endDate}", + "playStoreFreeTrialValidTill": "Prova gratuita valida fino al {endDate}.\nIn seguito potrai scegliere un piano a pagamento.", "subWillBeCancelledOn": "L'abbonamento verrà cancellato il {endDate}", "subscription": "Abbonamento", "paymentDetails": "Dettagli di Pagamento", @@ -599,6 +630,7 @@ "appleId": "Apple ID", "playstoreSubscription": "Abbonamento su PlayStore", "appstoreSubscription": "abbonamento AppStore", + "subAlreadyLinkedErrMessage": "Il tuo {id} è già collegato a un altro account Ente.\nSe desideri utilizzare il tuo {id} con questo account, per favore contatta il nostro supporto''", "visitWebToManage": "Visita web.ente.io per gestire il tuo abbonamento", "couldNotUpdateSubscription": "Impossibile aggiornare l'abbonamento", "pleaseContactSupportAndWeWillBeHappyToHelp": "Contatta support@ente.io e saremo felici di aiutarti!", @@ -619,6 +651,7 @@ "thankYou": "Grazie", "failedToVerifyPaymentStatus": "Impossibile verificare lo stato del pagamento", "pleaseWaitForSometimeBeforeRetrying": "Riprova tra qualche minuto", + "paymentFailedMessage": "Purtroppo il tuo pagamento non è riuscito. Contatta l'assistenza e ti aiuteremo!", "youAreOnAFamilyPlan": "Sei un utente con piano famiglia!", "contactFamilyAdmin": "Contatta {familyAdminEmail} per gestire il tuo abbonamento", "leaveFamily": "Abbandona il piano famiglia", @@ -642,7 +675,9 @@ "everywhere": "ovunque", "androidIosWebDesktop": "Android, iOS, Web, Desktop", "mobileWebDesktop": "Mobile, Web, Desktop", + "newToEnte": "Prima volta con Ente", "pleaseLoginAgain": "Effettua nuovamente l'accesso", + "autoLogoutMessage": "A causa di problemi tecnici, sei stato disconnesso. Ci scusiamo per l'inconveniente.", "yourSubscriptionHasExpired": "Il tuo abbonamento è scaduto", "storageLimitExceeded": "Limite d'archiviazione superato", "upgrade": "Acquista altro spazio", @@ -653,10 +688,12 @@ }, "backupFailed": "Backup fallito", "couldNotBackUpTryLater": "Impossibile eseguire il backup dei tuoi dati.\nRiproveremo più tardi.", + "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": "Ente può criptare e conservare i file solo se gliene concedi l'accesso", "pleaseGrantPermissions": "Concedi i permessi", "grantPermission": "Concedi il permesso", "privateSharing": "Condivisioni private", "shareOnlyWithThePeopleYouWant": "Condividi solo con le persone che vuoi", + "usePublicLinksForPeopleNotOnEnte": "Usa link pubblici per persone non registrate su Ente", "allowPeopleToAddPhotos": "Permetti alle persone di aggiungere foto", "shareAnAlbumNow": "Condividi un album", "collectEventPhotos": "Raccogli le foto di un evento", @@ -679,6 +716,21 @@ "deleteEmptyAlbumsWithQuestionMark": "Eliminare gli album vuoti?", "deleteAlbumsDialogBody": "Questo eliminerà tutti gli album vuoti. È utile quando si desidera ridurre l'ingombro nella lista degli album.", "deleteProgress": "Eliminazione di {currentlyDeleting} / {totalCount}", + "genericProgress": "Elaborazione {currentlyProcessing} / {totalCount}", + "@genericProgress": { + "description": "Generic progress text to display when processing multiple items", + "type": "text", + "placeholders": { + "currentlyProcessing": { + "example": "1", + "type": "int" + }, + "totalCount": { + "example": "10", + "type": "int" + } + } + }, "permanentlyDelete": "Elimina definitivamente", "canOnlyCreateLinkForFilesOwnedByYou": "Puoi creare solo link per i file di tua proprietà", "publicLinkCreated": "Link pubblico creato", @@ -693,11 +745,13 @@ "unhide": "Mostra", "unarchive": "Rimuovi dall'archivio", "favorite": "Preferito", + "removeFromFavorite": "Rimuovi dai preferiti", "shareLink": "Condividi link", "createCollage": "Crea un collage", "saveCollage": "Salva il collage", "collageSaved": "Collage salvato nella galleria", "collageLayout": "Disposizione", + "addToEnte": "Aggiungi a Ente", "addToAlbum": "Aggiungi all'album", "delete": "Cancella", "hide": "Nascondi", @@ -762,7 +816,10 @@ "photosAddedByYouWillBeRemovedFromTheAlbum": "Le foto aggiunte da te verranno rimosse dall'album", "youveNoFilesInThisAlbumThatCanBeDeleted": "Non hai file in questo album che possono essere eliminati", "youDontHaveAnyArchivedItems": "Non hai nulla di archiviato.", + "ignoredFolderUploadReason": "Alcuni file in questo album vengono ignorati dal caricamento perché erano stati precedentemente eliminati da Ente.", "resetIgnoredFiles": "Ripristina i file ignorati", + "deviceFilesAutoUploading": "I file aggiunti a questo album del dispositivo verranno automaticamente caricati su Ente.", + "turnOnBackupForAutoUpload": "Attiva il backup per caricare automaticamente i file aggiunti a questa cartella del dispositivo su Ente.", "noHiddenPhotosOrVideos": "Nessuna foto o video nascosti", "toHideAPhotoOrVideo": "Per nascondere una foto o un video", "openTheItem": "• Apri la foto o il video", @@ -788,6 +845,7 @@ "close": "Chiudi", "setAs": "Imposta come", "fileSavedToGallery": "File salvato nella galleria", + "filesSavedToGallery": "File salvati nella galleria", "fileFailedToSaveToGallery": "Impossibile salvare il file nella galleria", "download": "Scarica", "pressAndHoldToPlayVideo": "Tieni premuto per riprodurre il video", @@ -890,6 +948,7 @@ "renameFile": "Rinomina file", "enterFileName": "Inserisci un nome per il file", "filesDeleted": "File eliminati", + "selectedFilesAreNotOnEnte": "I file selezionati non sono su Ente", "thisActionCannotBeUndone": "Questa azione non può essere annullata", "emptyTrash": "Vuoi svuotare il cestino?", "permDeleteWarning": "Tutti gli elementi nel cestino verranno eliminati definitivamente\n\nQuesta azione non può essere annullata", @@ -898,6 +957,7 @@ "permanentlyDeleteFromDevice": "Eliminare definitivamente dal dispositivo?", "someOfTheFilesYouAreTryingToDeleteAre": "Alcuni dei file che si sta tentando di eliminare sono disponibili solo sul dispositivo e non possono essere recuperati se cancellati", "theyWillBeDeletedFromAllAlbums": "Verranno eliminati da tutti gli album.", + "someItemsAreInBothEnteAndYourDevice": "Alcuni elementi sono sia su Ente che sul tuo dispositivo.", "selectedItemsWillBeDeletedFromAllAlbumsAndMoved": "Gli elementi selezionati verranno eliminati da tutti gli album e spostati nel cestino.", "theseItemsWillBeDeletedFromYourDevice": "Questi file verranno eliminati dal tuo dispositivo.", "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Sembra che qualcosa sia andato storto. Riprova tra un po'. Se l'errore persiste, contatta il nostro team di supporto.", @@ -933,11 +993,17 @@ "loadMessage7": "Le nostre app per smartphone vengono eseguite in background per crittografare e eseguire il backup di qualsiasi nuova foto o video", "loadMessage8": "web.ente.io ha un uploader intuitivo", "loadMessage9": "Usiamo Xchacha20Poly1305 per crittografare in modo sicuro i tuoi dati", + "photoDescriptions": "Descrizioni delle foto", + "fileTypesAndNames": "Tipi e nomi di file", "location": "Luogo", + "moments": "Momenti", + "searchFaceEmptySection": "Le persone saranno mostrate qui una volta completata l'indicizzazione", "searchDatesEmptySection": "Ricerca per data, mese o anno", "searchLocationEmptySection": "Raggruppa foto scattate entro un certo raggio da una foto", "searchPeopleEmptySection": "Invita persone e vedrai qui tutte le foto condivise da loro", "searchAlbumsEmptySection": "Album", + "searchFileTypesAndNamesEmptySection": "Tipi e nomi di file", + "searchCaptionEmptySection": "Aggiungi descrizioni come \"#viaggio\" nelle informazioni delle foto per trovarle rapidamente qui", "language": "Lingua", "selectLanguage": "Seleziona una lingua", "locationName": "Nome della località", @@ -986,6 +1052,7 @@ "@storageUsageInfo": { "description": "Example: 1.2 GB of 2 GB used or 100 GB or 2TB used" }, + "availableStorageSpace": "{freeAmount} {storageUnit} liberi", "appVersion": "Versione: {versionValue}", "verifyIDLabel": "Verifica", "fileInfoAddDescHint": "Aggiungi descrizione...", @@ -996,6 +1063,7 @@ }, "setRadius": "Imposta raggio", "familyPlanPortalTitle": "Famiglia", + "familyPlanOverview": "Aggiungi 5 membri della famiglia al tuo piano esistente senza pagare extra.\n\nOgni membro ottiene il proprio spazio privato e non può vedere i file dell'altro a meno che non siano condivisi.\n\nI piani familiari sono disponibili per i clienti che hanno un abbonamento Ente a pagamento.\n\nIscriviti ora per iniziare!", "androidBiometricHint": "Verifica l'identità", "@androidBiometricHint": { "description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters." @@ -1073,21 +1141,43 @@ "noAlbumsSharedByYouYet": "Ancora nessun album condiviso da te", "sharedWithYou": "Condivise con te", "sharedByYou": "Condivise da te", + "inviteYourFriendsToEnte": "Invita i tuoi amici a Ente", "failedToDownloadVideo": "Download del video non riuscito", "hiding": "Nascondendo...", "unhiding": "Rimuovendo dal nascondiglio...", "successfullyHid": "Nascosta con successo", "successfullyUnhid": "Rimossa dal nascondiglio con successo", "crashReporting": "Segnalazione di crash", + "resumableUploads": "Caricamenti riattivabili", "addToHiddenAlbum": "Aggiungi ad album nascosto", "moveToHiddenAlbum": "Sposta in album nascosto", + "fileTypes": "Tipi di file", "hearUsWhereTitle": "Come hai sentito parlare di Ente? (opzionale)", "hearUsExplanation": "Non teniamo traccia del numero di installazioni dell'app. Sarebbe utile se ci dicesse dove ci ha trovato!", "viewAddOnButton": "Visualizza componenti aggiuntivi", "addOns": "Componenti aggiuntivi", "addOnPageSubtitle": "Dettagli dei componenti aggiuntivi", + "yourMap": "La tua mappa", + "modifyYourQueryOrTrySearchingFor": "Modifica la tua interrogazione o prova a cercare", + "blackFridaySale": "Offerta del Black Friday", + "photos": "Foto", + "videos": "Video", "searchHint3": "Album, nomi di file e tipi", "searchHint4": "Luogo", + "addYourPhotosNow": "Aggiungi le tue foto ora", + "searchResultCount": "{count, plural, one{{count} risultato trovato} other{{count} risultati trovati}}", + "@searchResultCount": { + "description": "Text to tell user how many results were found for their search query", + "placeholders": { + "count": { + "example": "1|2|3", + "type": "int" + } + } + }, + "faces": "Volti", + "people": "Persone", + "contents": "Contenuti", "addNew": "Aggiungi nuovo", "@addNew": { "description": "Text to add a new item (location tag, album, caption etc)" @@ -1103,5 +1193,28 @@ "selectALocation": "Seleziona un luogo", "selectALocationFirst": "Scegli prima una posizione", "changeLocationOfSelectedItems": "Cambiare la posizione degli elementi selezionati?", - "editsToLocationWillOnlyBeSeenWithinEnte": "Le modifiche alla posizione saranno visibili solo all'interno di Ente" + "editsToLocationWillOnlyBeSeenWithinEnte": "Le modifiche alla posizione saranno visibili solo all'interno di Ente", + "waitingForVerification": "In attesa di verifica...", + "passkey": "Passkey", + "passkeyAuthTitle": "Verifica della passkey", + "passKeyPendingVerification": "La verifica è ancora in corso", + "loginSessionExpired": "Sessione scaduta", + "loginSessionExpiredDetails": "La sessione è scaduta. Si prega di accedere nuovamente.", + "verifyPasskey": "Verifica passkey", + "playOnTv": "Riproduci album sulla TV", + "pair": "Abbina", + "deviceNotFound": "Dispositivo non trovato", + "castInstruction": "Visita cast.ente.io sul dispositivo che vuoi abbinare.\n\nInserisci il codice qui sotto per riprodurre l'album sulla tua TV.", + "deviceCodeHint": "Inserisci il codice", + "joinDiscord": "Unisciti a Discord", + "locations": "Luoghi", + "descriptions": "Descrizioni", + "addAName": "Aggiungi un nome", + "findPeopleByName": "Trova rapidamente le persone per nome", + "addViewers": "{count, plural, zero {Aggiungi visualizzatore} one {Aggiungi visualizzatore} other {Aggiungi visualizzatori}}", + "addCollaborators": "{count, plural, zero {Aggiungi collaboratore} one {Aggiungi collaboratore} other {Aggiungi collaboratori}}", + "developerSettings": "Impostazioni sviluppatore", + "serverEndpoint": "Endpoint del server", + "invalidEndpoint": "Endpoint invalido", + "invalidEndpointMessage": "Spiacenti, l'endpoint inserito non è valido. Inserisci un endpoint valido e riprova." } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_nl.arb b/mobile/lib/l10n/intl_nl.arb index 62dc45e844..92a66a3401 100644 --- a/mobile/lib/l10n/intl_nl.arb +++ b/mobile/lib/l10n/intl_nl.arb @@ -12,7 +12,7 @@ "deleteAccountFeedbackPrompt": "We vinden het jammer je te zien gaan. Deel je feedback om ons te helpen verbeteren.", "feedback": "Feedback", "kindlyHelpUsWithThisInformation": "Help ons alsjeblieft met deze informatie", - "confirmDeletePrompt": "Ja, ik wil permanent mijn account inclusief alle gegevens verwijderen.", + "confirmDeletePrompt": "Ja, ik wil mijn account en de bijbehorende gegevens verspreid over alle apps permanent verwijderen.", "confirmAccountDeletion": "Account verwijderen bevestigen", "deleteAccountPermanentlyButton": "Account permanent verwijderen", "yourAccountHasBeenDeleted": "Je account is verwijderd", @@ -453,6 +453,8 @@ "showMemories": "Toon herinneringen", "yearsAgo": "{count, plural, one{{count} jaar geleden} other{{count} jaar geleden}}", "backupSettings": "Back-up instellingen", + "backupStatus": "Back-upstatus", + "backupStatusDescription": "Items die zijn geback-upt, worden hier getoond", "backupOverMobileData": "Back-up maken via mobiele data", "backupVideos": "Back-up video's", "disableAutoLock": "Automatisch vergrendelen uitschakelen", @@ -496,6 +498,7 @@ "removeDuplicates": "Duplicaten verwijderen", "removeDuplicatesDesc": "Controleer en verwijder bestanden die exacte kopieën zijn.", "viewLargeFiles": "Grote bestanden", + "viewLargeFilesDesc": "Bekijk bestanden die de meeste opslagruimte verbruiken.", "noDuplicates": "✨ Geen duplicaten", "youveNoDuplicateFilesThatCanBeCleared": "Je hebt geen dubbele bestanden die kunnen worden gewist", "success": "Succes", @@ -1313,5 +1316,6 @@ "cl_video_player_title": "Videospeler", "cl_video_player_description": "Een verfrissende nieuwe videospeler, met betere afspeelknoppen en ondersteuning voor HDR-video's.", "appLockDescriptions": "Kies tussen het standaard vergrendelscherm van uw apparaat en een aangepast vergrendelscherm met een pincode of wachtwoord.", - "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Om appvergrendeling in te schakelen, moet u een toegangscode of schermvergrendeling instellen in uw systeeminstellingen." + "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Om appvergrendeling in te schakelen, moet u een toegangscode of schermvergrendeling instellen in uw systeeminstellingen.", + "authToViewPasskey": "Verifieer uzelf om uw toegangssleutel te bekijken" } \ No newline at end of file diff --git a/mobile/lib/l10n/intl_no.arb b/mobile/lib/l10n/intl_no.arb index 9bf690cd30..1319dca79c 100644 --- a/mobile/lib/l10n/intl_no.arb +++ b/mobile/lib/l10n/intl_no.arb @@ -12,7 +12,6 @@ "deleteAccountFeedbackPrompt": "Vi er lei oss for at du forlater oss. Gi oss gjerne en tilbakemelding så vi kan forbedre oss.", "feedback": "Tilbakemelding", "kindlyHelpUsWithThisInformation": "Vær vennlig og hjelp oss med denne informasjonen", - "confirmDeletePrompt": "Ja, jeg ønsker å slette denne kontoen og all dataen dens permanent.", "confirmAccountDeletion": "Bekreft sletting av konto", "deleteAccountPermanentlyButton": "Slett bruker for altid", "yourAccountHasBeenDeleted": "Brukeren din har blitt slettet", diff --git a/mobile/lib/l10n/intl_pl.arb b/mobile/lib/l10n/intl_pl.arb index 7be752f684..bbbaddce95 100644 --- a/mobile/lib/l10n/intl_pl.arb +++ b/mobile/lib/l10n/intl_pl.arb @@ -12,7 +12,7 @@ "deleteAccountFeedbackPrompt": "Przykro nam, że odchodzisz. Wyjaśnij nam, dlaczego nas opuszczasz, aby pomóc ulepszać nasze usługi.", "feedback": "Opinia", "kindlyHelpUsWithThisInformation": "Pomóż nam z tą informacją", - "confirmDeletePrompt": "Tak, chcę trwale usunąć konto i wszystkie dane z nim powiązane.", + "confirmDeletePrompt": "Tak, chcę trwale usunąć to konto i jego dane ze wszystkich aplikacji.", "confirmAccountDeletion": "Potwierdź usunięcie konta", "deleteAccountPermanentlyButton": "Usuń konto na stałe", "yourAccountHasBeenDeleted": "Twoje konto zostało usunięte", @@ -453,6 +453,8 @@ "showMemories": "Pokaż wspomnienia", "yearsAgo": "{count, plural, one{{count} rok temu} few {{count} lata temu} many {{count} lat temu} other{{count} lata temu}}", "backupSettings": "Ustawienia kopii zapasowej", + "backupStatus": "Status kopii zapasowej", + "backupStatusDescription": "Elementy, których kopia zapasowa została utworzona, zostaną wyświetlone w tym miejscu", "backupOverMobileData": "Kopia zapasowa przez dane mobilne", "backupVideos": "Utwórz kopię zapasową wideo", "disableAutoLock": "Wyłącz automatyczną blokadę", diff --git a/mobile/lib/l10n/intl_pt.arb b/mobile/lib/l10n/intl_pt.arb index 0ca1ce69cd..630f8f63fa 100644 --- a/mobile/lib/l10n/intl_pt.arb +++ b/mobile/lib/l10n/intl_pt.arb @@ -12,7 +12,7 @@ "deleteAccountFeedbackPrompt": "Lamentamos ver você partir. Por favor, compartilhe seus comentários para nos ajudar a melhorar.", "feedback": "Comentários", "kindlyHelpUsWithThisInformation": "Ajude-nos com esta informação", - "confirmDeletePrompt": "Sim, desejo excluir permanentemente esta conta e todos os seus dados.", + "confirmDeletePrompt": "Sim, eu quero excluir permanentemente esta conta e seus dados em todos os aplicativos.", "confirmAccountDeletion": "Confirmar exclusão da conta", "deleteAccountPermanentlyButton": "Excluir conta permanentemente", "yourAccountHasBeenDeleted": "Sua conta foi excluída", @@ -453,6 +453,8 @@ "showMemories": "Mostrar memórias", "yearsAgo": "{count, plural, one{{count} anos atrás} other{{count} anos atrás}}", "backupSettings": "Configurações de backup", + "backupStatus": "Status do Backup", + "backupStatusDescription": "Os itens que foram salvos no backup aparecerão aqui", "backupOverMobileData": "Backup usando dados móveis", "backupVideos": "Backup de vídeos", "disableAutoLock": "Desativar bloqueio automático", diff --git a/mobile/lib/l10n/intl_ru.arb b/mobile/lib/l10n/intl_ru.arb index 2bf2d4efc1..d646ec6803 100644 --- a/mobile/lib/l10n/intl_ru.arb +++ b/mobile/lib/l10n/intl_ru.arb @@ -12,7 +12,7 @@ "deleteAccountFeedbackPrompt": "Мы сожалеем, что вы уходите. Пожалуйста, объясните, почему вы уходите, чтобы помочь нам развиваться.", "feedback": "Отзыв", "kindlyHelpUsWithThisInformation": "Пожалуйста, помогите нам с этой информацией", - "confirmDeletePrompt": "Да, я хочу навсегда удалить эту учётную запись и все её данные.", + "confirmDeletePrompt": "Да, я хочу навсегда удалить эту учётную запись и все её данные во всех приложениях Ente.", "confirmAccountDeletion": "Подтвердить удаление учётной записи", "deleteAccountPermanentlyButton": "Удалить аккаунт навсегда", "yourAccountHasBeenDeleted": "Ваша учетная запись была удалена", @@ -128,7 +128,7 @@ } } }, - "twofactorSetup": "Установка двуфакторной аутентификации", + "twofactorSetup": "Вход с 2FA", "enterCode": "Введите код", "scanCode": "Сканировать код", "codeCopiedToClipboard": "Код скопирован в буфер обмена", @@ -275,6 +275,7 @@ "codeAppliedPageTitle": "Код применён", "changeYourReferralCode": "Изменить ваш реферальный код", "change": "Изменить", + "unavailableReferralCode": "Извините, такого кода не существует.", "storageInGB": "{storageAmountInGB} Гигабайт", "claimed": "Получено", "@claimed": { @@ -306,8 +307,8 @@ } } }, - "faq": "ЧаВо", - "help": "помощь", + "faq": "Ответы на ваши вопросы", + "help": "Помощь", "oopsSomethingWentWrong": "Ой! Что-то пошло не так", "peopleUsingYourCode": "Люди использующие ваш код", "eligible": "подходящий", @@ -411,7 +412,13 @@ "photoGridSize": "Размер сетки фотографий", "manageDeviceStorage": "Управление хранилищем устройства", "machineLearning": "Machine learning", + "mlConsent": "Включить машинное обучение", + "mlConsentTitle": "Включить машинное обучение?", + "mlConsentDescription": "Если вы включите машинное обучение, Ente будет извлекать информацию из файлов (например, геометрию лица), включая те, которыми с вами поделились.\n\nЭто будет происходить на вашем устройстве, и любая сгенерированная биометрическая информация будет зашифрована с использованием сквозного (End-to-End) шифрования между вашим устройством и сервером.", + "mlConsentPrivacy": "Пожалуйста, нажмите здесь, чтобы узнать больше об этой функции в нашей политике конфиденциальности", + "mlConsentConfirmation": "Я понимаю и хочу включить машинное обучение", "magicSearch": "Волшебный поиск", + "mlIndexingDescription": "Обратите внимание, что машинное обучение приведёт к повышенному потреблению трафика и батареи, пока все элементы не будут проиндексированы. Рекомендуем использовать ПК версию для более быстрого индексирования. Полученные результаты будут синхронизированы автоматически между устройствами.", "loadingModel": "Загрузка моделей...", "waitingForWifi": "Ожидание WiFi...", "status": "Статус", @@ -443,7 +450,7 @@ }, "showMemories": "Показать воспоминания", "yearsAgo": "{count, plural, one{{count} год назад} other{{count} лет назад}}", - "backupSettings": "Резервная копия настроек", + "backupSettings": "Настройки резервного копирования", "backupOverMobileData": "Резервное копирование через мобильную сеть", "backupVideos": "Резервное копирование видео", "disableAutoLock": "Отключить автоблокировку", @@ -461,8 +468,8 @@ "authToChangeYourEmail": "Пожалуйста, авторизуйтесь, чтобы изменить адрес электронной почты", "changePassword": "Изменить пароль", "authToChangeYourPassword": "Пожалуйста, авторизуйтесь, чтобы изменить пароль", - "emailVerificationToggle": "Подтверждение электронной почты", - "authToChangeEmailVerificationSetting": "Авторизуйтесь, чтобы изменить подтверждение электронной почты", + "emailVerificationToggle": "Вход с кодом на почту", + "authToChangeEmailVerificationSetting": "Пожалуйста, войдите, чтобы изменить настройку подтверждения электронной почты", "exportYourData": "Экспорт данных", "logout": "Выйти", "authToInitiateAccountDeletion": "Пожалуйста, авторизуйтесь, чтобы начать удаление аккаунта", @@ -1143,6 +1150,7 @@ "successfullyHid": "Успешно скрыто", "successfullyUnhid": "Успешно показано", "crashReporting": "Отчеты об ошибках", + "resumableUploads": "Поддержка дозагрузки файл(а/ов) при разрыве связи", "addToHiddenAlbum": "Добавить в скрытый альбом", "moveToHiddenAlbum": "Переместить в скрытый альбом", "fileTypes": "Типы файлов", @@ -1266,6 +1274,8 @@ "enable": "Включить", "enabled": "Включено", "moreDetails": "Подробнее", + "enableMLIndexingDesc": "Ente поддерживает машинное обучение на устройстве для распознавания лиц, умного поиска и других расширенных функций поиска", + "magicSearchHint": "Умный поиск позволяет искать фотографии по их содержимому, например, 'цветок', 'красная машина', 'паспорт', 'документы'", "panorama": "Панорама", "reenterPassword": "Подтвердите пароль", "reenterPin": "Введите PIN-код ещё раз", diff --git a/mobile/lib/l10n/intl_sv.arb b/mobile/lib/l10n/intl_sv.arb index 3c51f175e0..bfb0e0291a 100644 --- a/mobile/lib/l10n/intl_sv.arb +++ b/mobile/lib/l10n/intl_sv.arb @@ -12,7 +12,6 @@ "deleteAccountFeedbackPrompt": "Vi är ledsna att se dig lämna oss. Vänligen dela dina synpunkter för att hjälpa oss att förbättra.", "feedback": "Feedback", "kindlyHelpUsWithThisInformation": "Vänligen hjälp oss med denna information", - "confirmDeletePrompt": "Ja, jag vill ta bort detta konto och all data permanent.", "confirmAccountDeletion": "Bekräfta radering av konto", "deleteAccountPermanentlyButton": "Radera kontot permanent", "yourAccountHasBeenDeleted": "Ditt konto har raderats", @@ -281,6 +280,7 @@ "description": "Used to indicate storage claimed, like 10GB Claimed" }, "inviteYourFriends": "Bjud in dina vänner", + "help": "Hjälp", "subscribe": "Prenumerera", "trash": "Papperskorg", "photoSmallCase": "foto", diff --git a/mobile/lib/l10n/intl_ta.arb b/mobile/lib/l10n/intl_ta.arb new file mode 100644 index 0000000000..d3d26e203c --- /dev/null +++ b/mobile/lib/l10n/intl_ta.arb @@ -0,0 +1,19 @@ +{ + "@@locale ": "en", + "enterYourEmailAddress": "உங்கள் மின்னஞ்சல் முகவரியை உள்ளிடவும்", + "accountWelcomeBack": "மீண்டும் வருக!", + "email": "மின்னஞ்சல்", + "cancel": "ரத்து செய்", + "verify": "சரிபார்க்கவும்", + "invalidEmailAddress": "தவறான மின்னஞ்சல் முகவரி", + "enterValidEmail": "சரியான மின்னஞ்சல் முகவரியை உள்ளிடவும்.", + "deleteAccount": "கணக்கை நீக்கு", + "askDeleteReason": "உங்கள் கணக்கை நீக்குவதற்கான முக்கிய காரணம் என்ன?", + "deleteAccountFeedbackPrompt": "நீங்கள் வெளியேறுவதை கண்டு வருந்துகிறோம். எங்களை மேம்படுத்த உதவ உங்கள் கருத்தைப் பகிரவும்.", + "feedback": "பின்னூட்டம்", + "kindlyHelpUsWithThisInformation": "இந்த தகவலுடன் தயவுசெய்து எங்களுக்கு உதவுங்கள்", + "confirmDeletePrompt": "ஆம், எல்லா செயலிகளிலும் இந்தக் கணக்கையும் அதன் தரவையும் நிரந்தரமாக நீக்க விரும்புகிறேன்.", + "confirmAccountDeletion": "கணக்கு நீக்குதலை உறுதிப்படுத்தவும்", + "deleteAccountPermanentlyButton": "கணக்கை நிரந்தரமாக நீக்கவும்", + "deleteReason1": "எனக்கு தேவையான ஒரு முக்கிய அம்சம் இதில் இல்லை" +} \ No newline at end of file diff --git a/mobile/lib/l10n/intl_th.arb b/mobile/lib/l10n/intl_th.arb index 9d6b4c0801..3cce924a17 100644 --- a/mobile/lib/l10n/intl_th.arb +++ b/mobile/lib/l10n/intl_th.arb @@ -12,7 +12,6 @@ "deleteAccountFeedbackPrompt": "เราเสียใจที่เห็นคุณไป โปรดแบ่งปันความคิดเห็นของคุณเพื่อช่วยให้เราปรับปรุง", "feedback": "ความคิดเห็น", "kindlyHelpUsWithThisInformation": "กรุณาช่วยเราด้วยข้อมูลนี้", - "confirmDeletePrompt": "ใช่ ฉันต้องการลบบัญชีนี้และข้อมูลที่เกี่ยวข้องทั้งหมดแบบถาวร", "confirmAccountDeletion": "ยืนยันการลบบัญชี", "deleteAccountPermanentlyButton": "ลบบัญชีถาวร", "yourAccountHasBeenDeleted": "บัญชีของคุณถูกลบแล้ว", diff --git a/mobile/lib/l10n/intl_tr.arb b/mobile/lib/l10n/intl_tr.arb index a51913a120..1e20822143 100644 --- a/mobile/lib/l10n/intl_tr.arb +++ b/mobile/lib/l10n/intl_tr.arb @@ -12,7 +12,6 @@ "deleteAccountFeedbackPrompt": "Aramızdan ayrıldığınız için üzgünüz. Lütfen kendimizi geliştirmemize yardımcı olun. Neden ayrıldığınızı Açıklar mısınız.", "feedback": "Geri Bildirim", "kindlyHelpUsWithThisInformation": "Lütfen bu bilgilerle bize yardımcı olun", - "confirmDeletePrompt": "Evet, bu hesabı ve tüm verileri kalıcı olarak silmek istiyorum.", "confirmAccountDeletion": "Hesap silme işlemini onayla", "deleteAccountPermanentlyButton": "Hesabımı kalıcı olarak sil", "yourAccountHasBeenDeleted": "Hesabınız silindi", diff --git a/mobile/lib/l10n/intl_zh.arb b/mobile/lib/l10n/intl_zh.arb index abb3a223ae..20912fdc44 100644 --- a/mobile/lib/l10n/intl_zh.arb +++ b/mobile/lib/l10n/intl_zh.arb @@ -12,7 +12,7 @@ "deleteAccountFeedbackPrompt": "我们很抱歉看到您离开。请分享您的反馈以帮助我们改进。", "feedback": "反馈", "kindlyHelpUsWithThisInformation": "请帮助我们了解这个信息", - "confirmDeletePrompt": "是的,我想永久删除此账户及其相关数据.", + "confirmDeletePrompt": "是的,我想永久删除此账户及其所有关联的应用程序的数据。", "confirmAccountDeletion": "确认删除账户", "deleteAccountPermanentlyButton": "永久删除账户", "yourAccountHasBeenDeleted": "您的账户已删除", @@ -453,6 +453,8 @@ "showMemories": "显示回忆", "yearsAgo": "{count, plural, one{{count} 年前} other{{count} 年前}}", "backupSettings": "备份设置", + "backupStatus": "备份状态", + "backupStatusDescription": "已备份的项目将显示在此处", "backupOverMobileData": "通过移动数据备份", "backupVideos": "备份视频", "disableAutoLock": "禁用自动锁定", From 743fc4aa41125842cdac9291bfb60165757e12ed Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Mon, 2 Sep 2024 01:17:03 +0000 Subject: [PATCH 178/275] New Crowdin translations by GitHub Action --- auth/lib/l10n/arb/app_bg.arb | 128 ++++++++++++++++++++++++++++++++++- auth/lib/l10n/arb/app_de.arb | 29 +++++++- auth/lib/l10n/arb/app_el.arb | 5 ++ auth/lib/l10n/arb/app_fr.arb | 13 ++-- auth/lib/l10n/arb/app_sv.arb | 22 +++++- auth/lib/l10n/arb/app_ta.arb | 1 + auth/lib/l10n/arb/app_vi.arb | 42 ++++++++++-- auth/lib/l10n/arb/app_zh.arb | 56 +++++++-------- 8 files changed, 256 insertions(+), 40 deletions(-) create mode 100644 auth/lib/l10n/arb/app_ta.arb diff --git a/auth/lib/l10n/arb/app_bg.arb b/auth/lib/l10n/arb/app_bg.arb index 12730e7933..85b0440407 100644 --- a/auth/lib/l10n/arb/app_bg.arb +++ b/auth/lib/l10n/arb/app_bg.arb @@ -67,7 +67,7 @@ "pleaseWait": "Моля изчакайте...", "generatingEncryptionKeysTitle": "Генерират се ключове за шифроване...", "recreatePassword": "Създайте отново парола", - "recreatePasswordMessage": "Текущото устройство не е достатъчно мощно, за да потвърди паролата Ви, така че трябва да го генерираме отново веднъж по начин, който работи с всички устройства. \n\nВлезте с Вашия ключ за възстановяване и генерирайте отново паролата си (можете да използвате същата отново, ако желаете).", + "recreatePasswordMessage": "Текущото устройство не е достатъчно мощно, за да потвърди паролата Ви, така че трябва да го генерираме отново веднъж по начин, който работи с всички устройства. \n\nМоля, влезте с Вашия ключ за възстановяване и генерирайте отново паролата си (можете да използвате същата отново, ако желаете).", "useRecoveryKey": "Използвайте ключ за възстановяване", "incorrectPasswordTitle": "Грешна парола", "welcomeBack": "Добре дошли отново!", @@ -130,7 +130,61 @@ "faq_q_3": "Как мога да изтрия кодове?", "faq_a_3": "Можете да изтриете код, като плъзнете наляво върху него.", "faq_q_4": "Как мога да подкрепя този проект?", + "faq_a_4": "Можете да подкрепите развитието на този проект, като се абонирате за нашето приложение за снимки @ ente.io.", + "faq_q_5": "Как мога да активирам заключване чрез FaceID в Auth", + "faq_a_5": "Можете да активирате заключване чрез FaceID в Настройки → Сигурност → Заключен екран.", + "somethingWentWrongMessage": "Нещо се обърка, моля опитайте отново", + "leaveFamily": "Напуснете семейството", + "leaveFamilyMessage": "Сигурни ли сте, че искате да напуснете семейния план?", + "inFamilyPlanMessage": "Вие сте на семеен план!", + "swipeHint": "Плъзнете наляво, за да редактирате или премахнете кодове", "scan": "Сканиране", + "scanACode": "Скениране на код", + "verify": "Потвърждаване", + "verifyEmail": "Потвърдете имейла", + "enterCodeHint": "Въведете 6-цифрения код от\nВашето приложение за удостоверяване", + "lostDeviceTitle": "Загубено устройство?", + "twoFactorAuthTitle": "Двуфакторно удостоверяване", + "passkeyAuthTitle": "Удостоверяване с ключ за парола", + "verifyPasskey": "Потвърдете ключ за парола", + "recoverAccount": "Възстановяване на акаунт", + "enterRecoveryKeyHint": "Въведете Вашия ключ за възстановяване", + "recover": "Възстановяване", + "contactSupportViaEmailMessage": "Моля, изпратете имейл до {email} от Вашия регистриран имейл адрес", + "@contactSupportViaEmailMessage": { + "placeholders": { + "email": { + "type": "String" + } + } + }, + "invalidQRCode": "Невалиден QR код", + "noRecoveryKeyTitle": "Няма ключ за възстановяване?", + "enterEmailHint": "Въведете Вашият имейл адрес", + "invalidEmailTitle": "Невалиден имейл адрес", + "invalidEmailMessage": "Моля, въведете валиден имейл адрес.", + "deleteAccount": "Изтриване на акаунта", + "deleteAccountQuery": "Ще съжаляваме да си тръгнете. Изправени ли сте пред някакъв проблем?", + "yesSendFeedbackAction": "Да, изпращане на обратна връзка", + "noDeleteAccountAction": "Не, изтриване на акаунта", + "initiateAccountDeleteTitle": "Моля, удостоверете се, за да инициирате изтриването на акаунта", + "sendEmail": "Изпратете имейл", + "createNewAccount": "Създаване на нов акаунт", + "weakStrength": "Слаба", + "strongStrength": "Силна", + "moderateStrength": "Умерена", + "confirmPassword": "Потвърждаване на паролата", + "close": "Затваряне", + "oopsSomethingWentWrong": "Ами сега, нещо се обърка.", + "selectLanguage": "Изберете език", + "language": "Език", + "social": "Социални мрежи", + "security": "Сигурност", + "lockscreen": "Заключен екран", + "authToChangeLockscreenSetting": "Моля, удостоверете се, за да промените настройката за заключен екран", + "deviceLockEnablePreSteps": "За да активирате заключването на устройството, моля, задайте парола за устройството или заключване на екрана в системните настройки.", + "viewActiveSessions": "Вижте активните сесии", + "authToViewYourActiveSessions": "Моля, удостоверете се, за да видите Вашите активни сесии", "searchHint": "Търсене...", "search": "Търсене", "sorryUnableToGenCode": "За съжаление не може да се генерира код за {issuerName}", @@ -183,46 +237,118 @@ "insecureDevice": "Несигурно устройство", "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": "За съжаление не можахме да генерираме защитени ключове на това устройство.\n\nМоля, регистрирайте се от друго устройство.", "howItWorks": "Как работи", + "ackPasswordLostWarning": "Разбирам, че ако загубя паролата си, може да загубя данните си, тъй като данните ми са шифровани от край до край.", + "loginTerms": "С натискането на вход, се съгласявам с условията за ползване и политиката за поверителност", + "logInLabel": "Вход", "logout": "Изход", "areYouSureYouWantToLogout": "Наистина ли искате да излезете от профила си?", "yesLogout": "Да, излез", "exit": "Изход", + "verifyingRecoveryKey": "Проверка на ключа за възстановяване...", + "recoveryKeyVerified": "Ключът за възстановяване е проверен", + "recoveryKeySuccessBody": "Страхотно! Вашият ключ за възстановяване е валиден. Благодарим Ви за проверката.\n\nМоля, не забравяйте да запазите безопасно архивирания си ключ за възстановяване.", + "invalidRecoveryKey": "Въведеният от Вас ключ за възстановяване не е валиден. Моля, уверете се, че съдържа 24 думи и проверете правописа на всяка.\n\nАко сте въвели по-стар код за възстановяване, уверете се, че е дълъг 64 знака и проверете всеки от тях.", + "recreatePasswordTitle": "Създайте отново парола", + "recreatePasswordBody": "Текущото устройство не е достатъчно мощно, за да потвърди паролата Ви, но можем да я регенерираме по начин, който работи с всички устройства.\n\nМоля, влезте с Вашия ключ за възстановяване и генерирайте отново паролата си (можете да използвате същата отново, ако желаете).", "invalidKey": "Невалиден ключ", "tryAgain": "Опитайте отново", + "viewRecoveryKey": "Вижте ключа за възстановяване", + "confirmRecoveryKey": "Потвърдете ключа за възстановяване", + "recoveryKeyVerifyReason": "Вашият ключ за възстановяване е единственият начин да възстановите Вашите снимки, ако забравите паролата си. Можете да намерите своя ключ за възстановяване в Настройки > Акаунт.\n\nМоля, въведете Вашия ключ за възстановяване тук, за да проверите дали сте го запазили правилно.", + "confirmYourRecoveryKey": "Потвърдете Вашия ключ за възстановяване", "confirm": "Потвърждаване", + "emailYourLogs": "Изпратете Вашата история на действията на имейл", + "pleaseSendTheLogsTo": "Моля, изпратете историята на действията на \n{toEmail}", + "copyEmailAddress": "Копиране на имейл адрес", + "exportLogs": "Експорт на файловете с историята", + "enterYourRecoveryKey": "Въведете Вашия ключ за възстановяване", + "tempErrorContactSupportIfPersists": "Изглежда нещо се обърка. Моля, опитайте отново след известно време. Ако грешката продължава, моля, свържете се с нашия екип за поддръжка.", + "networkHostLookUpErr": "Не може да се свърже с Ente, моля, проверете мрежовите си настройки и се свържете с поддръжката, ако проблемът продължава.", + "networkConnectionRefusedErr": "Не може да се свърже с Ente, моля, опитайте отново след известно време. Ако проблемът продължава, моля, свържете се с поддръжката.", + "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Изглежда нещо се обърка. Моля, опитайте отново след известно време. Ако грешката продължава, моля, свържете се с нашия екип за поддръжка.", "about": "Относно", + "weAreOpenSource": "Ние сме с отворен код!", "privacy": "Поверителност", "terms": "Условия", "checkForUpdates": "Провери за актуализации", "checkStatus": "Проверка на състоянието", "downloadUpdate": "Изтегляне", + "criticalUpdateAvailable": "Налична е критична актуализация", "updateAvailable": "Налична актуализация", "update": "Актуализиране", "checking": "Извършва се проверка...", + "youAreOnTheLatestVersion": "Вие сте с най-новата версия", "warning": "Предупреждение", + "exportWarningDesc": "Експортираният файл съдържа поверителна информация. Моля, съхранявайте го безопасно.", "iUnderStand": "Разбрах", "@iUnderStand": { "description": "Text for the button to confirm the user understands the warning" }, + "authToExportCodes": "Моля, удостоверете се, за да експортирате Вашите кодове", "importSuccessTitle": "Ура!", + "importSuccessDesc": "Импортирахте {count} кода!", + "@importSuccessDesc": { + "placeholders": { + "count": { + "description": "The number of codes imported", + "type": "int", + "example": "1" + } + } + }, "sorry": "Съжаляваме", + "importFailureDesc": "Неуспешен анализ на избрания файл.\nМоля, пишете на support@ente.io, ако имате нужда от помощ!", "pendingSyncs": "Предупреждение", + "pendingSyncsWarningBody": "Някои от вашите кодове не са архивирани.\n\nМоля, уверете се, че имате резервно копие на тези кодове, преди да излезете.", + "checkInboxAndSpamFolder": "Моля, проверете входящата си поща (и спама), за да завършите проверката", + "tapToEnterCode": "Докоснете, за да въведете код", "resendEmail": "Повторно изпращане на имейл", + "weHaveSendEmailTo": "Изпратихме имейл до {email}", + "@weHaveSendEmailTo": { + "description": "Text to indicate that we have sent a mail to the user", + "placeholders": { + "email": { + "description": "The email address of the user", + "type": "String", + "example": "example@ente.io" + } + } + }, "activeSessions": "Активни сесии", "somethingWentWrongPleaseTryAgain": "Нещо се обърка, моля опитайте отново", + "thisWillLogYouOutOfThisDevice": "Това ще Ви изкара от профила на това устройство!", + "thisWillLogYouOutOfTheFollowingDevice": "Това ще Ви изкара от профила на следното устройство:", + "terminateSession": "Прекратяване на сесията?", "terminate": "Прекратяване", "thisDevice": "Това устройство", + "toResetVerifyEmail": "За да нулирате паролата си, моля, първо потвърдете своя имейл.", "thisEmailIsAlreadyInUse": "Този имейл вече се използва", + "verificationFailedPleaseTryAgain": "Неуспешно проверка, моля опитайте отново", + "yourVerificationCodeHasExpired": "Вашият код за потвърждение е изтекъл", "incorrectCode": "Неправилен код", + "sorryTheCodeYouveEnteredIsIncorrect": "За съжаление кодът, който сте въвели, е неправилен", + "emailChangedTo": "Имейлът е променен на {newEmail}", "authenticationFailedPleaseTryAgain": "Неуспешно удостоверяване, моля опитайте отново", "authenticationSuccessful": "Успешно удостоверяване!", "twofactorAuthenticationSuccessfullyReset": "Двуфакторното удостоверяване бе успешно нулирано", + "incorrectRecoveryKey": "Неправилен ключ за възстановяване", + "theRecoveryKeyYouEnteredIsIncorrect": "Въведеният от Вас ключ за възстановяване е неправилен", "enterPassword": "Въведете парола", "selectExportFormat": "Изберете формат за експортиране", + "exportDialogDesc": "Шифрованите експорти ще бъдат защитени с парола по Ваш избор.", "encrypted": "Шифровано", "plainText": "Обикновен текст", "passwordToEncryptExport": "Парола за шифроване на експортирането", "export": "Експортиране", + "useOffline": "Използвайте без резервни копия", + "signInToBackup": "Влезте, за да архивирате Вашите кодове", + "singIn": "Вход", + "sigInBackupReminder": "Моля, експортирайте Вашите кодове, за да сте сигурни, че имате резервно копие, от което можете да ги възстановите.", + "offlineModeWarning": "Избрахте да продължите без резервни копия. Моля, направете ръчни резервни копия, за да сте сигурни, че Вашите кодове са в безопасност.", + "showLargeIcons": "Показване на големи икони", + "shouldHideCode": "Скриване на кодове", + "doubleTapToViewHiddenCode": "Можете да докоснете два пъти върху запис, за да видите кода", + "focusOnSearchBar": "Фокусиране на търсенето при стартиране на приложението", "confirmUpdatingkey": "Сигурни ли сте, че искате да актуализирате секретния ключ?", "minimizeAppOnCopy": "Минимизиране на приложението при копиране", "editCodeAuthMessage": "Удостоверете се, за да редактирате кода", diff --git a/auth/lib/l10n/arb/app_de.arb b/auth/lib/l10n/arb/app_de.arb index 4d67965b2c..217fe8f2ae 100644 --- a/auth/lib/l10n/arb/app_de.arb +++ b/auth/lib/l10n/arb/app_de.arb @@ -72,7 +72,7 @@ "incorrectPasswordTitle": "Falsches Passwort", "welcomeBack": "Willkommen zurück!", "madeWithLoveAtPrefix": "gemacht mit ❤️ bei ", - "supportDevs": "Bei ente registrieren um das Projekt zu unterstützen.", + "supportDevs": "Bei ente registrieren, um das Projekt zu unterstützen", "supportDiscount": "Benutze den Rabattcode \"AUTH\" für 10% Rabatt im ersten Jahr", "changeEmail": "E-Mail ändern", "changePassword": "Passwort ändern", @@ -182,6 +182,7 @@ "security": "Sicherheit", "lockscreen": "Sperrbildschirm", "authToChangeLockscreenSetting": "Bitte authentifizieren um die Einstellungen des Sperrbildschirms zu ändern", + "deviceLockEnablePreSteps": "Um die Gerätesperre zu aktivieren, richte bitte einen Gerätepasscode oder eine Bildschirmsperre in den Systemeinstellungen ein.", "viewActiveSessions": "Aktive Sitzungen anzeigen", "authToViewYourActiveSessions": "Bitte authentifizieren um, die aktiven Sitzungen zu sehen", "searchHint": "Suchen...", @@ -441,5 +442,29 @@ "deleteTagTitle": "Tag löschen?", "deleteTagMessage": "Sind Sie sicher, dass Sie diesen Code löschen wollen? Diese Aktion ist unumkehrbar.", "somethingWentWrongParsingCode": "Wir konnten {x} Codes nicht parsen.", - "updateNotAvailable": "Update ist nicht verfügbar" + "updateNotAvailable": "Update ist nicht verfügbar", + "viewRawCodes": "Rohcodes anzeigen", + "rawCodes": "Rohcodes", + "rawCodeData": "Rohcode Daten", + "appLock": "App-Sperre", + "noSystemLockFound": "Keine Systemsperre gefunden", + "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Um die App-Sperre zu aktivieren, konfiguriere bitte den Gerätepasscode oder die Bildschirmsperre in den Systemeinstellungen.", + "autoLock": "Automatisches Sperren", + "immediately": "Sofort", + "reEnterPassword": "Passwort erneut eingeben", + "reEnterPin": "PIN erneut eingeben", + "next": "Weiter", + "tooManyIncorrectAttempts": "Zu viele fehlerhafte Versuche", + "tapToUnlock": "Zum Entsperren antippen", + "setNewPassword": "Neues Passwort festlegen", + "deviceLock": "Gerätesperre", + "hideContent": "Inhalte verstecken", + "hideContentDescriptionAndroid": "Versteckt Inhalte der App beim Wechseln zwischen Apps und deaktiviert Screenshots", + "hideContentDescriptioniOS": "Versteckt Inhalte der App beim Wechseln zwischen Apps", + "autoLockFeatureDescription": "Zeit, nach der die App gesperrt wird, nachdem sie in den Hintergrund verschoben wurde", + "appLockDescription": "Wähle zwischen dem Standard-Sperrbildschirm deines Gerätes und einem eigenen Sperrbildschirm mit PIN oder Passwort.", + "pinLock": "PIN-Sperre", + "enterPin": "PIN eingeben", + "setNewPin": "Neue PIN festlegen", + "importFailureDescNew": "Die ausgewählte Datei konnte nicht verarbeitet werden." } \ No newline at end of file diff --git a/auth/lib/l10n/arb/app_el.arb b/auth/lib/l10n/arb/app_el.arb index 0bbe9b9b81..e6f1d23b7c 100644 --- a/auth/lib/l10n/arb/app_el.arb +++ b/auth/lib/l10n/arb/app_el.arb @@ -182,6 +182,7 @@ "security": "Ασφάλεια", "lockscreen": "Οθόνη κλειδώματος", "authToChangeLockscreenSetting": "Παρακαλώ πραγματοποιήστε έλεγχο ταυτότητας για να αλλάξετε τις ρυθμίσεις οθόνης κλειδώματος", + "deviceLockEnablePreSteps": "Για να ενεργοποιήσετε το κλείδωμα της συσκευής, παρακαλώ ρυθμίστε τον κωδικό πρόσβασης της συσκευής ή το κλείδωμα οθόνης στις ρυθμίσεις του συστήματός σας.", "viewActiveSessions": "Προβολή ενεργών συνεδριών", "authToViewYourActiveSessions": "Παρακαλώ πραγματοποιήστε έλεγχο ταυτότητας για να δείτε τις ενεργές συνεδρίες σας", "searchHint": "Αναζήτηση...", @@ -458,6 +459,10 @@ "setNewPassword": "Ορίστε νέο κωδικό πρόσβασης", "deviceLock": "Κλείδωμα συσκευής", "hideContent": "Απόκρυψη περιεχομένου", + "hideContentDescriptionAndroid": "Απόκρυψη περιεχομένου εφαρμογής στην εναλλαγή εφαρμογών και απενεργοποίηση στιγμιότυπων οθόνης", + "hideContentDescriptioniOS": "Απόκρυψη περιεχομένου εφαρμογών στην εναλλαγή εφαρμογών", + "autoLockFeatureDescription": "Χρόνος μετά τον οποίο η εφαρμογή κλειδώνει μετά την τοποθέτηση στο παρασκήνιο", + "appLockDescription": "Επιλέξτε ανάμεσα στην προεπιλεγμένη οθόνη κλειδώματος της συσκευής σας και σε μια προσαρμοσμένη οθόνη κλειδώματος με ένα PIN ή έναν κωδικό πρόσβασης.", "pinLock": "Κλείδωμα καρφιτσωμάτων", "enterPin": "Εισαγωγή PIN", "setNewPin": "Ορίστε νέο PIN", diff --git a/auth/lib/l10n/arb/app_fr.arb b/auth/lib/l10n/arb/app_fr.arb index 1c411338ea..ec8ce6f86d 100644 --- a/auth/lib/l10n/arb/app_fr.arb +++ b/auth/lib/l10n/arb/app_fr.arb @@ -19,7 +19,7 @@ "pleaseVerifyDetails": "Veuillez vérifier vos informations et réessayez", "codeIssuerHint": "Émetteur", "codeSecretKeyHint": "Clé secrète", - "codeAccountHint": "Compte (vous@exemple.com)", + "codeAccountHint": "Compte (nom@exemple.com)", "codeTagHint": "Tag", "accountKeyType": "Type de clé", "sessionExpired": "Session expirée", @@ -118,7 +118,7 @@ "existingUser": "Utilisateur existant", "newUser": "Nouveau dans Ente", "delete": "Supprimer", - "enterYourPasswordHint": "Saisir votre mot de passe", + "enterYourPasswordHint": "Entrez votre mot de passe", "forgotPassword": "Mot de passe oublié", "oops": "Oups", "suggestFeatures": "Suggérer des fonctionnalités", @@ -135,14 +135,14 @@ "faq_a_5": "Vous pouvez activer le verrouillage FaceID dans Paramètres → Sécurité → Écran de verrouillage.", "somethingWentWrongMessage": "Quelque chose s'est mal passé, veuillez recommencer", "leaveFamily": "Quitter le plan familial", - "leaveFamilyMessage": "Êtes-vous certains de vouloir quitter le plan familial?", + "leaveFamilyMessage": "Êtes-vous sûr de vouloir quitter le plan familial ?", "inFamilyPlanMessage": "Vous êtes sur un plan familial !", "swipeHint": "Glisser vers la gauche pour modifier ou supprimer des codes", "scan": "Analyser", "scanACode": "Scanner un code", "verify": "Vérifier", "verifyEmail": "Vérifier l'e-mail", - "enterCodeHint": "Saisir le code à 6 caractères de votre appli d'authentification", + "enterCodeHint": "Entrez le code à 6 chiffres de votre application d'authentification", "lostDeviceTitle": "Appareil perdu ?", "twoFactorAuthTitle": "Authentification à deux facteurs", "passkeyAuthTitle": "Vérification du code d'accès", @@ -446,7 +446,9 @@ "viewRawCodes": "Afficher les codes bruts", "rawCodes": "Codes bruts", "rawCodeData": "Données de code brut", + "appLock": "Verrouillage d'application", "noSystemLockFound": "Aucun verrou système trouvé", + "toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Pour activer le verrouillage d'application, veuillez configurer un code d'accès ou le verrouillage de l'écran dans les paramètres de votre appareil.", "autoLock": "Verrouillage automatique", "immediately": "Immédiatement", "reEnterPassword": "Ressaisir le mot de passe", @@ -457,6 +459,9 @@ "setNewPassword": "Définir un nouveau mot de passe", "deviceLock": "Verrouillage de l'appareil", "hideContent": "Masquer le contenu", + "autoLockFeatureDescription": "Délai après lequel l'application se verrouille une fois qu'elle a été mise en arrière-plan", + "appLockDescription": "Choisissez entre l'écran de verrouillage par défaut de votre appareil et un écran de verrouillage par code PIN ou mot de passe personnalisé.", + "pinLock": "Verrouillage par code PIN", "enterPin": "Saisir le code PIN", "setNewPin": "Définir un nouveau code PIN", "importFailureDescNew": "Impossible de lire le fichier sélectionné." diff --git a/auth/lib/l10n/arb/app_sv.arb b/auth/lib/l10n/arb/app_sv.arb index e47c1b8c0e..e0c817c13c 100644 --- a/auth/lib/l10n/arb/app_sv.arb +++ b/auth/lib/l10n/arb/app_sv.arb @@ -20,10 +20,11 @@ "@sessionExpired": { "description": "Title of the dialog when the users current session is invalid/expired" }, - "pleaseLoginAgain": "Vänligen logga in igen", + "pleaseLoginAgain": "Logga in igen", "loggingOut": "Loggar ut...", "saveAction": "Spara", "nextTotpTitle": "nästa", + "deleteCodeTitle": "Radera kod?", "deleteCodeMessage": "Vill du ta bort den här koden? Det går inte att ångra den här åtgärden.", "viewLogsAction": "Visa loggar", "emailLogsTitle": "E-posta loggar", @@ -63,6 +64,7 @@ "importCodes": "Importera koder", "exportCodes": "Exportera koder", "importLabel": "Importera", + "ok": "OK", "cancel": "Avbryt", "yes": "Ja", "no": "Nej", @@ -109,8 +111,21 @@ "recoveryKeyOnForgotPassword": "Om du glömmer ditt lösenord är det enda sättet du kan återställa dina data med denna nyckel.", "saveKey": "Spara nyckel", "save": "Spara", + "send": "Skicka", "back": "Tillbaka", "createAccount": "Skapa konto", + "passwordStrength": "Lösenordsstyrka: {passwordStrengthValue}", + "@passwordStrength": { + "description": "Text to indicate the password strength", + "placeholders": { + "passwordStrengthValue": { + "description": "The strength of the password as a string", + "type": "String", + "example": "Weak or Moderate or Strong" + } + }, + "message": "Password Strength: {passwordStrengthText}" + }, "password": "Lösenord", "privacyPolicyTitle": "Integritetspolicy", "termsOfServicesTitle": "Villkor", @@ -151,6 +166,7 @@ "incorrectRecoveryKey": "Felaktig återställningsnyckel", "enterPassword": "Ange lösenord", "export": "Exportera", + "signInToBackup": "Logga in för att säkerhetskopiera dina koder", "singIn": "Logga in", "shouldHideCode": "Dölj koder", "androidCancelButton": "Avbryt", @@ -163,7 +179,11 @@ }, "noInternetConnection": "Ingen internetanslutning", "pleaseCheckYourInternetConnectionAndTryAgain": "Kontrollera din internetanslutning och försök igen.", + "signOutOtherDevices": "Logga ut andra enheter", "loginSessionExpiredDetails": "Din session har upphört. Logga in igen.", + "create": "Skapa", + "editTag": "Redigera tagg", + "deleteTagTitle": "Radera tagg?", "immediately": "Omedelbart", "reEnterPassword": "Ange lösenord igen", "reEnterPin": "Ange PIN-kod igen", diff --git a/auth/lib/l10n/arb/app_ta.arb b/auth/lib/l10n/arb/app_ta.arb new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/auth/lib/l10n/arb/app_ta.arb @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/auth/lib/l10n/arb/app_vi.arb b/auth/lib/l10n/arb/app_vi.arb index 672afa36c3..1c75de3109 100644 --- a/auth/lib/l10n/arb/app_vi.arb +++ b/auth/lib/l10n/arb/app_vi.arb @@ -21,12 +21,13 @@ "codeSecretKeyHint": "Khóa bí mật", "codeAccountHint": "Tài khoản (bạn@miền.com)", "codeTagHint": "Thẻ", + "accountKeyType": "Loại khóa", "sessionExpired": "Phiên làm việc đã hết hạn", "@sessionExpired": { "description": "Title of the dialog when the users current session is invalid/expired" }, "pleaseLoginAgain": "Vui lòng đăng nhập lại", - "loggingOut": "Đang thoát...", + "loggingOut": "Đang đăng xuất...", "timeBasedKeyType": "Dựa trên thời gian (TOTP)", "counterBasedKeyType": "Dựa trên bộ đếm (HOTP)", "saveAction": "Lưu", @@ -74,7 +75,7 @@ "supportDevs": "Đăng ký ente để hỗ trợ dự án này.", "supportDiscount": "Sử dụng mã giảm giá \"AUTH\" để được giảm 10% trong năm đầu tiên", "changeEmail": "Thay đổi email", - "changePassword": "Thay đổi mật khẩu", + "changePassword": "Đổi mật khẩu", "data": "Dữ liệu", "importCodes": "Nhập mã", "importTypePlainText": "Văn bản thuần", @@ -131,7 +132,7 @@ "faq_a_4": "Bạn có thể hỗ trợ sự phát triển của dự án này bằng cách đăng ký ứng dụng Ảnh @ ente.io của chúng tôi.", "faq_q_5": "Làm sao để tôi bật FaceID trong ente", "faq_a_5": "Bạn có thể bật khóa FaceID trong Cài đặt → Bảo mật → Màn hình khóa.", - "somethingWentWrongMessage": "Phát hiện có lỗi, xin thử lại", + "somethingWentWrongMessage": "Đã xảy ra lỗi, xin thử lại", "leaveFamily": "Rời khỏi gia đình", "leaveFamilyMessage": "Bạn có chắc chắn muốn thoát khỏi gói dành cho gia đình không?", "inFamilyPlanMessage": "Bạn đang sử dụng gói dành cho gia đình!", @@ -141,7 +142,7 @@ "verify": "Xác minh", "verifyEmail": "Xác nhận địa chỉ Email", "enterCodeHint": "Nhập mã gồm 6 chữ số từ ứng dụng xác thực của bạn", - "lostDeviceTitle": "Bạn đã mất thiết bị?", + "lostDeviceTitle": "Mất thiết bị?", "twoFactorAuthTitle": "Xác thực hai yếu tố", "recoverAccount": "Khôi phục tài khoản", "enterRecoveryKeyHint": "Nhập khóa khôi phục của bạn", @@ -154,6 +155,7 @@ } } }, + "invalidQRCode": "Mã QR không hợp lệ", "noRecoveryKeyTitle": "Không có khóa khôi phục?", "enterEmailHint": "Nhập địa chỉ email của bạn", "invalidEmailTitle": "Địa chỉ email không hợp lệ", @@ -177,6 +179,7 @@ "security": "Bảo mật", "lockscreen": "Màn hình khoá", "authToChangeLockscreenSetting": "Vui lòng xác thực để thay đổi cài đặt màn hình khóa", + "deviceLockEnablePreSteps": "Để bật khoá thiết bị, vui lòng thiết lập mật khẩu thiết bị hoặc khóa màn hình trong cài đặt hệ thống của bạn.", "viewActiveSessions": "Xem danh sách phiên làm việc hiện tại", "authToViewYourActiveSessions": "Vui lòng xác thực để xem danh sách phiên làm việc của bạn", "searchHint": "Tìm kiếm...", @@ -195,6 +198,8 @@ "recoveryKeySaveDescription": "Chúng tôi không lưu trữ khóa này, vui lòng lưu khóa 24 từ này ở nơi an toàn.", "doThisLater": "Để sau", "saveKey": "Lưu khóa", + "save": "Lưu", + "send": "Gửi", "back": "Quay lại", "createAccount": "Tạo tài khoản", "passwordStrength": "Độ mạnh mật khẩu: {passwordStrengthValue}", @@ -253,6 +258,8 @@ "exportLogs": "Xuất nhật ký", "enterYourRecoveryKey": "Nhập khóa khôi phục của bạn", "tempErrorContactSupportIfPersists": "Có vẻ như đã xảy ra sự cố. Vui lòng thử lại sau một thời gian. Nếu lỗi vẫn tiếp diễn, vui lòng liên hệ với nhóm hỗ trợ của chúng tôi.", + "networkHostLookUpErr": "Không thể kết nối đến Ente, vui lòng kiểm tra lại kết nối mạng. Nếu vẫn còn lỗi, xin vui lòng liên hệ hỗ trợ.", + "networkConnectionRefusedErr": "Không thể kết nối đến Ente, vui lòng thử lại sau. Nếu vẫn còn lỗi, xin vui lòng liên hệ hỗ trợ.", "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Có vẻ như đã xảy ra sự cố. Vui lòng thử lại sau một thời gian. Nếu lỗi vẫn tiếp diễn, vui lòng liên hệ với nhóm hỗ trợ của chúng tôi.", "about": "Về chúng tôi", "weAreOpenSource": "Chúng tôi có mã nguồn mở!", @@ -342,6 +349,7 @@ "deleteCodeAuthMessage": "Xác minh để xóa mã", "showQRAuthMessage": "Xác minh để hiển thị mã QR", "confirmAccountDeleteTitle": "Xác nhận xóa tài khoản", + "confirmAccountDeleteMessage": "Tài khoản này được liên kết với các ứng dụng Ente trên các nền tảng khác, nếu bạn có sử dụng.\n\nDữ liệu đã tải lên của bạn, trên mọi nền tảng, sẽ bị lên lịch xóa và tài khoản của bạn sẽ bị xóa vĩnh viễn.", "androidBiometricHint": "Xác định danh tính", "@androidBiometricHint": { "description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters." @@ -402,11 +410,37 @@ "doNotSignOut": "Không được đăng xuất", "hearUsWhereTitle": "Bạn biết đến Ente bằng cách nào? (không bắt buộc)", "hearUsExplanation": "Chúng tôi không theo dõi lượt cài đặt ứng dụng. Sẽ rất hữu ích nếu bạn cho chúng tôi biết nơi bạn tìm thấy chúng tôi!", + "recoveryKeySaved": "Đã lưu khoá dự phòng vào thư mục Tải về!", + "waitingForVerification": "Đang chờ xác thực", + "loginSessionExpired": "Phiên làm việc hết hạn", + "loginSessionExpiredDetails": "Phiên làm việc hết hạn. Vui lòng đăng nhập lại.", + "developerSettings": "Cài đặt cho nhà phát triển", + "customEndpoint": "Đã kết nối đến", + "pinText": "Ghim", + "unpinText": "Bỏ ghim", + "tags": "Thẻ", + "createNewTag": "Tạo thẻ mới", + "tag": "Thẻ", + "create": "Tạo", + "editTag": "Sửa thẻ", + "deleteTagTitle": "Xóa thẻ?", + "deleteTagMessage": "Bạn có chắc chắn muốn xóa thẻ này không? Hành động này không thể đảo ngược.", "updateNotAvailable": "Cập nhật không khả dụng", "viewRawCodes": "Xem mã nguồn", "rawCodes": "Mã nguồn", + "appLock": "Khóa ứng dụng", + "autoLock": "Tự động khóa", + "immediately": "Tức thì", + "reEnterPassword": "Nhập lại mật khẩu", + "reEnterPin": "Nhập lại mã PIN", + "next": "Tiếp", + "tooManyIncorrectAttempts": "Quá nhiều lần thử không chính xác", + "tapToUnlock": "Nhấn để mở khóa", "setNewPassword": "Đặt lại mật khẩu", "deviceLock": "Khóa thiết bị", + "hideContent": "Ẩn nội dung", + "hideContentDescriptionAndroid": "Ẩn nội dung khi chuyển ứng dụng và chặn chụp màn hình", + "hideContentDescriptioniOS": "Ẩn nội dung khi chuyển ứng dụng", "pinLock": "Mã PIN", "enterPin": "Nhập mã PIN", "setNewPin": "Đổi mã PIN" diff --git a/auth/lib/l10n/arb/app_zh.arb b/auth/lib/l10n/arb/app_zh.arb index b20bf2dd38..a62a7c13f3 100644 --- a/auth/lib/l10n/arb/app_zh.arb +++ b/auth/lib/l10n/arb/app_zh.arb @@ -27,15 +27,15 @@ "description": "Title of the dialog when the users current session is invalid/expired" }, "pleaseLoginAgain": "请重新登录", - "loggingOut": "正在退出登录...", - "timeBasedKeyType": "基于时间的 (TOTP)", - "counterBasedKeyType": "基于计数器的(HOTP)", + "loggingOut": "正在登出...", + "timeBasedKeyType": "基于时间 (TOTP)", + "counterBasedKeyType": "基于计数器 (HOTP)", "saveAction": "保存", "nextTotpTitle": "下一个", "deleteCodeTitle": "要删除代码吗?", - "deleteCodeMessage": "您确定要删除此代码吗?此操作是不可逆的。", + "deleteCodeMessage": "您确定要删除此代码吗?此操作不可逆。", "viewLogsAction": "查看日志", - "sendLogsDescription": "这将跨日志发送以帮助我们调试您的问题。 虽然我们采取预防措施以确保不记录敏感信息,但我们鼓励您在共享这些日志之前先查看它们。", + "sendLogsDescription": "这将发送日志以帮助我们调试您的问题。虽然我们采取预防措施确保不记录敏感信息,但我们建议您在共享这些日志之前先查看它们。", "preparingLogsTitle": "正在准备日志...", "emailLogsTitle": "电子邮件日志", "emailLogsMessage": "请将日志发送至 {email}", @@ -67,13 +67,13 @@ "pleaseWait": "请稍候...", "generatingEncryptionKeysTitle": "正在生成加密密钥...", "recreatePassword": "重新创建密码", - "recreatePasswordMessage": "当前设备的强度不足以验证您的密码, 所以我们需要以一种能够与所有设备一起运行的方式重新生成它。 \n\n请使用您的恢复密钥登录并重新生成您的密码 (如果您愿意,您可以再次使用相同密钥)。", + "recreatePasswordMessage": "当前设备的功能不足以验证您的密码,因此我们需要以一种适用于所有设备的方式重新生成一次密码。\n\n请使用您的恢复密钥登录并重新生成您的密码(如果您愿意,可以再次使用相同的密码)。", "useRecoveryKey": "使用恢复密钥", "incorrectPasswordTitle": "密码错误", "welcomeBack": "欢迎回来!", "madeWithLoveAtPrefix": "用❤️制成 ", "supportDevs": "订阅 ente 以支持此项目。", - "supportDiscount": "使用优惠券号码“AUTH”获得第一年优惠10%的折扣", + "supportDiscount": "使用优惠码“AUTH”可享受首年 10% 折扣", "changeEmail": "修改邮箱", "changePassword": "修改密码", "data": "数据", @@ -83,29 +83,29 @@ "passwordForDecryptingExport": "用来解密导出的密码", "passwordEmptyError": "密码不能为空", "importFromApp": "从 {appName} 导入代码", - "importGoogleAuthGuide": "使用“转移帐户”选项将您的帐户从 Google 身份验证器导出到二维码。然后使用另一台设备扫描二维码。\n\n提示:您可以使用笔记本电脑的网络摄像头拍摄二维码的照片。", + "importGoogleAuthGuide": "使用“转移账户”选项将您的账户从 Google Authenticator 导出到二维码。然后使用另一台设备扫描二维码。\n\n提示:您可以使用笔记本电脑的摄像头拍摄二维码的照片。", "importSelectJsonFile": "选择 JSON 文件", "importSelectAppExport": "选择 {appName} 的导出文件", "importEnteEncGuide": "选择从 Ente 导出的 JSON 加密文件", "importRaivoGuide": "使用 Raivo 设置中的“将 OTP 导出到 Zip 存档”选项。\n\n解压 zip 文件并导入 JSON 文件。", - "importBitwardenGuide": "使用 Bitwarden 工具中的“导出保管库”选项并导入未加密的 JSON 文件。", - "importAegisGuide": "在Aegis的设置中使用\"导出密码库\"选项。\n\n如果您的密码库已加密,您需要输入密码才能解密密码库。", - "import2FasGuide": "使用 2FAS 中的“设置 -> 备份 - 导出”选项。\n\n如果您的备份已被加密,则需要输入密码才能解密备份", + "importBitwardenGuide": "使用 Bitwarden 工具中的“导出密码库”选项并导入未加密的 JSON 文件。", + "importAegisGuide": "使用 Aegis 设置中的“导出密码库”选项。\n\n如果您的密码库已加密,则需要输入密码库密码才能解密密码库。", + "import2FasGuide": "使用 2FAS 中的“设置 -> 备份 -> 导出”选项。\n\n如果您的备份已加密,则需要输入密码来解密备份", "importLastpassGuide": "使用 Lastpass Authenticator 设置中的“转移账户”选项,然后按“将账户导出到文件”。导入下载的 JSON。", "exportCodes": "导出代码", "importLabel": "导入", - "importInstruction": "请以以下格式选择包含代码列表的文件", + "importInstruction": "请选择一个包含以下格式的代码列表的文件", "importCodeDelimiterInfo": "代码可以用逗号或新行分隔。", "selectFile": "选择文件", "emailVerificationToggle": "电子邮件验证", - "emailVerificationEnableWarning": "如果您将 2FA 存储到我们的电子邮件中,则打开电子邮件验证可能会导致僵局。如果您被一项服务锁定,您可能无法登录另一项服务。", + "emailVerificationEnableWarning": "为避免被锁在您的账户之外,请在启用电子邮件验证之前确保在 Ente Auth 之外存储电子邮件双重验证的副本。", "authToChangeEmailVerificationSetting": "请进行身份验证以更改电子邮件验证", "authToViewYourRecoveryKey": "请验证以查看您的恢复密钥", "authToChangeYourEmail": "请验证以更改您的电子邮件", "authToChangeYourPassword": "请验证以更改密码", - "authToViewSecrets": "请进行身份验证以查看您的秘密", + "authToViewSecrets": "请进行身份验证以查看您的密钥", "authToInitiateSignIn": "请进行身份验证以启动登录进行备份。", - "ok": "好的", + "ok": "确定", "cancel": "取消", "yes": "是", "no": "否", @@ -125,8 +125,8 @@ "faq": "常见问题", "faq_q_1": "Auth 的安全性如何?", "faq_a_1": "您通过 Auth 备份的所有代码均以端到端加密方式存储。这意味着只有您可以访问您的代码。我们的应用程序是开源的并且我们的加密技术已经过外部审计。", - "faq_q_2": "我可以在桌面上访问我的代码吗?", - "faq_a_2": "您可以在 web @auth.ente.io 上访问您的代码。", + "faq_q_2": "我可以在桌面设备上访问我的代码吗?", + "faq_a_2": "您可以在网页 auth.ente.io 上访问您的代码。", "faq_q_3": "我如何删除代码?", "faq_a_3": "您可以通过向左滑动该项目来删除该代码。", "faq_q_4": "我该如何支持该项目?", @@ -240,9 +240,9 @@ "ackPasswordLostWarning": "我明白,如果我丢失密码,我可能会丢失我的数据,因为我的数据是 端到端加密的。", "loginTerms": "点击登录后,我同意 服务条款隐私政策", "logInLabel": "登录", - "logout": "退出登录", - "areYouSureYouWantToLogout": "您确定要退出登录吗?", - "yesLogout": "是的,退出登陆", + "logout": "登出", + "areYouSureYouWantToLogout": "您确定要登出吗?", + "yesLogout": "是的,登出", "exit": "退出", "verifyingRecoveryKey": "正在验证恢复密钥...", "recoveryKeyVerified": "恢复密钥已验证", @@ -299,7 +299,7 @@ "sorry": "抱歉", "importFailureDesc": "无法解析选定的文件。\n如果您需要帮助,请写入support@ente.io!", "pendingSyncs": "警告", - "pendingSyncsWarningBody": "您的一些代码尚未备份。\n\n请确保您在退出登录之前备份这些代码。", + "pendingSyncsWarningBody": "您的一些代码尚未备份。\n\n请确保您在登出之前备份这些代码。", "checkInboxAndSpamFolder": "请检查您的收件箱 (或者是在您的“垃圾邮件”列表内) 以完成验证", "tapToEnterCode": "点击以输入代码", "resendEmail": "重新发送电子邮件", @@ -316,8 +316,8 @@ }, "activeSessions": "已登录的设备", "somethingWentWrongPleaseTryAgain": "出了点问题,请重试", - "thisWillLogYouOutOfThisDevice": "这将使您在此设备上退出登录!", - "thisWillLogYouOutOfTheFollowingDevice": "这将使您在以下设备中退出登录:", + "thisWillLogYouOutOfThisDevice": "这将使您登出该设备!", + "thisWillLogYouOutOfTheFollowingDevice": "这将使您登出以下设备:", "terminateSession": "是否终止会话?", "terminate": "终止", "thisDevice": "此设备", @@ -396,7 +396,7 @@ "@androidGoToSettingsDescription": { "description": "Message advising the user to go to the settings and configure biometric on their device. It shows in a dialog on Android side." }, - "iOSLockOut": "生物识别身份验证已禁用。请锁定再解锁您的屏幕以启用它。", + "iOSLockOut": "生物识别身份验证已禁用。请锁定并解锁屏幕以启用该功能。", "@iOSLockOut": { "description": "Message advising the user to re-enable biometrics on their device. It shows in a dialog on iOS side." }, @@ -410,11 +410,11 @@ }, "noInternetConnection": "无互联网连接", "pleaseCheckYourInternetConnectionAndTryAgain": "请检查您的互联网连接,然后重试。", - "signOutFromOtherDevices": "从其他设备退出登录", - "signOutOtherBody": "如果你认为有人可能知道你的密码,你可以强制所有使用你账户的其他设备退出登录。", + "signOutFromOtherDevices": "从其他设备登出", + "signOutOtherBody": "如果您认为有人可能知道您的密码,您可以强制所有其他使用您账户的设备登出。", "signOutOtherDevices": "登出其他设备", - "doNotSignOut": "不要退登", - "hearUsWhereTitle": "您是如何知道Ente的? (可选的)", + "doNotSignOut": "不要登出", + "hearUsWhereTitle": "您是怎么知道 Ente 的?(可选)", "hearUsExplanation": "我们不跟踪应用程序安装情况。如果您告诉我们您是在哪里找到我们的,将会有所帮助!", "recoveryKeySaved": "恢复密钥已保存在下载文件夹中!", "waitingForBrowserRequest": "正在等待浏览器请求...", From 1197e11f58fc17e5b2b35870efba3101f16eebbe Mon Sep 17 00:00:00 2001 From: Tanguy Date: Fri, 30 Aug 2024 18:18:04 +0200 Subject: [PATCH 179/275] Remove unnecessary slug fields --- .../custom-icons/_data/custom-icons.json | 56 ++++++------------- 1 file changed, 16 insertions(+), 40 deletions(-) diff --git a/auth/assets/custom-icons/_data/custom-icons.json b/auth/assets/custom-icons/_data/custom-icons.json index 0918925ace..77e7f20b01 100644 --- a/auth/assets/custom-icons/_data/custom-icons.json +++ b/auth/assets/custom-icons/_data/custom-icons.json @@ -70,19 +70,16 @@ "blockchain.com", "blockchain.com Wallet", "blockchain.com Exchange" - ], - "slug": "blockchain" + ] }, { "title": "BorgBase", "altNames": [ "borg" - ], - "slug": "BorgBase" + ] }, { "title": "Booking", - "slug": "booking", "altNames":[ "Booking.com" ] @@ -117,8 +114,7 @@ "title": "CloudAMQP" }, { - "title": "ConfigCat", - "slug": "configcat" + "title": "ConfigCat" }, { "title": "CoinDCX" @@ -147,8 +143,7 @@ "title": "DCS", "altNames": [ "Digital Combat Simulator" - ], - "slug": "dcs" + ] }, { "title": "DEGIRO" @@ -240,16 +235,13 @@ "title": "HuggingFace", "altNames": [ "Hugging Face" - ], - "slug": "huggingface" + ] }, { - "title": "IceDrive", - "slug": "Icedrive" + "title": "IceDrive" }, { - "titile": "Infomaniak", - "slug": "infomaniak" + "titile": "Infomaniak" }, { "title": "ING" @@ -270,8 +262,7 @@ "hex": "000000" }, { - "title": "IVPN", - "slug": "IVPN" + "title": "IVPN" }, { "title": "Jagex", @@ -333,7 +324,6 @@ "mathstodon", "fosstodon" ], - "slug": "mastodon", "hex": "6364FF" }, { @@ -420,8 +410,7 @@ "title": "Notion" }, { - "title": "NuCommunity", - "slug": "nucommunity" + "title": "NuCommunity" }, { "title": "NVIDIA" @@ -447,8 +436,7 @@ "title": "PayPal" }, { - "title": "pCloud", - "slug": "pCloud" + "title": "pCloud" }, { "title": "Peerberry", @@ -495,7 +483,6 @@ "title": "Registro br", "slug": "registro_br", "altNames": [ - "Registro br", "registrobr", "Registro.br" ] @@ -551,8 +538,7 @@ ] }, { - "title": "SMTP2GO", - "slug": "smtp2go" + "title": "SMTP2GO" }, { "title": "Snapchat" @@ -571,7 +557,6 @@ }, { "title": "TCPShield", - "slug": "tcpshield", "hex": "FFFFFF" }, { @@ -597,7 +582,6 @@ }, { "title": "Trading 212", - "slug": "trading212", "hex": "4BA4DE" }, { @@ -636,7 +620,6 @@ }, { "title": "Uphold", - "slug": "uphold", "hex": "6FE68A" }, { @@ -660,12 +643,10 @@ "title": "Wise" }, { - "title": "WYZE", - "slug": "wyze" + "title": "WYZE" }, { "title": "WorkOS", - "slug": "workos", "altNames": [ "Work OS" ] @@ -675,8 +656,7 @@ "altNames": [ "Ya", "Яндекс" - ], - "slug": "Yandex" + ] }, { "title": "yahoo" @@ -686,21 +666,17 @@ "altNames": [ "You Need A Budget" ], - "slug": "ynab", "hex": "3B5EDA" }, { - "title": "Shakepay", - "slug": "shakepay" + "title": "Shakepay" }, { "title": "Newton", - "altNames": ["Newton Crypto"], - "slug": "newton" + "altNames": ["Newton Crypto"] }, { - "title": "RippleMatch", - "slug": "ripplematch" + "title": "RippleMatch" }, { "title": "T-Mobile ID", From a13256cf3968a488b7be4bc8a8d536a08c6afdd7 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Fri, 30 Aug 2024 18:19:00 +0200 Subject: [PATCH 180/275] Remove unnecessary slug fields --- auth/assets/custom-icons/_data/custom-icons.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/auth/assets/custom-icons/_data/custom-icons.json b/auth/assets/custom-icons/_data/custom-icons.json index 77e7f20b01..a3b49db55d 100644 --- a/auth/assets/custom-icons/_data/custom-icons.json +++ b/auth/assets/custom-icons/_data/custom-icons.json @@ -176,8 +176,8 @@ "hex": "1DB954" }, { - "title": "enom" - }, + "title": "enom" + }, { "title": "Epic Games", "slug": "epic_games", @@ -686,8 +686,7 @@ "slug": "t-mobile" }, { - "title": "Wealthfront", - "slug": "wealthfront" + "title": "Wealthfront" }, { "title": "BinanceUS", From dbde6abc8c58608ef01463c14e8c46d2f41c4b2f Mon Sep 17 00:00:00 2001 From: Tanguy Date: Fri, 30 Aug 2024 18:22:12 +0200 Subject: [PATCH 181/275] Refactor and clean code --- .../custom-icons/_data/custom-icons.json | 51 ++++++++++--------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/auth/assets/custom-icons/_data/custom-icons.json b/auth/assets/custom-icons/_data/custom-icons.json index a3b49db55d..cbf3dc6b60 100644 --- a/auth/assets/custom-icons/_data/custom-icons.json +++ b/auth/assets/custom-icons/_data/custom-icons.json @@ -31,12 +31,12 @@ "title": "bitget" }, { - "titile":"bitget wallet", - "slug":"bitget_wallet" + "titile": "bitget wallet", + "slug": "bitget_wallet" }, { "title": "Bitmart", - "hex":"000000" + "hex": "000000" }, { "title": "BitMEX" @@ -80,14 +80,14 @@ }, { "title": "Booking", - "altNames":[ + "altNames": [ "Booking.com" ] }, { "title": "Brave Creators", "slug": "brave_creators", - "altNames":[ + "altNames": [ "Brave", "Brave Rewards", "Brave Browser" @@ -168,8 +168,8 @@ "slug": "dusnet" }, { - "title":"ecitizen kenya", - "slug":"ecitizen_kenya" + "title": "ecitizen kenya", + "slug": "ecitizen_kenya" }, { "title": "ente", @@ -213,10 +213,10 @@ }, { "title": "Gosuslugi", + "slug": "Gosuslugi", "altNames": [ "Госуслуги" - ], - "slug": "Gosuslugi" + ] }, { "title": "Habbo" @@ -355,11 +355,10 @@ "title": "Mozilla" }, { - "title": "Murena", + "title": "ecloud", "altNames": [ - "eCloud" - ], - "slug": "ecloud" + "Murena" + ] }, { "title": "MyFRITZ!Net", @@ -421,14 +420,15 @@ { "titile": "OpenObserve", "slug": "open_observe", - "altNames":[ + "altNames": [ "openobserve.ai", "openobserve ai" ] }, { "title": "okx", - "hex": "000000" }, + "hex": "000000" + }, { "title": "Parsec" }, @@ -673,32 +673,35 @@ }, { "title": "Newton", - "altNames": ["Newton Crypto"] + "altNames": [ + "Newton Crypto" + ] }, { "title": "RippleMatch" }, { - "title": "T-Mobile ID", + "title": "T-Mobile", "altNames": [ - "T-Mobile" - ], - "slug": "t-mobile" + "T-Mobile ID" + ] }, { "title": "Wealthfront" }, { "title": "BinanceUS", + "slug": "binance_us", "altNames": [ "Binance US" - ], - "slug": "binance_us" + ] }, { "title": "Bethesda Softworks", - "altNames": ["Bethesda"], - "slug": "bethesda" + "slug": "bethesda", + "altNames": [ + "Bethesda" + ] } ] } From b1e727f269e4f998af14da7363c984be929ea70c Mon Sep 17 00:00:00 2001 From: Tanguy Date: Fri, 30 Aug 2024 18:24:51 +0200 Subject: [PATCH 182/275] Refactor --- auth/assets/custom-icons/_data/custom-icons.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/auth/assets/custom-icons/_data/custom-icons.json b/auth/assets/custom-icons/_data/custom-icons.json index cbf3dc6b60..d4b5de23a8 100644 --- a/auth/assets/custom-icons/_data/custom-icons.json +++ b/auth/assets/custom-icons/_data/custom-icons.json @@ -697,10 +697,9 @@ ] }, { - "title": "Bethesda Softworks", - "slug": "bethesda", + "title": "Bethesda", "altNames": [ - "Bethesda" + "Bethesda Softworks" ] } ] From a1742f71e0c5f6b275566d923905cafea7302a16 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Fri, 30 Aug 2024 18:32:11 +0200 Subject: [PATCH 183/275] Fix typo --- auth/assets/custom-icons/_data/custom-icons.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/auth/assets/custom-icons/_data/custom-icons.json b/auth/assets/custom-icons/_data/custom-icons.json index d4b5de23a8..ea9d05a0f3 100644 --- a/auth/assets/custom-icons/_data/custom-icons.json +++ b/auth/assets/custom-icons/_data/custom-icons.json @@ -31,7 +31,7 @@ "title": "bitget" }, { - "titile": "bitget wallet", + "title": "bitget wallet", "slug": "bitget_wallet" }, { @@ -241,7 +241,7 @@ "title": "IceDrive" }, { - "titile": "Infomaniak" + "title": "Infomaniak" }, { "title": "ING" @@ -418,7 +418,7 @@ "title": "Odido" }, { - "titile": "OpenObserve", + "title": "OpenObserve", "slug": "open_observe", "altNames": [ "openobserve.ai", @@ -626,7 +626,7 @@ "title": "Upstox" }, { - "titile": "Vikunja", + "title": "Vikunja", "slug": "vikunja" }, { From 0a7a8e49fed329879134badda97d83338d301e85 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Fri, 30 Aug 2024 18:32:51 +0200 Subject: [PATCH 184/275] Reorder alphabetically --- .../custom-icons/_data/custom-icons.json | 104 +++++++++--------- 1 file changed, 49 insertions(+), 55 deletions(-) diff --git a/auth/assets/custom-icons/_data/custom-icons.json b/auth/assets/custom-icons/_data/custom-icons.json index ea9d05a0f3..f80c4f0551 100644 --- a/auth/assets/custom-icons/_data/custom-icons.json +++ b/auth/assets/custom-icons/_data/custom-icons.json @@ -24,6 +24,19 @@ { "title": "AscendEX" }, + { + "title": "Bethesda", + "altNames": [ + "Bethesda Softworks" + ] + }, + { + "title": "BinanceUS", + "slug": "binance_us", + "altNames": [ + "Binance US" + ] + }, { "title": "Bitfinex" }, @@ -31,7 +44,7 @@ "title": "bitget" }, { - "title": "bitget wallet", + "titile": "bitget wallet", "slug": "bitget_wallet" }, { @@ -107,14 +120,11 @@ "slug": "cih", "hex": "D14633" }, - { - "title": "Cloudflare" - }, { "title": "CloudAMQP" }, { - "title": "ConfigCat" + "title": "Cloudflare" }, { "title": "CoinDCX" @@ -122,6 +132,9 @@ { "title": "ConfigCat" }, + { + "title": "ConfigCat" + }, { "title": "Control D", "slug": "controld", @@ -171,6 +184,12 @@ "title": "ecitizen kenya", "slug": "ecitizen_kenya" }, + { + "title": "ecloud", + "altNames": [ + "Murena" + ] + }, { "title": "ente", "hex": "1DB954" @@ -241,7 +260,7 @@ "title": "IceDrive" }, { - "title": "Infomaniak" + "titile": "Infomaniak" }, { "title": "ING" @@ -354,12 +373,6 @@ { "title": "Mozilla" }, - { - "title": "ecloud", - "altNames": [ - "Murena" - ] - }, { "title": "MyFRITZ!Net", "slug": "myfritz", @@ -395,6 +408,12 @@ { "title": "NextDNS" }, + { + "title": "Newton", + "altNames": [ + "Newton Crypto" + ] + }, { "title": "ngrok", "hex": "858585" @@ -418,7 +437,7 @@ "title": "Odido" }, { - "title": "OpenObserve", + "titile": "OpenObserve", "slug": "open_observe", "altNames": [ "openobserve.ai", @@ -494,6 +513,9 @@ "title": "Revolt", "hex": "858585" }, + { + "title": "RippleMatch" + }, { "title": "Rockstar Games", "slug": "rockstar_games" @@ -516,6 +538,9 @@ { "title": "service-bw" }, + { + "title": "Shakepay" + }, { "title": "SimpleLogin" }, @@ -626,9 +651,12 @@ "title": "Upstox" }, { - "title": "Vikunja", + "titile": "Vikunja", "slug": "vikunja" }, + { + "title": "Wealthfront" + }, { "title": "Wealthsimple" }, @@ -642,15 +670,18 @@ { "title": "Wise" }, - { - "title": "WYZE" - }, { "title": "WorkOS", "altNames": [ "Work OS" ] }, + { + "title": "WYZE" + }, + { + "title": "yahoo" + }, { "title": "Yandex", "altNames": [ @@ -658,49 +689,12 @@ "Яндекс" ] }, - { - "title": "yahoo" - }, { "title": "YNAB", "altNames": [ "You Need A Budget" ], "hex": "3B5EDA" - }, - { - "title": "Shakepay" - }, - { - "title": "Newton", - "altNames": [ - "Newton Crypto" - ] - }, - { - "title": "RippleMatch" - }, - { - "title": "T-Mobile", - "altNames": [ - "T-Mobile ID" - ] - }, - { - "title": "Wealthfront" - }, - { - "title": "BinanceUS", - "slug": "binance_us", - "altNames": [ - "Binance US" - ] - }, - { - "title": "Bethesda", - "altNames": [ - "Bethesda Softworks" - ] } ] -} +} \ No newline at end of file From 05cf33ffb2caf9c1d76920e3159dac3a4737f1d5 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Fri, 30 Aug 2024 18:50:21 +0200 Subject: [PATCH 185/275] Remove unnecessary hex fields --- .../custom-icons/_data/custom-icons.json | 42 +++++++------------ auth/assets/custom-icons/icons/kucoin.svg | 2 +- auth/assets/custom-icons/icons/postnl.svg | 2 +- 3 files changed, 16 insertions(+), 30 deletions(-) diff --git a/auth/assets/custom-icons/_data/custom-icons.json b/auth/assets/custom-icons/_data/custom-icons.json index f80c4f0551..5c04d71028 100644 --- a/auth/assets/custom-icons/_data/custom-icons.json +++ b/auth/assets/custom-icons/_data/custom-icons.json @@ -64,8 +64,7 @@ "title": "Bitstamp" }, { - "title": "Bitvavo", - "hex": "0051FF" + "title": "Bitvavo" }, { "title": "Bitwarden" @@ -137,8 +136,7 @@ }, { "title": "Control D", - "slug": "controld", - "hex": "5FD800" + "slug": "controld" }, { "title": "Crowdpear" @@ -291,8 +289,7 @@ "title": "Kagi" }, { - "title": "Kick", - "hex": "53FC19" + "title": "Kick" }, { "title": "Kite" @@ -305,15 +302,13 @@ "color": "00CC00" }, { - "title": "Kraken", - "hex": "5848D5" + "title": "Kraken" }, { "title": "Kronos" }, { - "title": "KuCoin", - "hex": "01BC8D" + "title": "KuCoin" }, { "title": "La Poste", @@ -458,12 +453,10 @@ "title": "pCloud" }, { - "title": "Peerberry", - "hex": "03E5A5" + "title": "Peerberry" }, { - "title": "Pingvin Share", - "hex": "485099" + "title": "Pingvin Share" }, { "title": "Plutus", @@ -473,12 +466,10 @@ "title": "Poloniex" }, { - "title": "Porkbun", - "hex": "F27777" + "title": "Porkbun" }, { - "title": "PostNL", - "color": "EF8300" + "title": "PostNL" }, { "title": "Privacy Guides", @@ -521,8 +512,7 @@ "slug": "rockstar_games" }, { - "title": "RuneMate", - "hex": "2ECC71" + "title": "RuneMate" }, { "title": "Rust Language Forum", @@ -570,8 +560,7 @@ }, { "title": "Standard Notes", - "slug": "standardnotes", - "hex": "2173E6" + "slug": "standardnotes" }, { "title": "Surfshark" @@ -606,8 +595,7 @@ "title": "TorGuard" }, { - "title": "Trading 212", - "hex": "4BA4DE" + "title": "Trading 212" }, { "title": "TradingView" @@ -644,8 +632,7 @@ "hex": "858585" }, { - "title": "Uphold", - "hex": "6FE68A" + "title": "Uphold" }, { "title": "Upstox" @@ -693,8 +680,7 @@ "title": "YNAB", "altNames": [ "You Need A Budget" - ], - "hex": "3B5EDA" + ] } ] } \ No newline at end of file diff --git a/auth/assets/custom-icons/icons/kucoin.svg b/auth/assets/custom-icons/icons/kucoin.svg index 1b67b54717..d51a1660d8 100644 --- a/auth/assets/custom-icons/icons/kucoin.svg +++ b/auth/assets/custom-icons/icons/kucoin.svg @@ -1 +1 @@ - + diff --git a/auth/assets/custom-icons/icons/postnl.svg b/auth/assets/custom-icons/icons/postnl.svg index 3aa9415188..8ab3ff6784 100644 --- a/auth/assets/custom-icons/icons/postnl.svg +++ b/auth/assets/custom-icons/icons/postnl.svg @@ -1 +1 @@ - + From dc120a06ca8b80e40fc5bab021af95b6978eae62 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Fri, 30 Aug 2024 18:51:22 +0200 Subject: [PATCH 186/275] Refactor --- auth/assets/custom-icons/_data/custom-icons.json | 1 - 1 file changed, 1 deletion(-) diff --git a/auth/assets/custom-icons/_data/custom-icons.json b/auth/assets/custom-icons/_data/custom-icons.json index 5c04d71028..5989c5bb00 100644 --- a/auth/assets/custom-icons/_data/custom-icons.json +++ b/auth/assets/custom-icons/_data/custom-icons.json @@ -146,7 +146,6 @@ "slug": "crypto", "altNames": [ "crypto", - "Crypto.com", "Crypto com" ] }, From e16fa2dc3193ecc3d618ba20640ac8e61fa8bd62 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Fri, 30 Aug 2024 18:52:07 +0200 Subject: [PATCH 187/275] Fix typo --- auth/assets/custom-icons/_data/custom-icons.json | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/auth/assets/custom-icons/_data/custom-icons.json b/auth/assets/custom-icons/_data/custom-icons.json index 5989c5bb00..842afc6dab 100644 --- a/auth/assets/custom-icons/_data/custom-icons.json +++ b/auth/assets/custom-icons/_data/custom-icons.json @@ -44,7 +44,7 @@ "title": "bitget" }, { - "titile": "bitget wallet", + "title": "bitget wallet", "slug": "bitget_wallet" }, { @@ -257,7 +257,7 @@ "title": "IceDrive" }, { - "titile": "Infomaniak" + "title": "Infomaniak" }, { "title": "ING" @@ -431,7 +431,7 @@ "title": "Odido" }, { - "titile": "OpenObserve", + "title": "OpenObserve", "slug": "open_observe", "altNames": [ "openobserve.ai", @@ -637,8 +637,7 @@ "title": "Upstox" }, { - "titile": "Vikunja", - "slug": "vikunja" + "title": "Vikunja" }, { "title": "Wealthfront" From dca50a4e458f2a5ad59038f1cd6f7d61fdb1c7e2 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Fri, 30 Aug 2024 18:54:08 +0200 Subject: [PATCH 188/275] Refactor --- auth/assets/custom-icons/_data/custom-icons.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/auth/assets/custom-icons/_data/custom-icons.json b/auth/assets/custom-icons/_data/custom-icons.json index 842afc6dab..d1d90ff4f0 100644 --- a/auth/assets/custom-icons/_data/custom-icons.json +++ b/auth/assets/custom-icons/_data/custom-icons.json @@ -131,9 +131,6 @@ { "title": "ConfigCat" }, - { - "title": "ConfigCat" - }, { "title": "Control D", "slug": "controld" From 05bcfdc16e1c3fc18aaf83a5eeafa09c01180ab7 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Fri, 30 Aug 2024 19:17:21 +0200 Subject: [PATCH 189/275] Fix TCPShield icon --- .../custom-icons/_data/custom-icons.json | 3 +- auth/assets/custom-icons/icons/tcpshield.svg | 35 +++++-------------- 2 files changed, 9 insertions(+), 29 deletions(-) diff --git a/auth/assets/custom-icons/_data/custom-icons.json b/auth/assets/custom-icons/_data/custom-icons.json index d1d90ff4f0..dcd03b50e8 100644 --- a/auth/assets/custom-icons/_data/custom-icons.json +++ b/auth/assets/custom-icons/_data/custom-icons.json @@ -566,8 +566,7 @@ "slug": "synology_dsm" }, { - "title": "TCPShield", - "hex": "FFFFFF" + "title": "TCPShield" }, { "title": "Techlore", diff --git a/auth/assets/custom-icons/icons/tcpshield.svg b/auth/assets/custom-icons/icons/tcpshield.svg index 9f6ce24091..6e6914700f 100644 --- a/auth/assets/custom-icons/icons/tcpshield.svg +++ b/auth/assets/custom-icons/icons/tcpshield.svg @@ -1,27 +1,8 @@ - - TCPShield - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + From 0fc0a00f47644cf4e7b7171268eec08afcd624d3 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Fri, 30 Aug 2024 21:25:26 +0200 Subject: [PATCH 190/275] Add Battle.net icon --- auth/assets/custom-icons/_data/custom-icons.json | 8 ++++++++ auth/assets/custom-icons/icons/battlenet.svg | 10 ++++++++++ 2 files changed, 18 insertions(+) create mode 100644 auth/assets/custom-icons/icons/battlenet.svg diff --git a/auth/assets/custom-icons/_data/custom-icons.json b/auth/assets/custom-icons/_data/custom-icons.json index dcd03b50e8..aee0df534c 100644 --- a/auth/assets/custom-icons/_data/custom-icons.json +++ b/auth/assets/custom-icons/_data/custom-icons.json @@ -24,6 +24,14 @@ { "title": "AscendEX" }, + { + "title": "Battle.net", + "slug": "battlenet", + "altNames": [ + "Battle net", + "Blizzard" + ] + }, { "title": "Bethesda", "altNames": [ diff --git a/auth/assets/custom-icons/icons/battlenet.svg b/auth/assets/custom-icons/icons/battlenet.svg new file mode 100644 index 0000000000..023e205622 --- /dev/null +++ b/auth/assets/custom-icons/icons/battlenet.svg @@ -0,0 +1,10 @@ + + + + + + + + + + From 7500fdd380243e65b962643d181acd192f18d94d Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Wed, 28 Aug 2024 04:11:04 +0800 Subject: [PATCH 191/275] Request focus on the search box when clicked the search icon --- auth/lib/ui/home_page.dart | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/auth/lib/ui/home_page.dart b/auth/lib/ui/home_page.dart index 1e17947210..f9c6410d9d 100644 --- a/auth/lib/ui/home_page.dart +++ b/auth/lib/ui/home_page.dart @@ -55,6 +55,9 @@ class _HomePageState extends State { final Logger _logger = Logger("HomePage"); final scaffoldKey = GlobalKey(); + // Used to request focus on the search box when clicked the search icon + late FocusNode searchBoxFocusNode; + final TextEditingController _textController = TextEditingController(); final bool _autoFocusSearch = PreferenceService.instance.shouldAutoFocusOnSearchBar(); @@ -89,6 +92,8 @@ class _HomePageState extends State { setState(() {}); }); _showSearchBox = _autoFocusSearch; + + searchBoxFocusNode = FocusNode(); } void _loadCodes() { @@ -158,6 +163,9 @@ class _HomePageState extends State { _triggerLogoutEvent?.cancel(); _iconsChangedEvent?.cancel(); _textController.removeListener(_applyFilteringAndRefresh); + + searchBoxFocusNode.dispose(); + super.dispose(); } @@ -241,6 +249,7 @@ class _HomePageState extends State { border: InputBorder.none, focusedBorder: InputBorder.none, ), + focusNode: searchBoxFocusNode, ), centerTitle: true, actions: [ @@ -258,6 +267,12 @@ class _HomePageState extends State { _searchText = ""; } else { _searchText = _textController.text; + + // Request focus on the search box + // For Windows only for now. "Platform.isWindows" can be removed if other platforms has been tested. + if (Platform.isWindows) { + searchBoxFocusNode.requestFocus(); + } } _applyFilteringAndRefresh(); }, From a6359f07564296e60a01a1c49d6a93f686cacb2b Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Mon, 2 Sep 2024 13:43:26 +0530 Subject: [PATCH 192/275] Prefer existing clusters when adding --- .../new/photos/services/ml/cluster.ts | 82 ++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/web/packages/new/photos/services/ml/cluster.ts b/web/packages/new/photos/services/ml/cluster.ts index 271cd6d491..6513b9432e 100644 --- a/web/packages/new/photos/services/ml/cluster.ts +++ b/web/packages/new/photos/services/ml/cluster.ts @@ -393,7 +393,8 @@ interface ClusterLinearResult { clusters: EmbeddingCluster[]; } -const clusterLinear = ( +// TODO-Cluster remove me +export const clusterLinear_Direct = ( embeddings: number[][], threshold: number, ): ClusterLinearResult => { @@ -454,3 +455,82 @@ const clusterLinear = ( return { clusters: validClusters }; }; + +const clusterLinear = ( + embeddings: number[][], + threshold: number, +): ClusterLinearResult => { + const clusters: EmbeddingCluster[] = []; + const clusterIndexForEmbeddingIndex = new Map(); + // For each embedding + for (const [i, ei] of embeddings.entries()) { + // If the embedding is already part of a cluster, then skip it. + if (clusterIndexForEmbeddingIndex.get(i)) continue; + + // Find the nearest neighbour from among all the other embeddings. + let nnIndex: number | undefined; + let nnCosineSimilarity = 0; + // Find the nearest cluster from among all the existing clusters. + let nClusterIndex: number | undefined; + let nClusterCosineSimilarity = 0; + for (const [j, ej] of embeddings.entries()) { + // ! This is an O(n^2) loop, be careful when adding more code here. + + // Skip ourselves. + if (i == j) continue; + + // The vectors are already normalized, so we can directly use their + // dot product as their cosine similarity. + const csim = dotProduct(ei, ej); + if (csim > threshold) { + if (csim > nnCosineSimilarity) { + nnIndex = j; + nnCosineSimilarity = csim; + } + if (csim > nClusterCosineSimilarity) { + const jClusterIndex = clusterIndexForEmbeddingIndex.get(j); + if (jClusterIndex) { + nClusterIndex = jClusterIndex; + nClusterCosineSimilarity = csim; + } + } + } + } + + if (nClusterIndex) { + // Found a neighbouring cluster close enough, add ourselves to that. + + ensure(clusters[nClusterIndex]).push(i); + clusterIndexForEmbeddingIndex.set(i, nClusterIndex); + } else if (nnIndex) { + // Find the cluster the nearest neighbour belongs to, if any. + const nnClusterIndex = clusterIndexForEmbeddingIndex.get(nnIndex); + + if (nnClusterIndex) { + // If the neighbour is already part of a cluster, also add + // ourselves to that cluster. + + ensure(clusters[nnClusterIndex]).push(i); + clusterIndexForEmbeddingIndex.set(i, nnClusterIndex); + } else { + // Otherwise create a new cluster with us and our nearest + // neighbour. + + clusterIndexForEmbeddingIndex.set(i, clusters.length); + clusterIndexForEmbeddingIndex.set(nnIndex, clusters.length); + clusters.push([i, nnIndex]); + } + } else { + // We didn't find a neighbour within the threshold. Create a new + // cluster with only this embedding. + + clusterIndexForEmbeddingIndex.set(i, clusters.length); + clusters.push([i]); + } + } + + // Prune singleton clusters. + const validClusters = clusters.filter((cs) => cs.length > 1); + + return { clusters: validClusters }; +}; From c0ad778c90d9fc5e4bff2711fa3adc2a480ad24d Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Mon, 2 Sep 2024 13:56:00 +0530 Subject: [PATCH 193/275] Add min threshold --- web/apps/photos/src/pages/cluster-debug.tsx | 9 +++++++ .../new/photos/services/ml/cluster.ts | 25 +++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 6337daffd1..d2f921b532 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -112,6 +112,7 @@ const OptionsForm: React.FC = ({ onCluster }) => { method: "linear", minBlur: 10, minScore: 0.8, + minClusterSize: 2, joinThreshold: 0.7, batchSize: 12500, }, @@ -120,6 +121,7 @@ const OptionsForm: React.FC = ({ onCluster }) => { method: values.method, minBlur: toFloat(values.minBlur), minScore: toFloat(values.minScore), + minClusterSize: toFloat(values.minClusterSize), joinThreshold: toFloat(values.joinThreshold), batchSize: toFloat(values.batchSize), }), @@ -162,6 +164,13 @@ const OptionsForm: React.FC = ({ onCluster }) => { size="small" onChange={handleChange} /> + { - const { method, batchSize, minBlur, minScore, joinThreshold } = opts; + const { + method, + batchSize, + minBlur, + minScore, + minClusterSize, + joinThreshold, + } = opts; const t = Date.now(); // A flattened array of faces. @@ -299,7 +307,12 @@ export const clusterFaces = ( } } - const sortedClusters = clusters.sort( + // Prune clusters that are smaller than the threshold. + const validClusters = clusters.filter( + (cs) => cs.faceIDs.length > minClusterSize, + ); + + const sortedClusters = validClusters.sort( (a, b) => b.faceIDs.length - a.faceIDs.length, ); @@ -361,7 +374,7 @@ export const clusterFaces = ( const timeTakenMs = Date.now() - t; log.info( - `Clustered ${faces.length} faces into ${clusters.length} clusters, ${faces.length - clusterIDForFaceID.size} faces remain unclustered (${timeTakenMs} ms)`, + `Clustered ${faces.length} faces into ${sortedClusters.length} clusters, ${faces.length - clusterIDForFaceID.size} faces remain unclustered (${timeTakenMs} ms)`, ); return { @@ -507,11 +520,13 @@ const clusterLinear = ( const nnClusterIndex = clusterIndexForEmbeddingIndex.get(nnIndex); if (nnClusterIndex) { + // TODO-Cluster remove this case. // If the neighbour is already part of a cluster, also add // ourselves to that cluster. - ensure(clusters[nnClusterIndex]).push(i); - clusterIndexForEmbeddingIndex.set(i, nnClusterIndex); + // ensure(clusters[nnClusterIndex]).push(i); + // clusterIndexForEmbeddingIndex.set(i, nnClusterIndex); + throw new Error("We shouldn't have reached here"); } else { // Otherwise create a new cluster with us and our nearest // neighbour. From ab86c5129e5498146b8b8addddb6f990fcbc6a4f Mon Sep 17 00:00:00 2001 From: ashilkn Date: Mon, 2 Sep 2024 14:46:52 +0530 Subject: [PATCH 194/275] [mob][photos] Refactor --- mobile/lib/core/configuration.dart | 9 --------- mobile/lib/ui/viewer/file/file_app_bar.dart | 10 +++++----- .../file/native_video_player_controls/seek_bar.dart | 4 ++-- mobile/lib/ui/viewer/file/video_widget_native.dart | 5 ++--- mobile/lib/utils/local_settings.dart | 9 +++++++++ 5 files changed, 18 insertions(+), 19 deletions(-) diff --git a/mobile/lib/core/configuration.dart b/mobile/lib/core/configuration.dart index 70db6c3d96..16a65d497f 100644 --- a/mobile/lib/core/configuration.dart +++ b/mobile/lib/core/configuration.dart @@ -71,7 +71,6 @@ class Configuration { "has_selected_all_folders_for_backup"; static const anonymousUserIDKey = "anonymous_user_id"; static const endPointKey = "endpoint"; - static const shouldLoopVideoKey = "should_loop_video"; static final _logger = Logger("Configuration"); String? _cachedToken; @@ -662,14 +661,6 @@ class Configuration { await _preferences.setBool(hasSelectedAllFoldersForBackupKey, value); } - Future setShouldLoopVideo(bool value) async { - await _preferences.setBool(shouldLoopVideoKey, value); - } - - bool shouldLoopVideo() { - return _preferences.getBool(shouldLoopVideoKey) ?? true; - } - Future _migrateSecurityStorageToFirstUnlock() async { final hasMigratedSecureStorage = _preferences.getBool(hasMigratedSecureStorageKey) ?? false; diff --git a/mobile/lib/ui/viewer/file/file_app_bar.dart b/mobile/lib/ui/viewer/file/file_app_bar.dart index 8913790766..67b10bb9ad 100644 --- a/mobile/lib/ui/viewer/file/file_app_bar.dart +++ b/mobile/lib/ui/viewer/file/file_app_bar.dart @@ -6,7 +6,6 @@ import "package:flutter_svg/flutter_svg.dart"; import "package:local_auth/local_auth.dart"; import 'package:logging/logging.dart'; import 'package:media_extension/media_extension.dart'; -import "package:photos/core/configuration.dart"; import "package:photos/core/event_bus.dart"; import "package:photos/events/guest_view_event.dart"; import "package:photos/generated/l10n.dart"; @@ -17,6 +16,7 @@ import 'package:photos/models/file/file_type.dart'; import 'package:photos/models/file/trash_file.dart'; import "package:photos/models/metadata/common_keys.dart"; import 'package:photos/models/selected_files.dart'; +import "package:photos/service_locator.dart"; import 'package:photos/services/collections_service.dart'; import 'package:photos/services/hidden_service.dart'; import "package:photos/services/local_authentication_service.dart"; @@ -44,8 +44,8 @@ class FileAppBar extends StatefulWidget { this.height, this.shouldShowActions, { required this.enableFullScreenNotifier, - Key? key, - }) : super(key: key); + super.key, + }); @override FileAppBarState createState() => FileAppBarState(); @@ -56,7 +56,7 @@ class FileAppBarState extends State { final List _actions = []; late final StreamSubscription _guestViewEventSubscription; bool isGuestView = false; - bool shouldLoopVideo = Configuration.instance.shouldLoopVideo(); + bool shouldLoopVideo = localSettings.shouldLoopVideo(); bool _reloadActions = false; @override @@ -390,7 +390,7 @@ class FileAppBarState extends State { } _onToggleLoopVideo() { - Configuration.instance.setShouldLoopVideo(!shouldLoopVideo); + localSettings.setShouldLoopVideo(!shouldLoopVideo); setState(() { _reloadActions = true; shouldLoopVideo = !shouldLoopVideo; diff --git a/mobile/lib/ui/viewer/file/native_video_player_controls/seek_bar.dart b/mobile/lib/ui/viewer/file/native_video_player_controls/seek_bar.dart index f57d772566..f37791d56e 100644 --- a/mobile/lib/ui/viewer/file/native_video_player_controls/seek_bar.dart +++ b/mobile/lib/ui/viewer/file/native_video_player_controls/seek_bar.dart @@ -2,7 +2,7 @@ import "dart:async"; import "package:flutter/material.dart"; import "package:native_video_player/native_video_player.dart"; -import "package:photos/core/configuration.dart"; +import "package:photos/service_locator.dart"; import "package:photos/theme/colors.dart"; import "package:photos/theme/ente_theme.dart"; import "package:photos/utils/debouncer.dart"; @@ -149,7 +149,7 @@ class _SeekBarState extends State with SingleTickerProviderStateMixin { setState(() { _animationController.value = 0; }); - if (!Configuration.instance.shouldLoopVideo()) { + if (!localSettings.shouldLoopVideo()) { return; } } diff --git a/mobile/lib/ui/viewer/file/video_widget_native.dart b/mobile/lib/ui/viewer/file/video_widget_native.dart index 268bdec5e2..4281d405df 100644 --- a/mobile/lib/ui/viewer/file/video_widget_native.dart +++ b/mobile/lib/ui/viewer/file/video_widget_native.dart @@ -4,15 +4,14 @@ import "dart:io"; import "package:flutter/material.dart"; import "package:logging/logging.dart"; import "package:native_video_player/native_video_player.dart"; -import "package:photos/core/configuration.dart"; import "package:photos/core/constants.dart"; import "package:photos/core/event_bus.dart"; import "package:photos/events/guest_view_event.dart"; import "package:photos/events/pause_video_event.dart"; -// import "package:photos/events/pause_video_event.dart"; import "package:photos/generated/l10n.dart"; import "package:photos/models/file/extensions/file_props.dart"; import "package:photos/models/file/file.dart"; +import "package:photos/service_locator.dart"; import "package:photos/services/files_service.dart"; import "package:photos/theme/colors.dart"; import "package:photos/theme/ente_theme.dart"; @@ -348,7 +347,7 @@ class _VideoWidgetNativeState extends State } void _onPlaybackEnded() { - if (Configuration.instance.shouldLoopVideo()) { + if (localSettings.shouldLoopVideo()) { _controller?.play(); } } diff --git a/mobile/lib/utils/local_settings.dart b/mobile/lib/utils/local_settings.dart index cdf0b6ef63..cc657c369e 100644 --- a/mobile/lib/utils/local_settings.dart +++ b/mobile/lib/utils/local_settings.dart @@ -14,6 +14,7 @@ class LocalSettings { static const kRateUsShownCount = "rate_us_shown_count"; static const kEnableMultiplePart = "ls.enable_multiple_part"; static const kRateUsPromptThreshold = 2; + static const shouldLoopVideoKey = "video.should_loop"; final SharedPreferences _prefs; @@ -82,4 +83,12 @@ class LocalSettings { await _prefs.setBool("remoteFetchEnabled", !remoteFetchEnabled); } //#endregion + + Future setShouldLoopVideo(bool value) async { + await _prefs.setBool(shouldLoopVideoKey, value); + } + + bool shouldLoopVideo() { + return _prefs.getBool(shouldLoopVideoKey) ?? true; + } } From b90a719972c13b479806f66c2101fbc32293a88c Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Mon, 2 Sep 2024 11:24:57 +0200 Subject: [PATCH 195/275] [mob][photos] Cleaner indication of isolate logging --- mobile/lib/core/error-reporting/isolate_logging.dart | 2 +- mobile/lib/core/error-reporting/super_logging.dart | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mobile/lib/core/error-reporting/isolate_logging.dart b/mobile/lib/core/error-reporting/isolate_logging.dart index 0d686178f8..5521e0748d 100644 --- a/mobile/lib/core/error-reporting/isolate_logging.dart +++ b/mobile/lib/core/error-reporting/isolate_logging.dart @@ -28,7 +28,7 @@ class IsolateLogger { final Queue fileQueueEntries = Queue(); Future onLogRecordInIsolate(LogRecord rec) async { - final str = "[ISOLATE]" + rec.toPrettyString(); + final str = rec.toPrettyString(null, true); // write to stdout SuperLogging.printLog(str); diff --git a/mobile/lib/core/error-reporting/super_logging.dart b/mobile/lib/core/error-reporting/super_logging.dart index f146b1b14c..c71cea8254 100644 --- a/mobile/lib/core/error-reporting/super_logging.dart +++ b/mobile/lib/core/error-reporting/super_logging.dart @@ -38,8 +38,9 @@ extension SuperString on String { } extension SuperLogRecord on LogRecord { - String toPrettyString([String? extraLines]) { - final header = "[$loggerName] [$level] [$time]"; + String toPrettyString([String? extraLines, bool inIsolate = false]) { + final header = + "[$loggerName${inIsolate ? " (in isolate)" : ""}] [$level] [$time]"; var msg = "$header $message"; From dcac2332965bbcb0f7dd99b156158761dc7364a9 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Mon, 2 Sep 2024 11:50:06 +0200 Subject: [PATCH 196/275] [mob][photos] refactor --- .../lib/core/error-reporting/isolate_logging.dart | 4 ++-- .../services/machine_learning/ml_computer.dart | 15 ++++++++------- mobile/lib/ui/settings/ml/ml_user_dev_screen.dart | 4 ++-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/mobile/lib/core/error-reporting/isolate_logging.dart b/mobile/lib/core/error-reporting/isolate_logging.dart index 5521e0748d..5ac74b6303 100644 --- a/mobile/lib/core/error-reporting/isolate_logging.dart +++ b/mobile/lib/core/error-reporting/isolate_logging.dart @@ -49,9 +49,9 @@ class IsolateLogger { } /// WARNING: only call this from the main thread - static void handLogStringsToMainLogger(Queue logs) { + static void handLogStringsToMainLogger(List logs) { while (logs.isNotEmpty) { - final logString = logs.removeFirst(); + final logString = logs.removeAt(0); final log = IsolateLogString.fromJsonString(logString); SuperLogging.saveLogString(log.logString, log.error); } diff --git a/mobile/lib/services/machine_learning/ml_computer.dart b/mobile/lib/services/machine_learning/ml_computer.dart index f027208758..f0e01d4c7d 100644 --- a/mobile/lib/services/machine_learning/ml_computer.dart +++ b/mobile/lib/services/machine_learning/ml_computer.dart @@ -114,8 +114,8 @@ class MLComputer { logger.info("XXX logging from isolate is working!!!"); final Queue logStrings = isolateLogger.getLogStringsAndClear(); - final test = [List.from(logStrings)]; - sendPort.send(test); + final logs = List.from(logStrings); + sendPort.send({"data": true, "logs": logs}); break; } } catch (e, stackTrace) { @@ -233,16 +233,17 @@ class MLComputer { }); } - Future testLogging() async { + Future testLogging() async { try { - final test = await _runInIsolate( + final result = await _runInIsolate( ( MLComputerOperation.testLogging, {}, ), - ) as List>; - IsolateLogger.handLogStringsToMainLogger(Queue.from(test[0])); - return; + ) as Map; + final logs = result['logs'] as List; + IsolateLogger.handLogStringsToMainLogger(logs); + return result['data'] as bool; } catch (e, s) { _logger.severe("XXX Could not test logging in isolate", e, s); rethrow; diff --git a/mobile/lib/ui/settings/ml/ml_user_dev_screen.dart b/mobile/lib/ui/settings/ml/ml_user_dev_screen.dart index 7c4d808592..1f75c95d5b 100644 --- a/mobile/lib/ui/settings/ml/ml_user_dev_screen.dart +++ b/mobile/lib/ui/settings/ml/ml_user_dev_screen.dart @@ -62,8 +62,8 @@ class MLUserDeveloperOptions extends StatelessWidget { buttonType: ButtonType.neutral, labelText: "Log something in isolate", onTap: () async { - await MLComputer.instance.testLogging(); - showShortToast(context, "Done"); + final boolean = await MLComputer.instance.testLogging(); + showShortToast(context, "Done: $boolean"); }, ), const SafeArea( From 5fef369e91c2ff54b999a550ed5a5ce21b0bd26c Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Mon, 2 Sep 2024 14:47:29 +0530 Subject: [PATCH 197/275] [mob] Surface backup status --- .../settings/backup/backup_section_widget.dart | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/mobile/lib/ui/settings/backup/backup_section_widget.dart b/mobile/lib/ui/settings/backup/backup_section_widget.dart index 183b79b203..56ef0e02f7 100644 --- a/mobile/lib/ui/settings/backup/backup_section_widget.dart +++ b/mobile/lib/ui/settings/backup/backup_section_widget.dart @@ -6,6 +6,7 @@ import 'package:photos/ui/components/expandable_menu_item_widget.dart'; import 'package:photos/ui/components/menu_item_widget/menu_item_widget.dart'; import 'package:photos/ui/settings/backup/backup_folder_selection_page.dart'; import 'package:photos/ui/settings/backup/backup_settings_screen.dart'; +import "package:photos/ui/settings/backup/backup_status_screen.dart"; import "package:photos/ui/settings/backup/free_space_options.dart"; import 'package:photos/ui/settings/common_settings.dart'; import 'package:photos/utils/navigation_util.dart'; @@ -47,6 +48,21 @@ class BackupSectionWidgetState extends State { }, ), sectionOptionSpacing, + MenuItemWidget( + captionedTextWidget: CaptionedTextWidget( + title: S.of(context).backupStatus, + ), + pressedColor: getEnteColorScheme(context).fillFaint, + trailingIcon: Icons.chevron_right_outlined, + trailingIconIsMuted: true, + onTap: () async { + await routeToPage( + context, + const BackupStatusScreen(), + ); + }, + ), + sectionOptionSpacing, MenuItemWidget( captionedTextWidget: CaptionedTextWidget( title: S.of(context).backupSettings, From 28e691122fa5ffcd5c6960c72237c5c641a280d2 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Mon, 2 Sep 2024 15:20:57 +0530 Subject: [PATCH 198/275] [mob] Fix translations --- mobile/lib/generated/intl/messages_all.dart | 4 + mobile/lib/generated/intl/messages_da.dart | 2 - mobile/lib/generated/intl/messages_de.dart | 2 +- mobile/lib/generated/intl/messages_en.dart | 5 + mobile/lib/generated/intl/messages_es.dart | 2 - mobile/lib/generated/intl/messages_fa.dart | 2 - mobile/lib/generated/intl/messages_fr.dart | 41 ++++- mobile/lib/generated/intl/messages_he.dart | 8 +- mobile/lib/generated/intl/messages_hi.dart | 2 - mobile/lib/generated/intl/messages_id.dart | 74 +++++++- mobile/lib/generated/intl/messages_it.dart | 193 +++++++++++++++++++- mobile/lib/generated/intl/messages_nl.dart | 9 +- mobile/lib/generated/intl/messages_no.dart | 4 +- mobile/lib/generated/intl/messages_pl.dart | 6 +- mobile/lib/generated/intl/messages_pt.dart | 6 +- mobile/lib/generated/intl/messages_ru.dart | 39 +++- mobile/lib/generated/intl/messages_sv.dart | 3 +- mobile/lib/generated/intl/messages_ta.dart | 53 ++++++ mobile/lib/generated/intl/messages_th.dart | 2 - mobile/lib/generated/intl/messages_tr.dart | 2 - mobile/lib/generated/intl/messages_zh.dart | 5 +- mobile/lib/generated/l10n.dart | 21 +++ mobile/lib/l10n/intl_en.arb | 2 + mobile/lib/l10n/intl_he.arb | 7 +- mobile/lib/l10n/intl_no.arb | 5 +- mobile/lib/l10n/intl_sv.arb | 2 +- 26 files changed, 455 insertions(+), 46 deletions(-) create mode 100644 mobile/lib/generated/intl/messages_ta.dart diff --git a/mobile/lib/generated/intl/messages_all.dart b/mobile/lib/generated/intl/messages_all.dart index fee2ce02b3..3d9620100b 100644 --- a/mobile/lib/generated/intl/messages_all.dart +++ b/mobile/lib/generated/intl/messages_all.dart @@ -42,6 +42,7 @@ import 'messages_pl.dart' as messages_pl; import 'messages_pt.dart' as messages_pt; import 'messages_ru.dart' as messages_ru; import 'messages_sv.dart' as messages_sv; +import 'messages_ta.dart' as messages_ta; import 'messages_te.dart' as messages_te; import 'messages_th.dart' as messages_th; import 'messages_ti.dart' as messages_ti; @@ -76,6 +77,7 @@ Map _deferredLibraries = { 'pt': () => new SynchronousFuture(null), 'ru': () => new SynchronousFuture(null), 'sv': () => new SynchronousFuture(null), + 'ta': () => new SynchronousFuture(null), 'te': () => new SynchronousFuture(null), 'th': () => new SynchronousFuture(null), 'ti': () => new SynchronousFuture(null), @@ -137,6 +139,8 @@ MessageLookupByLibrary? _findExact(String localeName) { return messages_ru.messages; case 'sv': return messages_sv.messages; + case 'ta': + return messages_ta.messages; case 'te': return messages_te.messages; case 'th': diff --git a/mobile/lib/generated/intl/messages_da.dart b/mobile/lib/generated/intl/messages_da.dart index f243887b61..2209983e4e 100644 --- a/mobile/lib/generated/intl/messages_da.dart +++ b/mobile/lib/generated/intl/messages_da.dart @@ -43,8 +43,6 @@ class MessageLookup extends MessageLookupByLibrary { "cancel": MessageLookupByLibrary.simpleMessage("Annuller"), "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage("Bekræft Sletning Af Konto"), - "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "Ja, jeg ønsker at slette denne konto og alle dens data permanent."), "confirmPassword": MessageLookupByLibrary.simpleMessage("Bekræft adgangskode"), "copypasteThisCodentoYourAuthenticatorApp": diff --git a/mobile/lib/generated/intl/messages_de.dart b/mobile/lib/generated/intl/messages_de.dart index 90dc0b7f0d..4004a561cd 100644 --- a/mobile/lib/generated/intl/messages_de.dart +++ b/mobile/lib/generated/intl/messages_de.dart @@ -518,7 +518,7 @@ class MessageLookup extends MessageLookupByLibrary { "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage("Kontolöschung bestätigen"), "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "Ja, ich möchte dieses Konto und alle enthaltenen Daten endgültig und unwiderruflich löschen."), + "Ja, ich möchte dieses Konto und alle enthaltenen Daten über alle Apps endgültig und unwiderruflich löschen."), "confirmPassword": MessageLookupByLibrary.simpleMessage("Passwort wiederholen"), "confirmPlanChange": diff --git a/mobile/lib/generated/intl/messages_en.dart b/mobile/lib/generated/intl/messages_en.dart index 9eaa0d5e5e..8ac868cb94 100644 --- a/mobile/lib/generated/intl/messages_en.dart +++ b/mobile/lib/generated/intl/messages_en.dart @@ -206,6 +206,8 @@ class MessageLookup extends MessageLookupByLibrary { static String m66(count) => "${Intl.plural(count, zero: '', one: '1 day', other: '${count} days')}"; + static String m72(count) => "Preserving ${count} memories..."; + static String m67(endDate) => "Valid till ${endDate}"; static String m68(email) => "Verify ${email}"; @@ -1607,6 +1609,9 @@ class MessageLookup extends MessageLookupByLibrary { "upgrade": MessageLookupByLibrary.simpleMessage("Upgrade"), "uploadingFilesToAlbum": MessageLookupByLibrary.simpleMessage("Uploading files to album..."), + "uploadingMultipleMemories": m72, + "uploadingSingleMemory": + MessageLookupByLibrary.simpleMessage("Preserving 1 memory..."), "upto50OffUntil4thDec": MessageLookupByLibrary.simpleMessage( "Upto 50% off, until 4th Dec."), "usableReferralStorageInfo": MessageLookupByLibrary.simpleMessage( diff --git a/mobile/lib/generated/intl/messages_es.dart b/mobile/lib/generated/intl/messages_es.dart index 479c1538a0..5395aaf930 100644 --- a/mobile/lib/generated/intl/messages_es.dart +++ b/mobile/lib/generated/intl/messages_es.dart @@ -492,8 +492,6 @@ class MessageLookup extends MessageLookupByLibrary { "¿Estás seguro de que deseas deshabilitar la autenticación de doble factor?"), "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage("Confirmar borrado de cuenta"), - "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "Sí, quiero eliminar permanentemente esta cuenta y todos sus datos."), "confirmPassword": MessageLookupByLibrary.simpleMessage("Confirmar contraseña"), "confirmPlanChange": MessageLookupByLibrary.simpleMessage( diff --git a/mobile/lib/generated/intl/messages_fa.dart b/mobile/lib/generated/intl/messages_fa.dart index b6650a943a..0332b402f3 100644 --- a/mobile/lib/generated/intl/messages_fa.dart +++ b/mobile/lib/generated/intl/messages_fa.dart @@ -113,8 +113,6 @@ class MessageLookup extends MessageLookupByLibrary { "confirm": MessageLookupByLibrary.simpleMessage("تایید"), "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage("تایید حذف حساب کاربری"), - "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "بله، من می‌خواهم برای همیشه این حساب کاربری و تمام اطلاعات آن را حذف کنم."), "confirmPassword": MessageLookupByLibrary.simpleMessage("تایید رمز عبور"), "confirmRecoveryKey": diff --git a/mobile/lib/generated/intl/messages_fr.dart b/mobile/lib/generated/intl/messages_fr.dart index af1060e22b..eb1159068d 100644 --- a/mobile/lib/generated/intl/messages_fr.dart +++ b/mobile/lib/generated/intl/messages_fr.dart @@ -128,6 +128,11 @@ class MessageLookup extends MessageLookupByLibrary { static String m38(albumName) => "Déplacé avec succès vers ${albumName}"; + static String m39(name) => "Pas ${name}?"; + + static String m40(familyAdminEmail) => + "Veuillez contacter ${familyAdminEmail} pour modifier votre code."; + static String m41(passwordStrengthValue) => "Sécurité du mot de passe : ${passwordStrengthValue}"; @@ -310,6 +315,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Authentification requise"), "appLock": MessageLookupByLibrary.simpleMessage( "Verrouillage d\'applications"), + "appLockDescriptions": MessageLookupByLibrary.simpleMessage( + "Choisissez entre l\'écran de verrouillage par défaut de votre appareil et un écran de verrouillage personnalisé avec un code PIN ou un mot de passe."), "appVersion": m10, "appleId": MessageLookupByLibrary.simpleMessage("Apple ID"), "apply": MessageLookupByLibrary.simpleMessage("Appliquer"), @@ -358,6 +365,8 @@ class MessageLookup extends MessageLookupByLibrary { "Veuillez vous authentifier pour configurer l\'authentification à deux facteurs"), "authToInitiateAccountDeletion": MessageLookupByLibrary.simpleMessage( "Veuillez vous authentifier pour débuter la suppression du compte"), + "authToViewPasskey": MessageLookupByLibrary.simpleMessage( + "Veuillez vous authentifier pour afficher votre clé de récupération"), "authToViewYourActiveSessions": MessageLookupByLibrary.simpleMessage( "Veuillez vous authentifier pour voir vos sessions actives"), "authToViewYourHiddenFiles": MessageLookupByLibrary.simpleMessage( @@ -516,7 +525,7 @@ class MessageLookup extends MessageLookupByLibrary { "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage( "Confirmer la suppression du compte"), "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "Oui, je veux supprimer définitivement ce compte et toutes ses données."), + "Oui, je veux supprimer définitivement ce compte et ses données dans toutes les applications."), "confirmPassword": MessageLookupByLibrary.simpleMessage("Confirmer le mot de passe"), "confirmPlanChange": MessageLookupByLibrary.simpleMessage( @@ -572,6 +581,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Création du lien..."), "criticalUpdateAvailable": MessageLookupByLibrary.simpleMessage( "Mise à jour critique disponible"), + "crop": MessageLookupByLibrary.simpleMessage("Rogner"), "currentUsageIs": MessageLookupByLibrary.simpleMessage( "L\'utilisation actuelle est "), "custom": MessageLookupByLibrary.simpleMessage("Personnaliser"), @@ -708,9 +718,13 @@ class MessageLookup extends MessageLookupByLibrary { "empty": MessageLookupByLibrary.simpleMessage("Vider"), "emptyTrash": MessageLookupByLibrary.simpleMessage("Vider la corbeille ?"), + "enable": MessageLookupByLibrary.simpleMessage("Activer"), + "enableMLIndexingDesc": MessageLookupByLibrary.simpleMessage( + "Ente prend en charge l\'apprentissage automatique sur l\'appareil pour la reconnaissance faciale, la recherche magique et d\'autres fonctionnalités de recherche avancée"), "enableMaps": MessageLookupByLibrary.simpleMessage("Activer la carte"), "enableMapsDesc": MessageLookupByLibrary.simpleMessage( "Vos photos seront affichées sur une carte du monde.\n\nCette carte est hébergée par Open Street Map, et les emplacements exacts de vos photos ne sont jamais partagés.\n\nVous pouvez désactiver cette fonction à tout moment dans les Paramètres."), + "enabled": MessageLookupByLibrary.simpleMessage("Activé"), "encryptingBackup": MessageLookupByLibrary.simpleMessage( "Chiffrement de la sauvegarde..."), "encryption": MessageLookupByLibrary.simpleMessage("Chiffrement"), @@ -852,6 +866,9 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Accorder la permission"), "groupNearbyPhotos": MessageLookupByLibrary.simpleMessage( "Grouper les photos à proximité"), + "guestView": MessageLookupByLibrary.simpleMessage("Vue invité"), + "guestViewEnablePreSteps": MessageLookupByLibrary.simpleMessage( + "Pour activer la vue invité, veuillez configurer le code d\'accès de l\'appareil ou le verrouillage de l\'écran dans les paramètres de votre système."), "hearUsExplanation": MessageLookupByLibrary.simpleMessage( "Nous ne suivons pas les installations d\'applications. Il serait utile que vous nous disiez comment vous nous avez trouvés !"), "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( @@ -1015,6 +1032,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Apprentissage automatique"), "magicSearch": MessageLookupByLibrary.simpleMessage("Recherche magique"), + "magicSearchHint": MessageLookupByLibrary.simpleMessage( + "La recherche magique permet de rechercher des photos par leur contenu, par exemple \'fleur\', \'voiture rouge\', \'documents d\'identité\'"), "manage": MessageLookupByLibrary.simpleMessage("Gérer"), "manageDeviceStorage": MessageLookupByLibrary.simpleMessage( "Gérer le stockage de l\'appareil"), @@ -1032,6 +1051,18 @@ class MessageLookup extends MessageLookupByLibrary { "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), "memoryCount": m0, "merchandise": MessageLookupByLibrary.simpleMessage("Marchandise"), + "mlConsent": MessageLookupByLibrary.simpleMessage( + "Activer l\'apprentissage automatique"), + "mlConsentConfirmation": MessageLookupByLibrary.simpleMessage( + "Je comprends, et souhaite activer l\'apprentissage automatique"), + "mlConsentDescription": MessageLookupByLibrary.simpleMessage( + "Si vous activez l\'apprentissage automatique, Ente extraira des informations comme la géométrie des visages, incluant les photos partagées avec vous. \nCela se fera sur votre appareil, avec un cryptage de bout-en-bout de toutes les données biométriques générées."), + "mlConsentPrivacy": MessageLookupByLibrary.simpleMessage( + "Veuillez cliquer ici pour plus de détails sur cette fonctionnalité dans notre politique de confidentialité"), + "mlConsentTitle": MessageLookupByLibrary.simpleMessage( + "Activer l\'apprentissage automatique ?"), + "mlIndexingDescription": MessageLookupByLibrary.simpleMessage( + "Veuillez noter que l\'apprentissage automatique entraînera une augmentation de l\'utilisation de la bande passante et de la batterie, jusqu\'à ce que tous les éléments soient indexés. \nEnvisagez d\'utiliser l\'application de bureau pour une indexation plus rapide, tous les résultats seront automatiquement synchronisés."), "mobileWebDesktop": MessageLookupByLibrary.simpleMessage("Mobile, Web, Ordinateur"), "moderateStrength": MessageLookupByLibrary.simpleMessage("Moyen"), @@ -1040,6 +1071,7 @@ class MessageLookup extends MessageLookupByLibrary { "Modifiez votre requête, ou essayez de rechercher"), "moments": MessageLookupByLibrary.simpleMessage("Souvenirs"), "monthly": MessageLookupByLibrary.simpleMessage("Mensuel"), + "moreDetails": MessageLookupByLibrary.simpleMessage("Plus de détails"), "moveItem": m37, "moveToAlbum": MessageLookupByLibrary.simpleMessage("Déplacer vers l\'album"), @@ -1093,6 +1125,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Aucun résultat trouvé"), "noSystemLockFound": MessageLookupByLibrary.simpleMessage("Aucun verrou système trouvé"), + "notPersonLabel": m39, "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( "Rien n\'a encore été partagé avec vous"), "nothingToSeeHere": MessageLookupByLibrary.simpleMessage( @@ -1102,6 +1135,7 @@ class MessageLookup extends MessageLookupByLibrary { "onDevice": MessageLookupByLibrary.simpleMessage("Sur l\'appareil"), "onEnte": MessageLookupByLibrary.simpleMessage( "Sur ente"), + "onlyFamilyAdminCanChangeCode": m40, "oops": MessageLookupByLibrary.simpleMessage("Oups"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( "Oups, impossible d\'enregistrer les modifications"), @@ -1328,6 +1362,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Restaurer vers l\'album"), "restoringFiles": MessageLookupByLibrary.simpleMessage( "Restauration des fichiers..."), + "resumableUploads": + MessageLookupByLibrary.simpleMessage("Chargements à poursuivre"), "retry": MessageLookupByLibrary.simpleMessage("Réessayer"), "reviewDeduplicateItems": MessageLookupByLibrary.simpleMessage( "Veuillez vérifier et supprimer les éléments que vous croyez dupliqués."), @@ -1626,6 +1662,7 @@ class MessageLookup extends MessageLookupByLibrary { "totalSize": MessageLookupByLibrary.simpleMessage("Taille totale"), "trash": MessageLookupByLibrary.simpleMessage("Corbeille"), "trashDaysLeft": m66, + "trim": MessageLookupByLibrary.simpleMessage("Recadrer"), "tryAgain": MessageLookupByLibrary.simpleMessage("Réessayer"), "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( "Activez la sauvegarde pour charger automatiquement sur Ente les fichiers ajoutés à ce dossier de l\'appareil."), @@ -1718,6 +1755,8 @@ class MessageLookup extends MessageLookupByLibrary { "Visualiser toutes les données EXIF"), "viewLargeFiles": MessageLookupByLibrary.simpleMessage("Fichiers volumineux"), + "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( + "Afficher les fichiers qui consomment le plus de stockage."), "viewLogs": MessageLookupByLibrary.simpleMessage("Afficher les journaux"), "viewRecoveryKey": diff --git a/mobile/lib/generated/intl/messages_he.dart b/mobile/lib/generated/intl/messages_he.dart index e27bbe712b..8b792cdcdb 100644 --- a/mobile/lib/generated/intl/messages_he.dart +++ b/mobile/lib/generated/intl/messages_he.dart @@ -24,7 +24,7 @@ class MessageLookup extends MessageLookupByLibrary { "${Intl.plural(count, one: 'הוסף פריט', two: 'הוסף פריטים', many: 'הוסף פריטים', other: 'הוסף פריטים')}"; static String m9(count) => - "${Intl.plural(count, zero: 'אין משתתפים', one: '1 משתתף', two: '${count} משתתפים', many: '${count} משתתפים', other: '${count} משתתפים')}"; + "${Intl.plural(count, zero: 'אין משתתפים', one: '1 משתתף', two: '2 משתתפים', other: '${count} משתתפים')}"; static String m12(paymentProvider) => "אנא בטל את המנוי הקיים מ-${paymentProvider} קודם"; @@ -46,7 +46,7 @@ class MessageLookup extends MessageLookupByLibrary { "אנא צור איתנו קשר ב-support@ente.io על מנת לנהל את המנוי ${provider}."; static String m19(count) => - "${Intl.plural(count, one: 'מחק ${count} פריט', two: 'מחק ${count} פריטים', many: 'מחק ${count} פריטים', other: 'מחק ${count} פריטים')}"; + "${Intl.plural(count, one: 'מחק ${count} פריט', two: 'מחק ${count} פריטים', other: 'מחק ${count} פריטים')}"; static String m20(currentlyDeleting, totalCount) => "מוחק ${currentlyDeleting} / ${totalCount}"; @@ -103,7 +103,7 @@ class MessageLookup extends MessageLookupByLibrary { "היי, תוכל לוודא שזה מזהה האימות שלך של ente.io: ${verificationID}"; static String m54(numberOfPeople) => - "${Intl.plural(numberOfPeople, zero: 'שתף עם אנשים ספציפיים', one: 'שותף עם איש 1', two: 'שותף עם ${numberOfPeople} אנשים', many: 'שותף עם ${numberOfPeople} אנשים', other: 'שותף עם ${numberOfPeople} אנשים')}"; + "${Intl.plural(numberOfPeople, zero: 'שתף עם אנשים ספציפיים', one: 'שותף עם איש 1', two: 'שותף עם 2 אנשים', other: 'שותף עם ${numberOfPeople} אנשים')}"; static String m55(emailIDs) => "הושתף ע\"י ${emailIDs}"; @@ -295,8 +295,6 @@ class MessageLookup extends MessageLookupByLibrary { "האם אתה בטוח שאתה רוצה להשבית את האימות הדו-גורמי?"), "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage("אשר את מחיקת החשבון"), - "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "כן, אני רוצה למחוק לצמיתות את החשבון הזה וכל המידע שלו."), "confirmPassword": MessageLookupByLibrary.simpleMessage("אמת סיסמא"), "confirmPlanChange": MessageLookupByLibrary.simpleMessage("אשר שינוי תוכנית"), diff --git a/mobile/lib/generated/intl/messages_hi.dart b/mobile/lib/generated/intl/messages_hi.dart index ce390ea7e0..ff4756d8d4 100644 --- a/mobile/lib/generated/intl/messages_hi.dart +++ b/mobile/lib/generated/intl/messages_hi.dart @@ -30,8 +30,6 @@ class MessageLookup extends MessageLookupByLibrary { "cancel": MessageLookupByLibrary.simpleMessage("रद्द करें"), "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage( "अकाउंट डिलीट करने की पुष्टि करें"), - "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "हां, मैं इस अकाउंट और इसके सभी डेटा को स्थायी रूप से हटाना चाहता/चाहती हूं।"), "confirmPassword": MessageLookupByLibrary.simpleMessage("पासवर्ड की पुष्टि करें"), "createAccount": MessageLookupByLibrary.simpleMessage("अकाउंट बनायें"), diff --git a/mobile/lib/generated/intl/messages_id.dart b/mobile/lib/generated/intl/messages_id.dart index 3d0cee4c14..ad25710471 100644 --- a/mobile/lib/generated/intl/messages_id.dart +++ b/mobile/lib/generated/intl/messages_id.dart @@ -25,6 +25,9 @@ class MessageLookup extends MessageLookupByLibrary { static String m4(count) => "${Intl.plural(count, other: 'Tambahkan item')}"; + static String m5(storageAmount, endDate) => + "Add-on ${storageAmount} kamu berlaku sampai ${endDate}"; + static String m7(emailOrName) => "Ditambahkan oleh ${emailOrName}"; static String m8(albumName) => "Berhasil ditambahkan ke ${albumName}"; @@ -37,6 +40,9 @@ class MessageLookup extends MessageLookupByLibrary { static String m11(freeAmount, storageUnit) => "${freeAmount} ${storageUnit} tersedia"; + static String m12(paymentProvider) => + "Harap batalkan langganan kamu dari ${paymentProvider} terlebih dahulu"; + static String m13(user) => "${user} tidak akan dapat menambahkan foto lagi di album ini\n\nMereka masih dapat menghapus foto yang sudah ada yang ditambahkan oleh mereka"; @@ -117,6 +123,9 @@ class MessageLookup extends MessageLookupByLibrary { static String m41(passwordStrengthValue) => "Keamanan sandi: ${passwordStrengthValue}"; + static String m42(providerName) => + "Harap hubungi dukungan ${providerName} jika kamu dikenai biaya"; + static String m43(endDate) => "Percobaan gratis berlaku hingga ${endDate}.\nKamu dapat memilih paket berbayar setelahnya."; @@ -201,6 +210,7 @@ class MessageLookup extends MessageLookupByLibrary { static Map _notInlinedMessages(_) => { "aNewVersionOfEnteIsAvailable": MessageLookupByLibrary.simpleMessage( "Versi baru dari Ente telah tersedia."), + "about": MessageLookupByLibrary.simpleMessage("Tentang"), "account": MessageLookupByLibrary.simpleMessage("Akun"), "accountWelcomeBack": MessageLookupByLibrary.simpleMessage("Selamat datang kembali!"), @@ -219,6 +229,7 @@ class MessageLookup extends MessageLookupByLibrary { "addLocation": MessageLookupByLibrary.simpleMessage("Tambah tempat"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Tambah"), "addMore": MessageLookupByLibrary.simpleMessage("Tambah lagi"), + "addOnValidTill": m5, "addPhotos": MessageLookupByLibrary.simpleMessage("Tambah foto"), "addSelected": MessageLookupByLibrary.simpleMessage("Tambahkan yang dipilih"), @@ -275,6 +286,8 @@ class MessageLookup extends MessageLookupByLibrary { "appleId": MessageLookupByLibrary.simpleMessage("ID Apple"), "apply": MessageLookupByLibrary.simpleMessage("Terapkan"), "applyCodeTitle": MessageLookupByLibrary.simpleMessage("Terapkan kode"), + "appstoreSubscription": + MessageLookupByLibrary.simpleMessage("Langganan AppStore"), "archive": MessageLookupByLibrary.simpleMessage("Arsip"), "archiveAlbum": MessageLookupByLibrary.simpleMessage("Arsipkan album"), "archiving": MessageLookupByLibrary.simpleMessage("Mengarsipkan..."), @@ -301,6 +314,8 @@ class MessageLookup extends MessageLookupByLibrary { "authToChangeEmailVerificationSetting": MessageLookupByLibrary.simpleMessage( "Harap autentikasi untuk mengatur verifikasi email"), + "authToChangeLockscreenSetting": MessageLookupByLibrary.simpleMessage( + "Lakukan autentikasi untuk mengubah pengaturan kunci layar"), "authToChangeYourEmail": MessageLookupByLibrary.simpleMessage( "Harap autentikasi untuk mengubah email kamu"), "authToChangeYourPassword": MessageLookupByLibrary.simpleMessage( @@ -343,6 +358,10 @@ class MessageLookup extends MessageLookupByLibrary { "Cadangkan dengan data seluler"), "backupSettings": MessageLookupByLibrary.simpleMessage("Pengaturan pencadangan"), + "backupStatus": + MessageLookupByLibrary.simpleMessage("Status pencadangan"), + "backupStatusDescription": MessageLookupByLibrary.simpleMessage( + "Item yang sudah dicadangkan akan terlihat di sini"), "backupVideos": MessageLookupByLibrary.simpleMessage("Cadangkan video"), "blackFridaySale": MessageLookupByLibrary.simpleMessage("Penawaran Black Friday"), @@ -352,9 +371,12 @@ class MessageLookup extends MessageLookupByLibrary { "canOnlyRemoveFilesOwnedByYou": MessageLookupByLibrary.simpleMessage( "Hanya dapat menghapus berkas yang dimiliki oleh mu"), "cancel": MessageLookupByLibrary.simpleMessage("Batal"), + "cancelOtherSubscription": m12, "cancelSubscription": MessageLookupByLibrary.simpleMessage("Batalkan langganan"), "cannotAddMorePhotosAfterBecomingViewer": m13, + "cannotDeleteSharedFiles": MessageLookupByLibrary.simpleMessage( + "Tidak dapat menghapus file berbagi"), "castIPMismatchBody": MessageLookupByLibrary.simpleMessage( "Harap pastikan kamu berada pada jaringan yang sama dengan TV-nya."), "castIPMismatchTitle": @@ -371,8 +393,11 @@ class MessageLookup extends MessageLookupByLibrary { "changePermissions": MessageLookupByLibrary.simpleMessage("Ubah izin?"), "changeYourReferralCode": MessageLookupByLibrary.simpleMessage("Ganti kode rujukan kamu"), + "checkForUpdates": + MessageLookupByLibrary.simpleMessage("Periksa pembaruan"), "checkInboxAndSpamFolder": MessageLookupByLibrary.simpleMessage( "Silakan periksa kotak masuk (serta kotak spam) untuk menyelesaikan verifikasi"), + "checkStatus": MessageLookupByLibrary.simpleMessage("Periksa status"), "checking": MessageLookupByLibrary.simpleMessage("Memeriksa..."), "claimFreeStorage": MessageLookupByLibrary.simpleMessage("Peroleh kuota gratis"), @@ -380,6 +405,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Peroleh lebih banyak!"), "claimed": MessageLookupByLibrary.simpleMessage("Diperoleh"), "claimedStorageSoFar": m14, + "clearIndexes": MessageLookupByLibrary.simpleMessage("Hapus indeks"), "click": MessageLookupByLibrary.simpleMessage("• Click"), "close": MessageLookupByLibrary.simpleMessage("Tutup"), "codeAppliedPageTitle": @@ -409,7 +435,7 @@ class MessageLookup extends MessageLookupByLibrary { "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage("Konfirmasi Penghapusan Akun"), "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "Ya, saya ingin menghapus akun ini dan seluruh data yang terkait secara permanen."), + "Ya, saya ingin menghapus akun ini dan seluruh datanya secara permanen di semua aplikasi."), "confirmPassword": MessageLookupByLibrary.simpleMessage("Konfirmasi sandi"), "confirmPlanChange": @@ -440,6 +466,8 @@ class MessageLookup extends MessageLookupByLibrary { "Kami tidak dapat mencadangkan data kamu.\nKami akan coba lagi nanti."), "couldNotFreeUpSpace": MessageLookupByLibrary.simpleMessage( "Tidak dapat membersihkan ruang"), + "couldNotUpdateSubscription": MessageLookupByLibrary.simpleMessage( + "Tidak dapat memperbarui langganan"), "count": MessageLookupByLibrary.simpleMessage("Jumlah"), "crashReporting": MessageLookupByLibrary.simpleMessage("Pelaporan crash"), @@ -519,6 +547,8 @@ class MessageLookup extends MessageLookupByLibrary { "deviceCodeHint": MessageLookupByLibrary.simpleMessage("Masukkan kode"), "deviceFilesAutoUploading": MessageLookupByLibrary.simpleMessage( "File yang ditambahkan ke album perangkat ini akan diunggah ke Ente secara otomatis."), + "deviceLockExplanation": MessageLookupByLibrary.simpleMessage( + "Nonaktfikan kunci layar perangkat saat Ente berada di latar depan dan ada pencadangan yang sedang berlangsung. Hal ini biasanya tidak diperlukan, namun dapat membantu unggahan dan import awal berkas berkas besar selesai lebih cepat."), "deviceNotFound": MessageLookupByLibrary.simpleMessage("Perangkat tidak ditemukan"), "didYouKnow": MessageLookupByLibrary.simpleMessage("Tahukah kamu?"), @@ -732,6 +762,8 @@ class MessageLookup extends MessageLookupByLibrary { "Proses indeks dijeda, dan akan otomatis dilanjutkan saat perangkat siap."), "insecureDevice": MessageLookupByLibrary.simpleMessage("Perangkat tidak aman"), + "installManually": + MessageLookupByLibrary.simpleMessage("Instal secara manual"), "invalidEmailAddress": MessageLookupByLibrary.simpleMessage("Alamat email tidak sah"), "invalidEndpoint": @@ -802,8 +834,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Memuat fotomu..."), "loadingModel": MessageLookupByLibrary.simpleMessage("Mengunduh model..."), + "localGallery": MessageLookupByLibrary.simpleMessage("Galeri lokal"), "locationName": MessageLookupByLibrary.simpleMessage("Nama tempat"), "lockButtonLabel": MessageLookupByLibrary.simpleMessage("Kunci"), + "lockscreen": MessageLookupByLibrary.simpleMessage("Kunci layar"), "logInLabel": MessageLookupByLibrary.simpleMessage("Masuk akun"), "loggingOut": MessageLookupByLibrary.simpleMessage("Mengeluarkan akun..."), @@ -837,6 +871,7 @@ class MessageLookup extends MessageLookupByLibrary { "mastodon": MessageLookupByLibrary.simpleMessage("Mastodon"), "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), "memoryCount": m0, + "merchandise": MessageLookupByLibrary.simpleMessage("Barang Dagangan"), "mlConsent": MessageLookupByLibrary.simpleMessage("Aktifkan pemelajaran mesin"), "mlConsentConfirmation": MessageLookupByLibrary.simpleMessage( @@ -868,6 +903,7 @@ class MessageLookup extends MessageLookupByLibrary { "Tidak dapat terhubung dengan Ente, harap periksa pengaturan jaringan kamu dan hubungi dukungan jika masalah berlanjut."), "never": MessageLookupByLibrary.simpleMessage("Tidak pernah"), "newAlbum": MessageLookupByLibrary.simpleMessage("Album baru"), + "newToEnte": MessageLookupByLibrary.simpleMessage("Baru di Ente"), "no": MessageLookupByLibrary.simpleMessage("Tidak"), "noAlbumsSharedByYouYet": MessageLookupByLibrary.simpleMessage( "Belum ada album yang kamu bagikan"), @@ -884,6 +920,9 @@ class MessageLookup extends MessageLookupByLibrary { "Tidak ada foto atau video tersembunyi"), "noInternetConnection": MessageLookupByLibrary.simpleMessage("Tidak ada koneksi internet"), + "noPhotosAreBeingBackedUpRightNow": + MessageLookupByLibrary.simpleMessage( + "Tidak ada foto yang sedang dicadangkan sekarang"), "noPhotosFoundHere": MessageLookupByLibrary.simpleMessage("Tidak ada foto di sini"), "noRecoveryKey": MessageLookupByLibrary.simpleMessage( @@ -938,7 +977,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Pembayaran gagal"), "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( "Sayangnya, pembayaranmu gagal. Silakan hubungi tim bantuan agar dapat kami bantu!"), + "paymentFailedTalkToProvider": m42, "pendingItems": MessageLookupByLibrary.simpleMessage("Item menunggu"), + "pendingSync": + MessageLookupByLibrary.simpleMessage("Sinkronisasi yang tertunda"), "people": MessageLookupByLibrary.simpleMessage("Orang"), "peopleUsingYourCode": MessageLookupByLibrary.simpleMessage( "Orang yang telah menggunakan kodemu"), @@ -959,6 +1001,8 @@ class MessageLookup extends MessageLookupByLibrary { "Foto yang telah kamu tambahkan akan dihapus dari album ini"), "playOnTv": MessageLookupByLibrary.simpleMessage("Putar album di TV"), "playStoreFreeTrialValidTill": m43, + "playstoreSubscription": + MessageLookupByLibrary.simpleMessage("Langganan PlayStore"), "pleaseCheckYourInternetConnectionAndTryAgain": MessageLookupByLibrary.simpleMessage( "Silakan periksa koneksi internet kamu, lalu coba lagi."), @@ -1002,6 +1046,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Link publik aktif"), "radius": MessageLookupByLibrary.simpleMessage("Radius"), "rateTheApp": MessageLookupByLibrary.simpleMessage("Nilai app ini"), + "rateUs": MessageLookupByLibrary.simpleMessage("Beri kami nilai"), "rateUsOnStore": m46, "recover": MessageLookupByLibrary.simpleMessage("Pulihkan"), "recoverAccount": MessageLookupByLibrary.simpleMessage("Pulihkan akun"), @@ -1031,8 +1076,15 @@ class MessageLookup extends MessageLookupByLibrary { "referralStep2": MessageLookupByLibrary.simpleMessage( "2. Ia perlu daftar ke paket berbayar"), "referralStep3": m47, + "referrals": MessageLookupByLibrary.simpleMessage("Referensi"), "referralsAreCurrentlyPaused": MessageLookupByLibrary.simpleMessage("Rujukan sedang dijeda"), + "remindToEmptyDeviceTrash": MessageLookupByLibrary.simpleMessage( + "Kosongkan juga “Baru Saja Dihapus” dari “Pengaturan” -> “Penyimpanan” untuk mengklaim ruang yang baru dikosongkan"), + "remindToEmptyEnteTrash": MessageLookupByLibrary.simpleMessage( + "Kosongkan juga \"Sampah\" untuk mendapatkan ruang yang baru dikosongkan"), + "remoteThumbnails": + MessageLookupByLibrary.simpleMessage("Thumbnail jarak jauh"), "remove": MessageLookupByLibrary.simpleMessage("Hapus"), "removeDuplicates": MessageLookupByLibrary.simpleMessage("Hapus duplikat"), @@ -1124,6 +1176,8 @@ class MessageLookup extends MessageLookupByLibrary { "selectItemsToAdd": MessageLookupByLibrary.simpleMessage( "Pilih item untuk ditambahkan"), "selectLanguage": MessageLookupByLibrary.simpleMessage("Pilih Bahasa"), + "selectMorePhotos": + MessageLookupByLibrary.simpleMessage("Pilih lebih banyak foto"), "selectReason": MessageLookupByLibrary.simpleMessage("Pilih alasan"), "selectYourPlan": MessageLookupByLibrary.simpleMessage("Pilih paket kamu"), @@ -1177,6 +1231,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Dibagikan oleh kamu"), "sharedPhotoNotifications": MessageLookupByLibrary.simpleMessage("Foto terbagi baru"), + "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( + "Terima notifikasi apabila seseorang menambahkan foto ke album bersama yang kamu ikuti"), "sharedWith": m55, "sharedWithMe": MessageLookupByLibrary.simpleMessage("Dibagikan dengan saya"), @@ -1275,6 +1331,8 @@ class MessageLookup extends MessageLookupByLibrary { "thankYou": MessageLookupByLibrary.simpleMessage("Terima kasih"), "thankYouForSubscribing": MessageLookupByLibrary.simpleMessage( "Terima kasih telah berlangganan!"), + "theDownloadCouldNotBeCompleted": MessageLookupByLibrary.simpleMessage( + "Unduhan tidak dapat diselesaikan"), "theRecoveryKeyYouEnteredIsIncorrect": MessageLookupByLibrary.simpleMessage( "Kunci pemulihan yang kamu masukkan salah"), @@ -1385,6 +1443,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Lihat seluruh data EXIF"), "viewLargeFiles": MessageLookupByLibrary.simpleMessage("File berukuran besar"), + "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( + "Tampilkan file yang banyak mengkonsumsi ruang penyimpanan."), "viewLogs": MessageLookupByLibrary.simpleMessage("Lihat log"), "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("Lihat kunci pemulihan"), @@ -1395,6 +1455,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Menunggu verifikasi..."), "waitingForWifi": MessageLookupByLibrary.simpleMessage("Menunggu WiFi..."), + "weAreOpenSource": + MessageLookupByLibrary.simpleMessage("Kode kami sumber terbuka!"), "weHaveSendEmailTo": m69, "weakStrength": MessageLookupByLibrary.simpleMessage("Lemah"), "welcomeBack": @@ -1422,6 +1484,8 @@ class MessageLookup extends MessageLookupByLibrary { "youCanManageYourLinksInTheShareTab": MessageLookupByLibrary.simpleMessage( "Kamu bisa atur link yang telah kamu buat di tab berbagi."), + "youCannotDowngradeToThisPlan": MessageLookupByLibrary.simpleMessage( + "Anda tidak dapat turun ke paket ini"), "youCannotShareWithYourself": MessageLookupByLibrary.simpleMessage( "Kamu tidak bisa berbagi dengan dirimu sendiri"), "youDontHaveAnyArchivedItems": MessageLookupByLibrary.simpleMessage( @@ -1430,6 +1494,11 @@ class MessageLookup extends MessageLookupByLibrary { "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage("Akunmu telah dihapus"), "yourMap": MessageLookupByLibrary.simpleMessage("Peta kamu"), + "yourPlanWasSuccessfullyDowngraded": + MessageLookupByLibrary.simpleMessage( + "Paket kamu berhasil di turunkan"), + "yourPlanWasSuccessfullyUpgraded": MessageLookupByLibrary.simpleMessage( + "Paket kamu berhasil ditingkatkan"), "yourPurchaseWasSuccessful": MessageLookupByLibrary.simpleMessage("Pembelianmu berhasil"), "yourStorageDetailsCouldNotBeFetched": @@ -1442,6 +1511,9 @@ class MessageLookup extends MessageLookupByLibrary { "Langgananmu telah berhasil diperbarui"), "yourVerificationCodeHasExpired": MessageLookupByLibrary.simpleMessage( "Kode verifikasi kamu telah kedaluwarsa"), + "youveNoDuplicateFilesThatCanBeCleared": + MessageLookupByLibrary.simpleMessage( + "Kamu tidak memiliki file duplikat yang dapat di hapus"), "zoomOutToSeePhotos": MessageLookupByLibrary.simpleMessage( "Perkecil peta untuk melihat foto lainnya") }; diff --git a/mobile/lib/generated/intl/messages_it.dart b/mobile/lib/generated/intl/messages_it.dart index 782eb147c5..c464296721 100644 --- a/mobile/lib/generated/intl/messages_it.dart +++ b/mobile/lib/generated/intl/messages_it.dart @@ -20,9 +20,18 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'it'; + static String m3(count) => + "${Intl.plural(count, zero: 'Aggiungi collaboratore', one: 'Aggiungi collaboratore', other: 'Aggiungi collaboratori')}"; + static String m4(count) => "${Intl.plural(count, one: 'Aggiungi elemento', other: 'Aggiungi elementi')}"; + static String m5(storageAmount, endDate) => + "Il tuo spazio aggiuntivo di ${storageAmount} è valido fino al ${endDate}"; + + static String m6(count) => + "${Intl.plural(count, zero: 'Aggiungi visualizzatore', one: 'Aggiungi visualizzatore', other: 'Aggiungi visualizzatori')}"; + static String m7(emailOrName) => "Aggiunto da ${emailOrName}"; static String m8(albumName) => "Aggiunto con successo su ${albumName}"; @@ -32,6 +41,9 @@ class MessageLookup extends MessageLookupByLibrary { static String m10(versionValue) => "Versione: ${versionValue}"; + static String m11(freeAmount, storageUnit) => + "${freeAmount} ${storageUnit} liberi"; + static String m12(paymentProvider) => "Annulla prima il tuo abbonamento esistente da ${paymentProvider}"; @@ -74,6 +86,9 @@ class MessageLookup extends MessageLookupByLibrary { static String m25(newEmail) => "Email cambiata in ${newEmail}"; + static String m26(email) => + "${email} non ha un account Ente.\n\nInvia un invito per condividere foto."; + static String m27(count, formattedNumber) => "${Intl.plural(count, one: '1 file', other: '${formattedNumber} file')} di quest\'album sono stati salvati in modo sicuro"; @@ -93,6 +108,9 @@ class MessageLookup extends MessageLookupByLibrary { static String m33(count, formattedSize) => "${Intl.plural(count, one: 'Può essere cancellata per liberare ${formattedSize}', other: 'Possono essere cancellati per liberare ${formattedSize}')}"; + static String m34(currentlyProcessing, totalCount) => + "Elaborazione ${currentlyProcessing} / ${totalCount}"; + static String m35(count) => "${Intl.plural(count, one: '${count} elemento', other: '${count} elementi')}"; @@ -106,12 +124,18 @@ class MessageLookup extends MessageLookupByLibrary { static String m38(albumName) => "Spostato con successo su ${albumName}"; + static String m40(familyAdminEmail) => + "Per favore contatta ${familyAdminEmail} per cambiare il tuo codice."; + static String m41(passwordStrengthValue) => "Sicurezza password: ${passwordStrengthValue}"; static String m42(providerName) => "Si prega di parlare con il supporto di ${providerName} se ti è stato addebitato qualcosa"; + static String m43(endDate) => + "Prova gratuita valida fino al ${endDate}.\nIn seguito potrai scegliere un piano a pagamento."; + static String m44(toEmail) => "Per favore invia un\'email a ${toEmail}"; static String m45(toEmail) => "Invia i log a \n${toEmail}"; @@ -126,6 +150,9 @@ class MessageLookup extends MessageLookupByLibrary { static String m49(endDate) => "Si rinnova il ${endDate}"; + static String m50(count) => + "${Intl.plural(count, one: '${count} risultato trovato', other: '${count} risultati trovati')}"; + static String m1(count) => "${count} selezionati"; static String m51(count, yourCount) => @@ -137,6 +164,9 @@ class MessageLookup extends MessageLookupByLibrary { static String m2(verificationID) => "Hey, puoi confermare che questo è il tuo ID di verifica: ${verificationID} su ente.io"; + static String m53(referralCode, referralStorageInGB) => + "Codice invito Ente: ${referralCode} \n\nInseriscilo in Impostazioni → Generali → Inviti per ottenere ${referralStorageInGB} GB gratis dopo la sottoscrizione a un piano a pagamento\n\nhttps://ente.io"; + static String m54(numberOfPeople) => "${Intl.plural(numberOfPeople, zero: 'Condividi con persone specifiche', one: 'Condividi con una persona', other: 'Condividi con ${numberOfPeople} persone')}"; @@ -145,12 +175,20 @@ class MessageLookup extends MessageLookupByLibrary { static String m56(fileType) => "Questo ${fileType} verrà eliminato dal tuo dispositivo."; + static String m57(fileType) => + "Questo ${fileType} è sia su Ente che sul tuo dispositivo."; + + static String m58(fileType) => "Questo ${fileType} verrà eliminato da Ente."; + static String m59(storageAmountInGB) => "${storageAmountInGB} GB"; static String m60( usedAmount, usedStorageUnit, totalAmount, totalStorageUnit) => "${usedAmount} ${usedStorageUnit} di ${totalAmount} ${totalStorageUnit} utilizzati"; + static String m61(id) => + "Il tuo ${id} è già collegato a un altro account Ente.\nSe desideri utilizzare il tuo ${id} con questo account, per favore contatta il nostro supporto\'\'"; + static String m62(endDate) => "L\'abbonamento verrà cancellato il ${endDate}"; static String m63(completed, total) => @@ -179,6 +217,8 @@ class MessageLookup extends MessageLookupByLibrary { final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { + "aNewVersionOfEnteIsAvailable": MessageLookupByLibrary.simpleMessage( + "Una nuova versione di Ente è disponibile."), "about": MessageLookupByLibrary.simpleMessage("Info"), "account": MessageLookupByLibrary.simpleMessage("Account"), "accountWelcomeBack": @@ -187,10 +227,12 @@ class MessageLookup extends MessageLookupByLibrary { "Comprendo che se perdo la password potrei perdere l\'accesso ai miei dati poiché sono criptati end-to-end."), "activeSessions": MessageLookupByLibrary.simpleMessage("Sessioni attive"), + "addAName": MessageLookupByLibrary.simpleMessage("Aggiungi un nome"), "addANewEmail": MessageLookupByLibrary.simpleMessage("Aggiungi una nuova email"), "addCollaborator": MessageLookupByLibrary.simpleMessage("Aggiungi collaboratore"), + "addCollaborators": m3, "addFromDevice": MessageLookupByLibrary.simpleMessage("Aggiungi dal dispositivo"), "addItem": m4, @@ -200,16 +242,21 @@ class MessageLookup extends MessageLookupByLibrary { "addNew": MessageLookupByLibrary.simpleMessage("Aggiungi nuovo"), "addOnPageSubtitle": MessageLookupByLibrary.simpleMessage( "Dettagli dei componenti aggiuntivi"), + "addOnValidTill": m5, "addOns": MessageLookupByLibrary.simpleMessage("Componenti aggiuntivi"), "addPhotos": MessageLookupByLibrary.simpleMessage("Aggiungi foto"), "addSelected": MessageLookupByLibrary.simpleMessage("Aggiungi selezionate"), "addToAlbum": MessageLookupByLibrary.simpleMessage("Aggiungi all\'album"), + "addToEnte": MessageLookupByLibrary.simpleMessage("Aggiungi a Ente"), "addToHiddenAlbum": MessageLookupByLibrary.simpleMessage("Aggiungi ad album nascosto"), "addViewer": MessageLookupByLibrary.simpleMessage("Aggiungi in sola lettura"), + "addViewers": m6, + "addYourPhotosNow": + MessageLookupByLibrary.simpleMessage("Aggiungi le tue foto ora"), "addedAs": MessageLookupByLibrary.simpleMessage("Aggiunto come"), "addedBy": m7, "addedSuccessfullyTo": m8, @@ -322,7 +369,10 @@ class MessageLookup extends MessageLookupByLibrary { "Autenticazione non riuscita, prova di nuovo"), "authenticationSuccessful": MessageLookupByLibrary.simpleMessage("Autenticazione riuscita!"), + "autoLogoutMessage": MessageLookupByLibrary.simpleMessage( + "A causa di problemi tecnici, sei stato disconnesso. Ci scusiamo per l\'inconveniente."), "available": MessageLookupByLibrary.simpleMessage("Disponibile"), + "availableStorageSpace": m11, "backedUpFolders": MessageLookupByLibrary.simpleMessage("Cartelle salvate"), "backup": MessageLookupByLibrary.simpleMessage("Backup"), @@ -333,6 +383,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Impostazioni backup"), "backupVideos": MessageLookupByLibrary.simpleMessage("Backup dei video"), + "blackFridaySale": + MessageLookupByLibrary.simpleMessage("Offerta del Black Friday"), "blog": MessageLookupByLibrary.simpleMessage("Blog"), "cachedData": MessageLookupByLibrary.simpleMessage("Dati nella cache"), "calculating": MessageLookupByLibrary.simpleMessage("Calcolando..."), @@ -351,7 +403,10 @@ class MessageLookup extends MessageLookupByLibrary { "cannotAddMorePhotosAfterBecomingViewer": m13, "cannotDeleteSharedFiles": MessageLookupByLibrary.simpleMessage( "Impossibile eliminare i file condivisi"), + "castInstruction": MessageLookupByLibrary.simpleMessage( + "Visita cast.ente.io sul dispositivo che vuoi abbinare.\n\nInserisci il codice qui sotto per riprodurre l\'album sulla tua TV."), "centerPoint": MessageLookupByLibrary.simpleMessage("Punto centrale"), + "change": MessageLookupByLibrary.simpleMessage("Cambia"), "changeEmail": MessageLookupByLibrary.simpleMessage("Modifica email"), "changeLocationOfSelectedItems": MessageLookupByLibrary.simpleMessage( "Cambiare la posizione degli elementi selezionati?"), @@ -361,10 +416,13 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Modifica password"), "changePermissions": MessageLookupByLibrary.simpleMessage("Cambio i permessi?"), + "changeYourReferralCode": + MessageLookupByLibrary.simpleMessage("Cambia il tuo codice invito"), "checkForUpdates": MessageLookupByLibrary.simpleMessage("Controlla aggiornamenti"), "checkInboxAndSpamFolder": MessageLookupByLibrary.simpleMessage( "Per favore, controlla la tua casella di posta (e lo spam) per completare la verifica"), + "checkStatus": MessageLookupByLibrary.simpleMessage("Verifica stato"), "checking": MessageLookupByLibrary.simpleMessage("Controllo in corso..."), "claimFreeStorage": @@ -384,10 +442,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Unisci per nome file"), "codeAppliedPageTitle": MessageLookupByLibrary.simpleMessage("Codice applicato"), + "codeChangeLimitReached": MessageLookupByLibrary.simpleMessage( + "Siamo spiacenti, hai raggiunto il limite di modifiche del codice."), "codeCopiedToClipboard": MessageLookupByLibrary.simpleMessage( "Codice copiato negli appunti"), "codeUsedByYou": MessageLookupByLibrary.simpleMessage("Codice utilizzato da te"), + "collabLinkSectionDescription": MessageLookupByLibrary.simpleMessage( + "Crea un link per consentire alle persone di aggiungere e visualizzare foto nel tuo album condiviso senza bisogno di un\'applicazione o di un account Ente. Ottimo per raccogliere foto di un evento."), "collaborativeLink": MessageLookupByLibrary.simpleMessage("Link collaborativo"), "collaborativeLinkCreatedFor": m15, @@ -409,7 +471,7 @@ class MessageLookup extends MessageLookupByLibrary { "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage( "Conferma eliminazione account"), "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "Sì, voglio eliminare definitivamente questo account e tutti i suoi dati."), + "Sì, voglio eliminare definitivamente questo account e i dati associati a esso su tutte le applicazioni."), "confirmPassword": MessageLookupByLibrary.simpleMessage("Conferma password"), "confirmPlanChange": MessageLookupByLibrary.simpleMessage( @@ -423,6 +485,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Contatta il supporto"), "contactToManageSubscription": m17, "contacts": MessageLookupByLibrary.simpleMessage("Contatti"), + "contents": MessageLookupByLibrary.simpleMessage("Contenuti"), "continueLabel": MessageLookupByLibrary.simpleMessage("Continua"), "continueOnFreeTrial": MessageLookupByLibrary.simpleMessage("Continua la prova gratuita"), @@ -493,6 +556,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Elimina da entrambi"), "deleteFromDevice": MessageLookupByLibrary.simpleMessage("Elimina dal dispositivo"), + "deleteFromEnte": + MessageLookupByLibrary.simpleMessage("Elimina da Ente"), "deleteItemCount": m19, "deleteLocation": MessageLookupByLibrary.simpleMessage("Elimina posizione"), @@ -512,11 +577,22 @@ class MessageLookup extends MessageLookupByLibrary { "Eliminare l\'album condiviso?"), "deleteSharedAlbumDialogBody": MessageLookupByLibrary.simpleMessage( "L\'album verrà eliminato per tutti\n\nPerderai l\'accesso alle foto condivise in questo album che sono di proprietà di altri"), + "descriptions": MessageLookupByLibrary.simpleMessage("Descrizioni"), "deselectAll": MessageLookupByLibrary.simpleMessage("Deseleziona tutti"), "designedToOutlive": MessageLookupByLibrary.simpleMessage("Progettato per sopravvivere"), "details": MessageLookupByLibrary.simpleMessage("Dettagli"), + "developerSettings": + MessageLookupByLibrary.simpleMessage("Impostazioni sviluppatore"), + "deviceCodeHint": + MessageLookupByLibrary.simpleMessage("Inserisci il codice"), + "deviceFilesAutoUploading": MessageLookupByLibrary.simpleMessage( + "I file aggiunti a questo album del dispositivo verranno automaticamente caricati su Ente."), + "deviceLockExplanation": MessageLookupByLibrary.simpleMessage( + "Disabilita il blocco schermo del dispositivo quando Ente è in primo piano e c\'è un backup in corso. Questo normalmente non è necessario ma può aiutare a completare più velocemente grossi caricamenti e l\'importazione iniziale di grandi librerie."), + "deviceNotFound": + MessageLookupByLibrary.simpleMessage("Dispositivo non trovato"), "didYouKnow": MessageLookupByLibrary.simpleMessage("Lo sapevi che?"), "disableAutoLock": MessageLookupByLibrary.simpleMessage( "Disabilita blocco automatico"), @@ -560,6 +636,7 @@ class MessageLookup extends MessageLookupByLibrary { "eligible": MessageLookupByLibrary.simpleMessage("idoneo"), "email": MessageLookupByLibrary.simpleMessage("Email"), "emailChangedTo": m25, + "emailNoEnteAccount": m26, "emailVerificationToggle": MessageLookupByLibrary.simpleMessage("Verifica Email"), "emailYourLogs": MessageLookupByLibrary.simpleMessage( @@ -577,6 +654,13 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Chiavi di crittografia"), "endtoendEncryptedByDefault": MessageLookupByLibrary.simpleMessage("Crittografia end-to-end"), + "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": + MessageLookupByLibrary.simpleMessage( + "Ente può criptare e conservare i file solo se gliene concedi l\'accesso"), + "entePhotosPerm": MessageLookupByLibrary.simpleMessage( + "Ente necessita del permesso per preservare le tue foto"), + "enteSubscriptionPitch": MessageLookupByLibrary.simpleMessage( + "Ente conserva i tuoi ricordi in modo che siano sempre a disposizione, anche se perdi il tuo dispositivo."), "enteSubscriptionShareWithFamily": MessageLookupByLibrary.simpleMessage( "Aggiungi la tua famiglia al tuo piano."), "enterAlbumName": MessageLookupByLibrary.simpleMessage( @@ -614,6 +698,7 @@ class MessageLookup extends MessageLookupByLibrary { "Questo link è scaduto. Si prega di selezionare un nuovo orario di scadenza o disabilitare la scadenza del link."), "exportLogs": MessageLookupByLibrary.simpleMessage("Esporta log"), "exportYourData": MessageLookupByLibrary.simpleMessage("Esporta dati"), + "faces": MessageLookupByLibrary.simpleMessage("Volti"), "failedToApplyCode": MessageLookupByLibrary.simpleMessage( "Impossibile applicare il codice"), "failedToCancel": @@ -630,6 +715,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Rinnovo fallito"), "failedToVerifyPaymentStatus": MessageLookupByLibrary.simpleMessage( "Impossibile verificare lo stato del pagamento"), + "familyPlanOverview": MessageLookupByLibrary.simpleMessage( + "Aggiungi 5 membri della famiglia al tuo piano esistente senza pagare extra.\n\nOgni membro ottiene il proprio spazio privato e non può vedere i file dell\'altro a meno che non siano condivisi.\n\nI piani familiari sono disponibili per i clienti che hanno un abbonamento Ente a pagamento.\n\nIscriviti ora per iniziare!"), "familyPlanPortalTitle": MessageLookupByLibrary.simpleMessage("Famiglia"), "familyPlans": MessageLookupByLibrary.simpleMessage("Piano famiglia"), @@ -643,9 +730,16 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Aggiungi descrizione..."), "fileSavedToGallery": MessageLookupByLibrary.simpleMessage("File salvato nella galleria"), + "fileTypes": MessageLookupByLibrary.simpleMessage("Tipi di file"), + "fileTypesAndNames": + MessageLookupByLibrary.simpleMessage("Tipi e nomi di file"), "filesBackedUpFromDevice": m27, "filesBackedUpInAlbum": m28, "filesDeleted": MessageLookupByLibrary.simpleMessage("File eliminati"), + "filesSavedToGallery": + MessageLookupByLibrary.simpleMessage("File salvati nella galleria"), + "findPeopleByName": MessageLookupByLibrary.simpleMessage( + "Trova rapidamente le persone per nome"), "flip": MessageLookupByLibrary.simpleMessage("Capovolgi"), "forYourMemories": MessageLookupByLibrary.simpleMessage("per i tuoi ricordi"), @@ -662,6 +756,8 @@ class MessageLookup extends MessageLookupByLibrary { "freeUpAmount": m32, "freeUpDeviceSpace": MessageLookupByLibrary.simpleMessage("Libera spazio"), + "freeUpDeviceSpaceDesc": MessageLookupByLibrary.simpleMessage( + "Risparmia spazio sul tuo dispositivo cancellando i file che sono già stati salvati online."), "freeUpSpace": MessageLookupByLibrary.simpleMessage("Libera spazio"), "freeUpSpaceSaving": m33, "galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage( @@ -669,6 +765,7 @@ class MessageLookup extends MessageLookupByLibrary { "general": MessageLookupByLibrary.simpleMessage("Generali"), "generatingEncryptionKeys": MessageLookupByLibrary.simpleMessage( "Generazione delle chiavi di crittografia..."), + "genericProgress": m34, "goToSettings": MessageLookupByLibrary.simpleMessage("Vai alle impostazioni"), "googlePlayId": MessageLookupByLibrary.simpleMessage("Google Play ID"), @@ -682,6 +779,7 @@ class MessageLookup extends MessageLookupByLibrary { "Non teniamo traccia del numero di installazioni dell\'app. Sarebbe utile se ci dicesse dove ci ha trovato!"), "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( "Come hai sentito parlare di Ente? (opzionale)"), + "help": MessageLookupByLibrary.simpleMessage("Aiuto"), "hidden": MessageLookupByLibrary.simpleMessage("Nascosti"), "hide": MessageLookupByLibrary.simpleMessage("Nascondi"), "hiding": MessageLookupByLibrary.simpleMessage("Nascondendo..."), @@ -696,6 +794,8 @@ class MessageLookup extends MessageLookupByLibrary { "L\'autenticazione biometrica è disabilitata. Blocca e sblocca lo schermo per abilitarla."), "iOSOkButton": MessageLookupByLibrary.simpleMessage("OK"), "ignoreUpdate": MessageLookupByLibrary.simpleMessage("Ignora"), + "ignoredFolderUploadReason": MessageLookupByLibrary.simpleMessage( + "Alcuni file in questo album vengono ignorati dal caricamento perché erano stati precedentemente eliminati da Ente."), "importing": MessageLookupByLibrary.simpleMessage("Importazione in corso...."), "incorrectCode": @@ -716,12 +816,19 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Installa manualmente"), "invalidEmailAddress": MessageLookupByLibrary.simpleMessage("Indirizzo email non valido"), + "invalidEndpoint": + MessageLookupByLibrary.simpleMessage("Endpoint invalido"), + "invalidEndpointMessage": MessageLookupByLibrary.simpleMessage( + "Spiacenti, l\'endpoint inserito non è valido. Inserisci un endpoint valido e riprova."), "invalidKey": MessageLookupByLibrary.simpleMessage("Chiave non valida"), "invalidRecoveryKey": MessageLookupByLibrary.simpleMessage( "La chiave di recupero che hai inserito non è valida. Assicurati che contenga 24 parole e controlla l\'ortografia di ciascuna parola.\n\nSe hai inserito un vecchio codice di recupero, assicurati che sia lungo 64 caratteri e controlla ciascuno di essi."), "invite": MessageLookupByLibrary.simpleMessage("Invita"), + "inviteToEnte": MessageLookupByLibrary.simpleMessage("Invita su Ente"), "inviteYourFriends": MessageLookupByLibrary.simpleMessage("Invita i tuoi amici"), + "inviteYourFriendsToEnte": + MessageLookupByLibrary.simpleMessage("Invita i tuoi amici a Ente"), "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Sembra che qualcosa sia andato storto. Riprova tra un po\'. Se l\'errore persiste, contatta il nostro team di supporto."), @@ -731,6 +838,8 @@ class MessageLookup extends MessageLookupByLibrary { "Gli elementi mostrano il numero di giorni rimanenti prima della cancellazione permanente"), "itemsWillBeRemovedFromAlbum": MessageLookupByLibrary.simpleMessage( "Gli elementi selezionati saranno rimossi da questo album"), + "joinDiscord": + MessageLookupByLibrary.simpleMessage("Unisciti a Discord"), "keepPhotos": MessageLookupByLibrary.simpleMessage("Mantieni foto"), "kiloMeterUnit": MessageLookupByLibrary.simpleMessage("km"), "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( @@ -782,17 +891,24 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Caricamento galleria..."), "loadingMessage": MessageLookupByLibrary.simpleMessage("Caricando le tue foto..."), + "loadingModel": + MessageLookupByLibrary.simpleMessage("Scaricamento modelli..."), "localGallery": MessageLookupByLibrary.simpleMessage("Galleria locale"), "location": MessageLookupByLibrary.simpleMessage("Luogo"), "locationName": MessageLookupByLibrary.simpleMessage("Nome della località"), "locationTagFeatureDescription": MessageLookupByLibrary.simpleMessage( "Un tag di localizzazione raggruppa tutte le foto scattate entro il raggio di una foto"), + "locations": MessageLookupByLibrary.simpleMessage("Luoghi"), "lockButtonLabel": MessageLookupByLibrary.simpleMessage("Blocca"), "lockscreen": MessageLookupByLibrary.simpleMessage("Schermata di blocco"), "logInLabel": MessageLookupByLibrary.simpleMessage("Accedi"), "loggingOut": MessageLookupByLibrary.simpleMessage("Disconnessione..."), + "loginSessionExpired": + MessageLookupByLibrary.simpleMessage("Sessione scaduta"), + "loginSessionExpiredDetails": MessageLookupByLibrary.simpleMessage( + "La sessione è scaduta. Si prega di accedere nuovamente."), "loginTerms": MessageLookupByLibrary.simpleMessage( "Cliccando sul pulsante Accedi, accetti i termini di servizio e la politica sulla privacy"), "logout": MessageLookupByLibrary.simpleMessage("Disconnetti"), @@ -818,9 +934,19 @@ class MessageLookup extends MessageLookupByLibrary { "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), "memoryCount": m0, "merchandise": MessageLookupByLibrary.simpleMessage("Merchandise"), + "mlConsentDescription": MessageLookupByLibrary.simpleMessage( + "Se abiliti il Machine Learning, Ente estrarrà informazioni come la geometria del volto dai file, inclusi quelli condivisi con te.\n\nQuesto accadrà sul tuo dispositivo, e qualsiasi informazione biometrica generata sarà crittografata end-to-end."), + "mlConsentPrivacy": MessageLookupByLibrary.simpleMessage( + "Clicca qui per maggiori dettagli su questa funzione nella nostra informativa sulla privacy"), + "mlIndexingDescription": MessageLookupByLibrary.simpleMessage( + "Si prega di notare che l\'attivazione dell\'apprendimento automatico si tradurrà in un maggior utilizzo della connessione e della batteria fino a quando tutti gli elementi non saranno indicizzati. Valuta di utilizzare l\'applicazione desktop per un\'indicizzazione più veloce, tutti i risultati verranno sincronizzati automaticamente."), "mobileWebDesktop": MessageLookupByLibrary.simpleMessage("Mobile, Web, Desktop"), "moderateStrength": MessageLookupByLibrary.simpleMessage("Mediocre"), + "modifyYourQueryOrTrySearchingFor": + MessageLookupByLibrary.simpleMessage( + "Modifica la tua interrogazione o prova a cercare"), + "moments": MessageLookupByLibrary.simpleMessage("Momenti"), "monthly": MessageLookupByLibrary.simpleMessage("Mensile"), "moveItem": m37, "moveToAlbum": @@ -839,6 +965,8 @@ class MessageLookup extends MessageLookupByLibrary { "Impossibile connettersi a Ente, controlla le impostazioni di rete e contatta l\'assistenza se l\'errore persiste."), "never": MessageLookupByLibrary.simpleMessage("Mai"), "newAlbum": MessageLookupByLibrary.simpleMessage("Nuovo album"), + "newToEnte": + MessageLookupByLibrary.simpleMessage("Prima volta con Ente"), "newest": MessageLookupByLibrary.simpleMessage("Più recenti"), "no": MessageLookupByLibrary.simpleMessage("No"), "noAlbumsSharedByYouYet": MessageLookupByLibrary.simpleMessage( @@ -876,6 +1004,7 @@ class MessageLookup extends MessageLookupByLibrary { "onDevice": MessageLookupByLibrary.simpleMessage("Sul dispositivo"), "onEnte": MessageLookupByLibrary.simpleMessage( "Su ente"), + "onlyFamilyAdminCanChangeCode": m40, "oops": MessageLookupByLibrary.simpleMessage("Oops"), "oopsCouldNotSaveEdits": MessageLookupByLibrary.simpleMessage( "Ops, impossibile salvare le modifiche"), @@ -891,6 +1020,12 @@ class MessageLookup extends MessageLookupByLibrary { "Facoltativo, breve quanto vuoi..."), "orPickAnExistingOne": MessageLookupByLibrary.simpleMessage( "Oppure scegline una esistente"), + "pair": MessageLookupByLibrary.simpleMessage("Abbina"), + "passKeyPendingVerification": MessageLookupByLibrary.simpleMessage( + "La verifica è ancora in corso"), + "passkey": MessageLookupByLibrary.simpleMessage("Passkey"), + "passkeyAuthTitle": + MessageLookupByLibrary.simpleMessage("Verifica della passkey"), "password": MessageLookupByLibrary.simpleMessage("Password"), "passwordChangedSuccessfully": MessageLookupByLibrary.simpleMessage( "Password modificata con successo"), @@ -903,11 +1038,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Dettagli di Pagamento"), "paymentFailed": MessageLookupByLibrary.simpleMessage("Pagamento non riuscito"), + "paymentFailedMessage": MessageLookupByLibrary.simpleMessage( + "Purtroppo il tuo pagamento non è riuscito. Contatta l\'assistenza e ti aiuteremo!"), "paymentFailedTalkToProvider": m42, "pendingItems": MessageLookupByLibrary.simpleMessage("Elementi in sospeso"), "pendingSync": MessageLookupByLibrary.simpleMessage("Sincronizzazione in sospeso"), + "people": MessageLookupByLibrary.simpleMessage("Persone"), "peopleUsingYourCode": MessageLookupByLibrary.simpleMessage( "Persone che hanno usato il tuo codice"), "permDeleteWarning": MessageLookupByLibrary.simpleMessage( @@ -916,15 +1054,21 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Elimina definitivamente"), "permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage( "Eliminare definitivamente dal dispositivo?"), + "photoDescriptions": + MessageLookupByLibrary.simpleMessage("Descrizioni delle foto"), "photoGridSize": MessageLookupByLibrary.simpleMessage("Dimensione griglia foto"), "photoSmallCase": MessageLookupByLibrary.simpleMessage("foto"), + "photos": MessageLookupByLibrary.simpleMessage("Foto"), "photosAddedByYouWillBeRemovedFromTheAlbum": MessageLookupByLibrary.simpleMessage( "Le foto aggiunte da te verranno rimosse dall\'album"), "pickCenterPoint": MessageLookupByLibrary.simpleMessage( "Selezionare il punto centrale"), "pinAlbum": MessageLookupByLibrary.simpleMessage("Fissa l\'album"), + "playOnTv": + MessageLookupByLibrary.simpleMessage("Riproduci album sulla TV"), + "playStoreFreeTrialValidTill": m43, "playstoreSubscription": MessageLookupByLibrary.simpleMessage("Abbonamento su PlayStore"), "pleaseCheckYourInternetConnectionAndTryAgain": @@ -1022,10 +1166,14 @@ class MessageLookup extends MessageLookupByLibrary { "remove": MessageLookupByLibrary.simpleMessage("Rimuovi"), "removeDuplicates": MessageLookupByLibrary.simpleMessage("Rimuovi i doppioni"), + "removeDuplicatesDesc": MessageLookupByLibrary.simpleMessage( + "Verifica e rimuovi i file che sono esattamente duplicati."), "removeFromAlbum": MessageLookupByLibrary.simpleMessage("Rimuovi dall\'album"), "removeFromAlbumTitle": MessageLookupByLibrary.simpleMessage("Rimuovi dall\'album?"), + "removeFromFavorite": + MessageLookupByLibrary.simpleMessage("Rimuovi dai preferiti"), "removeLink": MessageLookupByLibrary.simpleMessage("Elimina link"), "removeParticipant": MessageLookupByLibrary.simpleMessage("Rimuovi partecipante"), @@ -1058,6 +1206,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ripristina l\'album"), "restoringFiles": MessageLookupByLibrary.simpleMessage("Ripristinando file..."), + "resumableUploads": + MessageLookupByLibrary.simpleMessage("Caricamenti riattivabili"), "retry": MessageLookupByLibrary.simpleMessage("Riprova"), "reviewDeduplicateItems": MessageLookupByLibrary.simpleMessage( "Controlla ed elimina gli elementi che credi siano dei doppioni."), @@ -1083,8 +1233,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Nome album"), "searchByExamples": MessageLookupByLibrary.simpleMessage( "• Nomi degli album (es. \"Camera\")\n• Tipi di file (es. \"Video\", \".gif\")\n• Anni e mesi (e.. \"2022\", \"gennaio\")\n• Vacanze (ad es. \"Natale\")\n• Descrizioni delle foto (ad es. “#mare”)"), + "searchCaptionEmptySection": MessageLookupByLibrary.simpleMessage( + "Aggiungi descrizioni come \"#viaggio\" nelle informazioni delle foto per trovarle rapidamente qui"), "searchDatesEmptySection": MessageLookupByLibrary.simpleMessage( "Ricerca per data, mese o anno"), + "searchFaceEmptySection": MessageLookupByLibrary.simpleMessage( + "Le persone saranno mostrate qui una volta completata l\'indicizzazione"), + "searchFileTypesAndNamesEmptySection": + MessageLookupByLibrary.simpleMessage("Tipi e nomi di file"), "searchHint3": MessageLookupByLibrary.simpleMessage("Album, nomi di file e tipi"), "searchHint4": MessageLookupByLibrary.simpleMessage("Luogo"), @@ -1092,6 +1248,7 @@ class MessageLookup extends MessageLookupByLibrary { "Raggruppa foto scattate entro un certo raggio da una foto"), "searchPeopleEmptySection": MessageLookupByLibrary.simpleMessage( "Invita persone e vedrai qui tutte le foto condivise da loro"), + "searchResultCount": m50, "security": MessageLookupByLibrary.simpleMessage("Sicurezza"), "selectALocation": MessageLookupByLibrary.simpleMessage("Seleziona un luogo"), @@ -1111,6 +1268,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Seleziona un motivo"), "selectYourPlan": MessageLookupByLibrary.simpleMessage("Seleziona un piano"), + "selectedFilesAreNotOnEnte": MessageLookupByLibrary.simpleMessage( + "I file selezionati non sono su Ente"), "selectedFoldersWillBeEncryptedAndBackedUp": MessageLookupByLibrary.simpleMessage( "Le cartelle selezionate verranno crittografate e salvate su ente"), @@ -1123,6 +1282,8 @@ class MessageLookup extends MessageLookupByLibrary { "sendEmail": MessageLookupByLibrary.simpleMessage("Invia email"), "sendInvite": MessageLookupByLibrary.simpleMessage("Invita"), "sendLink": MessageLookupByLibrary.simpleMessage("Invia link"), + "serverEndpoint": + MessageLookupByLibrary.simpleMessage("Endpoint del server"), "sessionExpired": MessageLookupByLibrary.simpleMessage("Sessione scaduta"), "setAPassword": @@ -1146,9 +1307,16 @@ class MessageLookup extends MessageLookupByLibrary { "shareOnlyWithThePeopleYouWant": MessageLookupByLibrary.simpleMessage( "Condividi solo con le persone che vuoi"), "shareTextConfirmOthersVerificationID": m2, + "shareTextRecommendUsingEnte": MessageLookupByLibrary.simpleMessage( + "Scarica Ente in modo da poter facilmente condividere foto e video in qualità originale\n\nhttps://ente.io"), + "shareTextReferralCode": m53, + "shareWithNonenteUsers": MessageLookupByLibrary.simpleMessage( + "Condividi con utenti che non hanno un account Ente"), "shareWithPeopleSectionTitle": m54, "shareYourFirstAlbum": MessageLookupByLibrary.simpleMessage( "Condividi il tuo primo album"), + "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( + "Crea album condivisi e collaborativi con altri utenti di Ente, inclusi gli utenti con piani gratuiti."), "sharedByMe": MessageLookupByLibrary.simpleMessage("Condiviso da me"), "sharedByYou": MessageLookupByLibrary.simpleMessage("Condivise da te"), "sharedPhotoNotifications": @@ -1174,8 +1342,13 @@ class MessageLookup extends MessageLookupByLibrary { "singleFileDeleteFromDevice": m56, "singleFileDeleteHighlight": MessageLookupByLibrary.simpleMessage( "Verrà eliminato da tutti gli album."), + "singleFileInBothLocalAndRemote": m57, + "singleFileInRemoteOnly": m58, "skip": MessageLookupByLibrary.simpleMessage("Salta"), "social": MessageLookupByLibrary.simpleMessage("Social"), + "someItemsAreInBothEnteAndYourDevice": + MessageLookupByLibrary.simpleMessage( + "Alcuni elementi sono sia su Ente che sul tuo dispositivo."), "someOfTheFilesYouAreTryingToDeleteAre": MessageLookupByLibrary.simpleMessage( "Alcuni dei file che si sta tentando di eliminare sono disponibili solo sul dispositivo e non possono essere recuperati se cancellati"), @@ -1217,6 +1390,7 @@ class MessageLookup extends MessageLookupByLibrary { "Limite d\'archiviazione superato"), "storageUsageInfo": m60, "strongStrength": MessageLookupByLibrary.simpleMessage("Forte"), + "subAlreadyLinkedErrMessage": m61, "subWillBeCancelledOn": m62, "subscribe": MessageLookupByLibrary.simpleMessage("Iscriviti"), "subscribeToEnableSharing": MessageLookupByLibrary.simpleMessage( @@ -1298,6 +1472,8 @@ class MessageLookup extends MessageLookupByLibrary { "trash": MessageLookupByLibrary.simpleMessage("Cestino"), "trashDaysLeft": m66, "tryAgain": MessageLookupByLibrary.simpleMessage("Riprova"), + "turnOnBackupForAutoUpload": MessageLookupByLibrary.simpleMessage( + "Attiva il backup per caricare automaticamente i file aggiunti a questa cartella del dispositivo su Ente."), "twitter": MessageLookupByLibrary.simpleMessage("Twitter"), "twoMonthsFreeOnYearlyPlans": MessageLookupByLibrary.simpleMessage( "2 mesi gratis sui piani annuali"), @@ -1319,6 +1495,8 @@ class MessageLookup extends MessageLookupByLibrary { "Rimuovi album dall\'archivio"), "unarchiving": MessageLookupByLibrary.simpleMessage("Togliendo dall\'archivio..."), + "unavailableReferralCode": MessageLookupByLibrary.simpleMessage( + "Siamo spiacenti, questo codice non è disponibile."), "uncategorized": MessageLookupByLibrary.simpleMessage("Senza categoria"), "unhide": MessageLookupByLibrary.simpleMessage("Mostra"), @@ -1343,6 +1521,9 @@ class MessageLookup extends MessageLookupByLibrary { "Caricamento dei file nell\'album..."), "usableReferralStorageInfo": MessageLookupByLibrary.simpleMessage( "Lo spazio disponibile è limitato dal tuo piano corrente. L\'archiviazione in eccesso diventerà automaticamente utilizzabile quando aggiornerai il tuo piano."), + "usePublicLinksForPeopleNotOnEnte": + MessageLookupByLibrary.simpleMessage( + "Usa link pubblici per persone non registrate su Ente"), "useRecoveryKey": MessageLookupByLibrary.simpleMessage( "Utilizza un codice di recupero"), "useSelectedPhoto": @@ -1358,6 +1539,8 @@ class MessageLookup extends MessageLookupByLibrary { "verifyEmail": MessageLookupByLibrary.simpleMessage("Verifica email"), "verifyEmailID": m68, "verifyIDLabel": MessageLookupByLibrary.simpleMessage("Verifica"), + "verifyPasskey": + MessageLookupByLibrary.simpleMessage("Verifica passkey"), "verifyPassword": MessageLookupByLibrary.simpleMessage("Verifica password"), "verifying": @@ -1365,6 +1548,7 @@ class MessageLookup extends MessageLookupByLibrary { "verifyingRecoveryKey": MessageLookupByLibrary.simpleMessage( "Verifica della chiave di recupero..."), "videoSmallCase": MessageLookupByLibrary.simpleMessage("video"), + "videos": MessageLookupByLibrary.simpleMessage("Video"), "viewActiveSessions": MessageLookupByLibrary.simpleMessage("Visualizza sessioni attive"), "viewAddOnButton": MessageLookupByLibrary.simpleMessage( @@ -1372,12 +1556,18 @@ class MessageLookup extends MessageLookupByLibrary { "viewAll": MessageLookupByLibrary.simpleMessage("Visualizza tutte"), "viewAllExifData": MessageLookupByLibrary.simpleMessage("Mostra tutti i dati EXIF"), + "viewLargeFiles": + MessageLookupByLibrary.simpleMessage("File di grandi dimensioni"), + "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( + "Visualizza i file che stanno occupando la maggior parte dello spazio di archiviazione."), "viewLogs": MessageLookupByLibrary.simpleMessage("Visualizza i log"), "viewRecoveryKey": MessageLookupByLibrary.simpleMessage( "Visualizza chiave di recupero"), "viewer": MessageLookupByLibrary.simpleMessage("Sola lettura"), "visitWebToManage": MessageLookupByLibrary.simpleMessage( "Visita web.ente.io per gestire il tuo abbonamento"), + "waitingForVerification": + MessageLookupByLibrary.simpleMessage("In attesa di verifica..."), "waitingForWifi": MessageLookupByLibrary.simpleMessage("In attesa del WiFi..."), "weAreOpenSource": @@ -1422,6 +1612,7 @@ class MessageLookup extends MessageLookupByLibrary { "youHaveSuccessfullyFreedUp": m71, "yourAccountHasBeenDeleted": MessageLookupByLibrary.simpleMessage( "Il tuo account è stato eliminato"), + "yourMap": MessageLookupByLibrary.simpleMessage("La tua mappa"), "yourPlanWasSuccessfullyDowngraded": MessageLookupByLibrary.simpleMessage( "Il tuo piano è stato aggiornato con successo"), diff --git a/mobile/lib/generated/intl/messages_nl.dart b/mobile/lib/generated/intl/messages_nl.dart index a33e630355..e2a5cc4c5b 100644 --- a/mobile/lib/generated/intl/messages_nl.dart +++ b/mobile/lib/generated/intl/messages_nl.dart @@ -363,6 +363,8 @@ class MessageLookup extends MessageLookupByLibrary { "Graag verifiëren om tweestapsverificatie te configureren"), "authToInitiateAccountDeletion": MessageLookupByLibrary.simpleMessage( "Gelieve te verifiëren om het verwijderen van je account te starten"), + "authToViewPasskey": MessageLookupByLibrary.simpleMessage( + "Verifieer uzelf om uw toegangssleutel te bekijken"), "authToViewYourActiveSessions": MessageLookupByLibrary.simpleMessage( "Graag verifiëren om uw actieve sessies te bekijken"), "authToViewYourHiddenFiles": MessageLookupByLibrary.simpleMessage( @@ -401,6 +403,9 @@ class MessageLookup extends MessageLookupByLibrary { "Back-up maken via mobiele data"), "backupSettings": MessageLookupByLibrary.simpleMessage("Back-up instellingen"), + "backupStatus": MessageLookupByLibrary.simpleMessage("Back-upstatus"), + "backupStatusDescription": MessageLookupByLibrary.simpleMessage( + "Items die zijn geback-upt, worden hier getoond"), "backupVideos": MessageLookupByLibrary.simpleMessage("Back-up video\'s"), "blackFridaySale": @@ -515,7 +520,7 @@ class MessageLookup extends MessageLookupByLibrary { "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage( "Account verwijderen bevestigen"), "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "Ja, ik wil permanent mijn account inclusief alle gegevens verwijderen."), + "Ja, ik wil mijn account en de bijbehorende gegevens verspreid over alle apps permanent verwijderen."), "confirmPassword": MessageLookupByLibrary.simpleMessage("Wachtwoord bevestigen"), "confirmPlanChange": MessageLookupByLibrary.simpleMessage( @@ -1715,6 +1720,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Bekijk alle EXIF gegevens"), "viewLargeFiles": MessageLookupByLibrary.simpleMessage("Grote bestanden"), + "viewLargeFilesDesc": MessageLookupByLibrary.simpleMessage( + "Bekijk bestanden die de meeste opslagruimte verbruiken."), "viewLogs": MessageLookupByLibrary.simpleMessage("Logboeken bekijken"), "viewRecoveryKey": MessageLookupByLibrary.simpleMessage("Toon herstelsleutel"), diff --git a/mobile/lib/generated/intl/messages_no.dart b/mobile/lib/generated/intl/messages_no.dart index e5badae7f5..ff812646ff 100644 --- a/mobile/lib/generated/intl/messages_no.dart +++ b/mobile/lib/generated/intl/messages_no.dart @@ -21,7 +21,7 @@ class MessageLookup extends MessageLookupByLibrary { String get localeName => 'no'; static String m9(count) => - "${Intl.plural(count, zero: 'Ingen deltakere', one: '1 Deltaker', other: '${count} Deltakere')}"; + "${Intl.plural(count, zero: 'Ingen deltakere', one: '1 deltaker', other: '${count} deltakere')}"; static String m13(user) => "${user} vil ikke kunne legge til flere bilder til dette albumet\n\nDe vil fortsatt kunne fjerne eksisterende bilder lagt til av dem"; @@ -131,8 +131,6 @@ class MessageLookup extends MessageLookupByLibrary { "confirm": MessageLookupByLibrary.simpleMessage("Bekreft"), "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage("Bekreft sletting av konto"), - "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "Ja, jeg ønsker å slette denne kontoen og all dataen dens permanent."), "confirmPassword": MessageLookupByLibrary.simpleMessage("Bekreft passordet"), "confirmRecoveryKey": MessageLookupByLibrary.simpleMessage( diff --git a/mobile/lib/generated/intl/messages_pl.dart b/mobile/lib/generated/intl/messages_pl.dart index 8cb6018be4..7c2f1c7d5c 100644 --- a/mobile/lib/generated/intl/messages_pl.dart +++ b/mobile/lib/generated/intl/messages_pl.dart @@ -402,6 +402,10 @@ class MessageLookup extends MessageLookupByLibrary { "Kopia zapasowa przez dane mobilne"), "backupSettings": MessageLookupByLibrary.simpleMessage("Ustawienia kopii zapasowej"), + "backupStatus": + MessageLookupByLibrary.simpleMessage("Status kopii zapasowej"), + "backupStatusDescription": MessageLookupByLibrary.simpleMessage( + "Elementy, których kopia zapasowa została utworzona, zostaną wyświetlone w tym miejscu"), "backupVideos": MessageLookupByLibrary.simpleMessage("Utwórz kopię zapasową wideo"), "blackFridaySale": MessageLookupByLibrary.simpleMessage( @@ -516,7 +520,7 @@ class MessageLookup extends MessageLookupByLibrary { "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage("Potwierdź usunięcie konta"), "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "Tak, chcę trwale usunąć konto i wszystkie dane z nim powiązane."), + "Tak, chcę trwale usunąć to konto i jego dane ze wszystkich aplikacji."), "confirmPassword": MessageLookupByLibrary.simpleMessage("Powtórz hasło"), "confirmPlanChange": diff --git a/mobile/lib/generated/intl/messages_pt.dart b/mobile/lib/generated/intl/messages_pt.dart index 0472cbcbe0..cc57098dad 100644 --- a/mobile/lib/generated/intl/messages_pt.dart +++ b/mobile/lib/generated/intl/messages_pt.dart @@ -401,6 +401,10 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Backup usando dados móveis"), "backupSettings": MessageLookupByLibrary.simpleMessage("Configurações de backup"), + "backupStatus": + MessageLookupByLibrary.simpleMessage("Status do Backup"), + "backupStatusDescription": MessageLookupByLibrary.simpleMessage( + "Os itens que foram salvos no backup aparecerão aqui"), "backupVideos": MessageLookupByLibrary.simpleMessage("Backup de vídeos"), "blackFridaySale": @@ -513,7 +517,7 @@ class MessageLookup extends MessageLookupByLibrary { "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage("Confirmar exclusão da conta"), "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "Sim, desejo excluir permanentemente esta conta e todos os seus dados."), + "Sim, eu quero excluir permanentemente esta conta e seus dados em todos os aplicativos."), "confirmPassword": MessageLookupByLibrary.simpleMessage("Confirme sua senha"), "confirmPlanChange": diff --git a/mobile/lib/generated/intl/messages_ru.dart b/mobile/lib/generated/intl/messages_ru.dart index e40aaf8ce5..d43a5f04c6 100644 --- a/mobile/lib/generated/intl/messages_ru.dart +++ b/mobile/lib/generated/intl/messages_ru.dart @@ -341,7 +341,7 @@ class MessageLookup extends MessageLookupByLibrary { "atAFalloutShelter": MessageLookupByLibrary.simpleMessage("в бункере"), "authToChangeEmailVerificationSetting": MessageLookupByLibrary.simpleMessage( - "Авторизуйтесь, чтобы изменить подтверждение электронной почты"), + "Пожалуйста, войдите, чтобы изменить настройку подтверждения электронной почты"), "authToChangeLockscreenSetting": MessageLookupByLibrary.simpleMessage( "Пожалуйста, авторизуйтесь, чтобы изменить настройки экрана блокировки"), "authToChangeYourEmail": MessageLookupByLibrary.simpleMessage( @@ -390,8 +390,8 @@ class MessageLookup extends MessageLookupByLibrary { "Ошибка резервного копирования"), "backupOverMobileData": MessageLookupByLibrary.simpleMessage( "Резервное копирование через мобильную сеть"), - "backupSettings": - MessageLookupByLibrary.simpleMessage("Резервная копия настроек"), + "backupSettings": MessageLookupByLibrary.simpleMessage( + "Настройки резервного копирования"), "backupVideos": MessageLookupByLibrary.simpleMessage("Резервное копирование видео"), "blackFridaySale": MessageLookupByLibrary.simpleMessage( @@ -499,7 +499,7 @@ class MessageLookup extends MessageLookupByLibrary { "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage( "Подтвердить удаление учётной записи"), "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "Да, я хочу навсегда удалить эту учётную запись и все её данные."), + "Да, я хочу навсегда удалить эту учётную запись и все её данные во всех приложениях Ente."), "confirmPassword": MessageLookupByLibrary.simpleMessage("Подтвердите пароль"), "confirmPlanChange": @@ -676,13 +676,15 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("Электронная почта"), "emailChangedTo": m25, "emailNoEnteAccount": m26, - "emailVerificationToggle": MessageLookupByLibrary.simpleMessage( - "Подтверждение электронной почты"), + "emailVerificationToggle": + MessageLookupByLibrary.simpleMessage("Вход с кодом на почту"), "emailYourLogs": MessageLookupByLibrary.simpleMessage( "Отправить логи по электронной почте"), "empty": MessageLookupByLibrary.simpleMessage("Очистить"), "emptyTrash": MessageLookupByLibrary.simpleMessage("Очистить корзину?"), "enable": MessageLookupByLibrary.simpleMessage("Включить"), + "enableMLIndexingDesc": MessageLookupByLibrary.simpleMessage( + "Ente поддерживает машинное обучение на устройстве для распознавания лиц, умного поиска и других расширенных функций поиска"), "enableMaps": MessageLookupByLibrary.simpleMessage("Включить карты"), "enableMapsDesc": MessageLookupByLibrary.simpleMessage( "Ваши фотографии будут показаны на карте мира.\n\nЭта карта размещена на Open Street Map, и точное местоположение ваших фотографий никогда не разглашается.\n\nВы можете отключить эту функцию в любое время в настройках."), @@ -767,7 +769,7 @@ class MessageLookup extends MessageLookupByLibrary { "Добавьте 5 членов семьи к существующему плану без дополнительной оплаты.\n\nКаждый участник получает свое личное пространство и не может видеть файлы друг друга, если к ним не предоставлен общий доступ.\n\nСемейные планы доступны клиентам, имеющим платную подписку на Ente.\n\nПодпишитесь сейчас, чтобы начать!"), "familyPlanPortalTitle": MessageLookupByLibrary.simpleMessage("Семья"), "familyPlans": MessageLookupByLibrary.simpleMessage("Семейные планы"), - "faq": MessageLookupByLibrary.simpleMessage("ЧаВо"), + "faq": MessageLookupByLibrary.simpleMessage("Ответы на ваши вопросы"), "faqs": MessageLookupByLibrary.simpleMessage("Часто задаваемые вопросы"), "favorite": MessageLookupByLibrary.simpleMessage("В избранное"), @@ -831,7 +833,7 @@ class MessageLookup extends MessageLookupByLibrary { "Будет полезно, если вы укажете, где нашли нас, так как мы не отслеживаем установки приложения!"), "hearUsWhereTitle": MessageLookupByLibrary.simpleMessage( "Как вы узнали о Ente? (необязательно)"), - "help": MessageLookupByLibrary.simpleMessage("помощь"), + "help": MessageLookupByLibrary.simpleMessage("Помощь"), "hidden": MessageLookupByLibrary.simpleMessage("Скрыто"), "hide": MessageLookupByLibrary.simpleMessage("Скрыть"), "hideContent": @@ -987,6 +989,8 @@ class MessageLookup extends MessageLookupByLibrary { "machineLearning": MessageLookupByLibrary.simpleMessage("Machine learning"), "magicSearch": MessageLookupByLibrary.simpleMessage("Волшебный поиск"), + "magicSearchHint": MessageLookupByLibrary.simpleMessage( + "Умный поиск позволяет искать фотографии по их содержимому, например, \'цветок\', \'красная машина\', \'паспорт\', \'документы\'"), "manage": MessageLookupByLibrary.simpleMessage("Управление"), "manageDeviceStorage": MessageLookupByLibrary.simpleMessage( "Управление хранилищем устройства"), @@ -1005,6 +1009,18 @@ class MessageLookup extends MessageLookupByLibrary { "matrix": MessageLookupByLibrary.simpleMessage("Matrix"), "memoryCount": m0, "merchandise": MessageLookupByLibrary.simpleMessage("Товары"), + "mlConsent": + MessageLookupByLibrary.simpleMessage("Включить машинное обучение"), + "mlConsentConfirmation": MessageLookupByLibrary.simpleMessage( + "Я понимаю и хочу включить машинное обучение"), + "mlConsentDescription": MessageLookupByLibrary.simpleMessage( + "Если вы включите машинное обучение, Ente будет извлекать информацию из файлов (например, геометрию лица), включая те, которыми с вами поделились.\n\nЭто будет происходить на вашем устройстве, и любая сгенерированная биометрическая информация будет зашифрована с использованием сквозного (End-to-End) шифрования между вашим устройством и сервером."), + "mlConsentPrivacy": MessageLookupByLibrary.simpleMessage( + "Пожалуйста, нажмите здесь, чтобы узнать больше об этой функции в нашей политике конфиденциальности"), + "mlConsentTitle": + MessageLookupByLibrary.simpleMessage("Включить машинное обучение?"), + "mlIndexingDescription": MessageLookupByLibrary.simpleMessage( + "Обратите внимание, что машинное обучение приведёт к повышенному потреблению трафика и батареи, пока все элементы не будут проиндексированы. Рекомендуем использовать ПК версию для более быстрого индексирования. Полученные результаты будут синхронизированы автоматически между устройствами."), "mobileWebDesktop": MessageLookupByLibrary.simpleMessage("Телефон, Web, ПК"), "moderateStrength": MessageLookupByLibrary.simpleMessage("Средний"), @@ -1303,6 +1319,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Восстановить в альбоме"), "restoringFiles": MessageLookupByLibrary.simpleMessage("Восстановление файлов..."), + "resumableUploads": MessageLookupByLibrary.simpleMessage( + "Поддержка дозагрузки файл(а/ов) при разрыве связи"), "retry": MessageLookupByLibrary.simpleMessage("Повторить"), "reviewDeduplicateItems": MessageLookupByLibrary.simpleMessage( "Пожалуйста, проверьте и удалите те элементы, которые вы считаете что это дубликаты."), @@ -1609,13 +1627,14 @@ class MessageLookup extends MessageLookupByLibrary { "twofactorAuthenticationSuccessfullyReset": MessageLookupByLibrary.simpleMessage( "Двухфакторная аутентификация успешно сброшена"), - "twofactorSetup": MessageLookupByLibrary.simpleMessage( - "Установка двуфакторной аутентификации"), + "twofactorSetup": MessageLookupByLibrary.simpleMessage("Вход с 2FA"), "unarchive": MessageLookupByLibrary.simpleMessage("Разархивировать"), "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("Разархивировать альбом"), "unarchiving": MessageLookupByLibrary.simpleMessage("Разархивирование..."), + "unavailableReferralCode": MessageLookupByLibrary.simpleMessage( + "Извините, такого кода не существует."), "uncategorized": MessageLookupByLibrary.simpleMessage("Без категории"), "unhide": MessageLookupByLibrary.simpleMessage("Показать"), "unhideToAlbum": diff --git a/mobile/lib/generated/intl/messages_sv.dart b/mobile/lib/generated/intl/messages_sv.dart index 16f3eafe48..cd4bfa6c7d 100644 --- a/mobile/lib/generated/intl/messages_sv.dart +++ b/mobile/lib/generated/intl/messages_sv.dart @@ -167,8 +167,6 @@ class MessageLookup extends MessageLookupByLibrary { "confirm": MessageLookupByLibrary.simpleMessage("Bekräfta"), "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage("Bekräfta radering av konto"), - "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "Ja, jag vill ta bort detta konto och all data permanent."), "confirmPassword": MessageLookupByLibrary.simpleMessage("Bekräfta lösenord"), "confirmRecoveryKey": MessageLookupByLibrary.simpleMessage( @@ -272,6 +270,7 @@ class MessageLookup extends MessageLookupByLibrary { "goToSettings": MessageLookupByLibrary.simpleMessage("Gå till inställningar"), "guestView": MessageLookupByLibrary.simpleMessage("Gästvy"), + "help": MessageLookupByLibrary.simpleMessage("Hjälp"), "howItWorks": MessageLookupByLibrary.simpleMessage("Så här fungerar det"), "howToViewShareeVerificationID": MessageLookupByLibrary.simpleMessage( diff --git a/mobile/lib/generated/intl/messages_ta.dart b/mobile/lib/generated/intl/messages_ta.dart new file mode 100644 index 0000000000..30c00c6d72 --- /dev/null +++ b/mobile/lib/generated/intl/messages_ta.dart @@ -0,0 +1,53 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a ta locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'ta'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "accountWelcomeBack": + MessageLookupByLibrary.simpleMessage("மீண்டும் வருக!"), + "askDeleteReason": MessageLookupByLibrary.simpleMessage( + "உங்கள் கணக்கை நீக்குவதற்கான முக்கிய காரணம் என்ன?"), + "cancel": MessageLookupByLibrary.simpleMessage("ரத்து செய்"), + "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage( + "கணக்கு நீக்குதலை உறுதிப்படுத்தவும்"), + "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( + "ஆம், எல்லா செயலிகளிலும் இந்தக் கணக்கையும் அதன் தரவையும் நிரந்தரமாக நீக்க விரும்புகிறேன்."), + "deleteAccount": MessageLookupByLibrary.simpleMessage("கணக்கை நீக்கு"), + "deleteAccountFeedbackPrompt": MessageLookupByLibrary.simpleMessage( + "நீங்கள் வெளியேறுவதை கண்டு வருந்துகிறோம். எங்களை மேம்படுத்த உதவ உங்கள் கருத்தைப் பகிரவும்."), + "deleteAccountPermanentlyButton": + MessageLookupByLibrary.simpleMessage("கணக்கை நிரந்தரமாக நீக்கவும்"), + "deleteReason1": MessageLookupByLibrary.simpleMessage( + "எனக்கு தேவையான ஒரு முக்கிய அம்சம் இதில் இல்லை"), + "email": MessageLookupByLibrary.simpleMessage("மின்னஞ்சல்"), + "enterValidEmail": MessageLookupByLibrary.simpleMessage( + "சரியான மின்னஞ்சல் முகவரியை உள்ளிடவும்."), + "enterYourEmailAddress": MessageLookupByLibrary.simpleMessage( + "உங்கள் மின்னஞ்சல் முகவரியை உள்ளிடவும்"), + "feedback": MessageLookupByLibrary.simpleMessage("பின்னூட்டம்"), + "invalidEmailAddress": + MessageLookupByLibrary.simpleMessage("தவறான மின்னஞ்சல் முகவரி"), + "kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage( + "இந்த தகவலுடன் தயவுசெய்து எங்களுக்கு உதவுங்கள்"), + "verify": MessageLookupByLibrary.simpleMessage("சரிபார்க்கவும்") + }; +} diff --git a/mobile/lib/generated/intl/messages_th.dart b/mobile/lib/generated/intl/messages_th.dart index a1bc4df70a..1f16b0b2ab 100644 --- a/mobile/lib/generated/intl/messages_th.dart +++ b/mobile/lib/generated/intl/messages_th.dart @@ -99,8 +99,6 @@ class MessageLookup extends MessageLookupByLibrary { "confirm": MessageLookupByLibrary.simpleMessage("ยืนยัน"), "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage("ยืนยันการลบบัญชี"), - "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "ใช่ ฉันต้องการลบบัญชีนี้และข้อมูลที่เกี่ยวข้องทั้งหมดแบบถาวร"), "confirmPassword": MessageLookupByLibrary.simpleMessage("ยืนยันรหัสผ่าน"), "confirmRecoveryKey": diff --git a/mobile/lib/generated/intl/messages_tr.dart b/mobile/lib/generated/intl/messages_tr.dart index fd82236d0d..b5eb2a4e7e 100644 --- a/mobile/lib/generated/intl/messages_tr.dart +++ b/mobile/lib/generated/intl/messages_tr.dart @@ -432,8 +432,6 @@ class MessageLookup extends MessageLookupByLibrary { "İki adımlı kimlik doğrulamasını devre dışı bırakmak istediğinize emin misiniz?"), "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage("Hesap silme işlemini onayla"), - "confirmDeletePrompt": MessageLookupByLibrary.simpleMessage( - "Evet, bu hesabı ve tüm verileri kalıcı olarak silmek istiyorum."), "confirmPassword": MessageLookupByLibrary.simpleMessage("Şifrenizi onaylayın"), "confirmPlanChange": MessageLookupByLibrary.simpleMessage( diff --git a/mobile/lib/generated/intl/messages_zh.dart b/mobile/lib/generated/intl/messages_zh.dart index 2a34fee561..acb22b6465 100644 --- a/mobile/lib/generated/intl/messages_zh.dart +++ b/mobile/lib/generated/intl/messages_zh.dart @@ -350,6 +350,9 @@ class MessageLookup extends MessageLookupByLibrary { "backupOverMobileData": MessageLookupByLibrary.simpleMessage("通过移动数据备份"), "backupSettings": MessageLookupByLibrary.simpleMessage("备份设置"), + "backupStatus": MessageLookupByLibrary.simpleMessage("备份状态"), + "backupStatusDescription": + MessageLookupByLibrary.simpleMessage("已备份的项目将显示在此处"), "backupVideos": MessageLookupByLibrary.simpleMessage("备份视频"), "blackFridaySale": MessageLookupByLibrary.simpleMessage("黑色星期五特惠"), "blog": MessageLookupByLibrary.simpleMessage("博客"), @@ -439,7 +442,7 @@ class MessageLookup extends MessageLookupByLibrary { "confirmAccountDeletion": MessageLookupByLibrary.simpleMessage("确认删除账户"), "confirmDeletePrompt": - MessageLookupByLibrary.simpleMessage("是的,我想永久删除此账户及其相关数据."), + MessageLookupByLibrary.simpleMessage("是的,我想永久删除此账户及其所有关联的应用程序的数据。"), "confirmPassword": MessageLookupByLibrary.simpleMessage("请确认密码"), "confirmPlanChange": MessageLookupByLibrary.simpleMessage("确认更改计划"), "confirmRecoveryKey": MessageLookupByLibrary.simpleMessage("确认恢复密钥"), diff --git a/mobile/lib/generated/l10n.dart b/mobile/lib/generated/l10n.dart index e12296fb2c..c023f17710 100644 --- a/mobile/lib/generated/l10n.dart +++ b/mobile/lib/generated/l10n.dart @@ -6569,6 +6569,26 @@ class S { ); } + /// `Preserving {count} memories...` + String uploadingMultipleMemories(Object count) { + return Intl.message( + 'Preserving $count memories...', + name: 'uploadingMultipleMemories', + desc: '', + args: [count], + ); + } + + /// `Preserving 1 memory...` + String get uploadingSingleMemory { + return Intl.message( + 'Preserving 1 memory...', + name: 'uploadingSingleMemory', + desc: '', + args: [], + ); + } + /// `Archiving...` String get archiving { return Intl.message( @@ -9547,6 +9567,7 @@ class AppLocalizationDelegate extends LocalizationsDelegate { Locale.fromSubtags(languageCode: 'pt'), Locale.fromSubtags(languageCode: 'ru'), Locale.fromSubtags(languageCode: 'sv'), + Locale.fromSubtags(languageCode: 'ta'), Locale.fromSubtags(languageCode: 'te'), Locale.fromSubtags(languageCode: 'th'), Locale.fromSubtags(languageCode: 'ti'), diff --git a/mobile/lib/l10n/intl_en.arb b/mobile/lib/l10n/intl_en.arb index c252714447..7cc11a8f68 100644 --- a/mobile/lib/l10n/intl_en.arb +++ b/mobile/lib/l10n/intl_en.arb @@ -937,6 +937,8 @@ "encryptingBackup": "Encrypting backup...", "syncStopped": "Sync stopped", "syncProgress": "{completed}/{total} memories preserved", + "uploadingMultipleMemories" : "Preserving {count} memories...", + "uploadingSingleMemory": "Preserving 1 memory...", "@syncProgress": { "description": "Text to tell user how many memories have been preserved", "placeholders": { diff --git a/mobile/lib/l10n/intl_he.arb b/mobile/lib/l10n/intl_he.arb index 9342d8cf07..3e1960a83b 100644 --- a/mobile/lib/l10n/intl_he.arb +++ b/mobile/lib/l10n/intl_he.arb @@ -215,7 +215,8 @@ "after1Month": "אחרי חודש 1", "after1Year": "אחרי שנה 1", "manageParticipants": "נהל", - "albumParticipantsCount": "{count, plural, one {} two {{count} משתתפים} many {{count} משתתפים}=0 {אין משתתפים} =1 {1 משתתף} other {{count} משתתפים}}", + "albumParticipantsCount": "{count, plural, =0 {אין משתתפים} =1 {1 משתתף} two {2 משתתפים} other {{count} משתתפים}}", + "@albumParticipantsCount": { "placeholders": { "count": { @@ -236,7 +237,7 @@ "publicLinkEnabled": "לינק ציבורי אופשר", "shareALink": "שתף קישור", "sharedAlbumSectionDescription": "צור אלבומים הניתנים לשיתוף ושיתוף פעולה עם משתמשי ente אחרים, כולל משתמשים בתוכניות החינמיות.", - "shareWithPeopleSectionTitle": "{numberOfPeople, plural, one {} two {שותף עם {numberOfPeople} אנשים} many {שותף עם {numberOfPeople} אנשים}=0 {שתף עם אנשים ספציפיים} =1 {שותף עם איש 1} other {שותף עם {numberOfPeople} אנשים}}", + "shareWithPeopleSectionTitle": "{numberOfPeople, plural, =0 {שתף עם אנשים ספציפיים} =1 {שותף עם איש 1} two {שותף עם 2 אנשים} other {שותף עם {numberOfPeople} אנשים}}", "@shareWithPeopleSectionTitle": { "placeholders": { "numberOfPeople": { @@ -408,7 +409,7 @@ "skip": "דלג", "updatingFolderSelection": "מעדכן את בחירת התיקיות...", "itemCount": "{count, plural, one{{count} פריט} two {{count} פריטים} many {{count} פריטים} other{{count} פריטים}}", - "deleteItemCount": "{count, plural, one {} two {מחק {count} פריטים} many {מחק {count} פריטים}=1 {מחק {count} פריט} other {מחק {count} פריטים}}", + "deleteItemCount": "{count, plural, =1 {מחק {count} פריט} two {מחק {count} פריטים} other {מחק {count} פריטים}}", "duplicateItemsGroup": "{count} קבצים, כל אחד {formattedSize}", "@duplicateItemsGroup": { "description": "Display the number of duplicate files and their size", diff --git a/mobile/lib/l10n/intl_no.arb b/mobile/lib/l10n/intl_no.arb index 1319dca79c..4a66be1e01 100644 --- a/mobile/lib/l10n/intl_no.arb +++ b/mobile/lib/l10n/intl_no.arb @@ -215,7 +215,7 @@ "after1Month": "Etter 1 måned", "after1Year": "Etter 1 år", "manageParticipants": "Administrer", - "albumParticipantsCount": "{count, plural, one {}=0 {Ingen deltakere} =1 {1 Deltaker} other {{count} Deltakere}}", + "albumParticipantsCount": "{count, plural, =0 {Ingen deltakere} =1 {1 deltaker} other {{count} deltakere}}", "@albumParticipantsCount": { "placeholders": { "count": { @@ -233,7 +233,8 @@ "linkHasExpired": "Lenken har utløpt", "publicLinkEnabled": "Offentlig lenke aktivert", "shareALink": "Del en lenke", - "shareWithPeopleSectionTitle": "{numberOfPeople, plural, one {}=0 {Del med bestemte personer} =1 {Delt med 1 person} other {Delt med {numberOfPeople} personer}}", + "shareWithPeopleSectionTitle": "{numberOfPeople, plural, =0 {Del med bestemte personer} =1 {Delt med 1 person} other {Delt med {numberOfPeople} personer}}", + "@shareWithPeopleSectionTitle": { "placeholders": { "numberOfPeople": { diff --git a/mobile/lib/l10n/intl_sv.arb b/mobile/lib/l10n/intl_sv.arb index bfb0e0291a..4455c38fc5 100644 --- a/mobile/lib/l10n/intl_sv.arb +++ b/mobile/lib/l10n/intl_sv.arb @@ -236,7 +236,7 @@ "publicLinkEnabled": "Offentlig länk aktiverad", "shareALink": "Dela en länk", "sharedAlbumSectionDescription": "Skapa delade och samarbetande album med andra Ente användare, inklusive användare med gratisnivån.", - "shareWithPeopleSectionTitle": "{numberOfPeople, plural, one {}=0 {Dela med specifika personer} =1 {Delad med en person} other {Delad med {numberOfPeople} personer}}", + "shareWithPeopleSectionTitle": "{numberOfPeople, plural, =0 {Dela med specifika personer} =1 {Delad med en person} other {Delad med {numberOfPeople} personer}}", "@shareWithPeopleSectionTitle": { "placeholders": { "numberOfPeople": { From 187a149716a4ee3c1c9e10eadb05f97d0d4e3f47 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Mon, 2 Sep 2024 15:26:57 +0530 Subject: [PATCH 199/275] [mob] Show total memory count to upload --- mobile/lib/services/remote_sync_service.dart | 4 +++- mobile/lib/ui/home/status_bar_widget.dart | 13 ++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/mobile/lib/services/remote_sync_service.dart b/mobile/lib/services/remote_sync_service.dart index eab8478a6c..c1348ba45f 100644 --- a/mobile/lib/services/remote_sync_service.dart +++ b/mobile/lib/services/remote_sync_service.dart @@ -581,7 +581,9 @@ class RemoteSyncService { _ignoredUploads = 0; final int toBeUploaded = filesToBeUploaded.length + updatedFileIDs.length; if (toBeUploaded > 0) { - Bus.instance.fire(SyncStatusUpdate(SyncStatus.preparingForUpload)); + Bus.instance.fire( + SyncStatusUpdate(SyncStatus.preparingForUpload, total: toBeUploaded), + ); await _uploader.verifyMediaLocationAccess(); await _uploader.checkNetworkForUpload(); // verify if files upload is allowed based on their subscription plan and diff --git a/mobile/lib/ui/home/status_bar_widget.dart b/mobile/lib/ui/home/status_bar_widget.dart index 461a92a1c9..d676a42945 100644 --- a/mobile/lib/ui/home/status_bar_widget.dart +++ b/mobile/lib/ui/home/status_bar_widget.dart @@ -231,6 +231,9 @@ class RefreshIndicatorWidget extends StatelessWidget { } String _getRefreshingText(BuildContext context) { + if (event == null) { + return S.of(context).loadingGallery; + } if (event!.status == SyncStatus.startedFirstGalleryImport || event!.status == SyncStatus.completedFirstGalleryImport) { return S.of(context).loadingGallery; @@ -239,7 +242,15 @@ class RefreshIndicatorWidget extends StatelessWidget { return S.of(context).syncing; } if (event!.status == SyncStatus.preparingForUpload) { - return S.of(context).encryptingBackup; + if (event!.total == null || event!.total! <= 0) { + return S.of(context).encryptingBackup; + } else if (event!.total == 1) { + return S.of(context).uploadingSingleMemory; + } else { + return S + .of(context) + .uploadingMultipleMemories(NumberFormat().format(event!.total!)); + } } if (event!.status == SyncStatus.inProgress) { final format = NumberFormat(); From 30d5fedb11d9ec49c246a257c45a7dcc1acf1d3a Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Mon, 2 Sep 2024 15:19:44 +0530 Subject: [PATCH 200/275] sort by photo date --- .../new/photos/services/ml/cluster.ts | 41 ++++++++++++++++++- web/packages/new/photos/services/ml/index.ts | 13 +++--- web/packages/new/photos/services/ml/worker.ts | 6 ++- 3 files changed, 53 insertions(+), 7 deletions(-) diff --git a/web/packages/new/photos/services/ml/cluster.ts b/web/packages/new/photos/services/ml/cluster.ts index 254988dea9..0b7de59b59 100644 --- a/web/packages/new/photos/services/ml/cluster.ts +++ b/web/packages/new/photos/services/ml/cluster.ts @@ -1,6 +1,8 @@ +import { assertionFailed } from "@/base/assert"; import { newNonSecureID } from "@/base/id-worker"; import log from "@/base/log"; import { ensure } from "@/utils/ensure"; +import type { EnteFile } from "../../types/file"; import { type EmbeddingCluster, clusterHdbscan } from "./cluster-hdb"; import type { Face, FaceIndex } from "./face"; import { dotProduct } from "./math"; @@ -175,6 +177,7 @@ export interface ClusterPreviewFace { */ export const clusterFaces = ( faceIndexes: FaceIndex[], + localFiles: EnteFile[], opts: ClusteringOpts, ) => { const { @@ -187,13 +190,33 @@ export const clusterFaces = ( } = opts; const t = Date.now(); + const localFileByID = new Map(localFiles.map((f) => [f.id, f])); + // A flattened array of faces. const allFaces = [...enumerateFaces(faceIndexes)]; - const faces = allFaces + const filteredFaces = allFaces .filter((f) => f.blur > minBlur) .filter((f) => f.score > minScore); // .slice(0, 2000); + const fileForFaceID = new Map( + filteredFaces.map(({ faceID }) => [ + faceID, + ensure(localFileByID.get(ensure(fileIDFromFaceID(faceID)))), + ]), + ); + + const fileForFace = ({ faceID }: Face) => ensure(fileForFaceID.get(faceID)); + + // Sort faces so that photos taken temporally close together are close. + // + // This is a heuristic to help the clustering algorithm produce better results. + const faces = filteredFaces.sort( + (a, b) => + fileForFace(a).metadata.creationTime - + fileForFace(b).metadata.creationTime, + ); + // For fast reverse lookup - map from face ids to the face. const faceForFaceID = new Map(faces.map((f) => [f.faceID, f])); @@ -382,6 +405,7 @@ export const clusterFaces = ( filteredFaceCount, clusteredFaceCount, unclusteredFaceCount, + localFileByID, clusterPreviews, clusters: sortedClusters, cgroups, @@ -402,6 +426,21 @@ function* enumerateFaces(faceIndices: FaceIndex[]) { } } +/** + * Extract the fileID of the {@link EnteFile} to which the face belongs from its + * faceID. + * + * TODO-Cluster - duplicated with ml/index.ts + */ +const fileIDFromFaceID = (faceID: string) => { + const fileID = parseInt(faceID.split("_")[0] ?? ""); + if (isNaN(fileID)) { + assertionFailed(`Ignoring attempt to parse invalid faceID ${faceID}`); + return undefined; + } + return fileID; +}; + interface ClusterLinearResult { clusters: EmbeddingCluster[]; } diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 3bb6bb3eaf..37d961b165 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -16,7 +16,6 @@ import { ensure } from "@/utils/ensure"; import { throttled } from "@/utils/promise"; import { proxy, transfer } from "comlink"; import { isInternalUser } from "../feature-flags"; -import { getAllLocalFiles } from "../files"; import { getRemoteFlag, updateRemoteFlag } from "../remote-store"; import type { SearchPerson } from "../search/types"; import type { UploadItem } from "../upload/types"; @@ -381,11 +380,15 @@ export const wipClusterDebugPageContents = async ( _wip_searchPersons = undefined; triggerStatusUpdate(); - const { clusterPreviews, clusters, cgroups, unclusteredFaces, ...rest } = - await worker().then((w) => w.clusterFaces(opts)); + const { + localFileByID, + clusterPreviews, + clusters, + cgroups, + unclusteredFaces, + ...rest + } = await worker().then((w) => w.clusterFaces(opts)); - const localFiles = await getAllLocalFiles(); - const localFileByID = new Map(localFiles.map((f) => [f.id, f])); const fileForFace = ({ faceID }: Face) => ensure(localFileByID.get(ensure(fileIDFromFaceID(faceID)))); diff --git a/web/packages/new/photos/services/ml/worker.ts b/web/packages/new/photos/services/ml/worker.ts index c663abc2c9..391dc672f7 100644 --- a/web/packages/new/photos/services/ml/worker.ts +++ b/web/packages/new/photos/services/ml/worker.ts @@ -277,7 +277,11 @@ export class MLWorker { // TODO-Cluster async clusterFaces(opts: ClusteringOpts) { - return clusterFaces(await faceIndexes(), opts); + return clusterFaces( + await faceIndexes(), + await getAllLocalFiles(), + opts, + ); } } From ba083fff70b1664456f23bcb43ca9aba97209af6 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Mon, 2 Sep 2024 12:45:08 +0200 Subject: [PATCH 201/275] [mob][photos] exception handlign works in isolate --- mobile/lib/ui/settings/ml/ml_user_dev_screen.dart | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/mobile/lib/ui/settings/ml/ml_user_dev_screen.dart b/mobile/lib/ui/settings/ml/ml_user_dev_screen.dart index 1f75c95d5b..c50ede988f 100644 --- a/mobile/lib/ui/settings/ml/ml_user_dev_screen.dart +++ b/mobile/lib/ui/settings/ml/ml_user_dev_screen.dart @@ -62,8 +62,17 @@ class MLUserDeveloperOptions extends StatelessWidget { buttonType: ButtonType.neutral, labelText: "Log something in isolate", onTap: () async { - final boolean = await MLComputer.instance.testLogging(); - showShortToast(context, "Done: $boolean"); + try { + final boolean = + await MLComputer.instance.testLogging(); + showShortToast(context, "Done: $boolean"); + } catch (e) { + // ignore: unawaited_futures + showGenericErrorDialog( + context: context, + error: e, + ); + } }, ), const SafeArea( From da316fdcfd38b9d9d94bc81380d2a2854266b1dd Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Mon, 2 Sep 2024 12:45:30 +0200 Subject: [PATCH 202/275] [mob][photos] refactor --- .../machine_learning/ml_computer.dart | 112 +++++++++--------- 1 file changed, 59 insertions(+), 53 deletions(-) diff --git a/mobile/lib/services/machine_learning/ml_computer.dart b/mobile/lib/services/machine_learning/ml_computer.dart index f0e01d4c7d..91f49925af 100644 --- a/mobile/lib/services/machine_learning/ml_computer.dart +++ b/mobile/lib/services/machine_learning/ml_computer.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import "dart:collection" show Queue; import "dart:io" show File; import 'dart:isolate'; import 'dart:typed_data' show Uint8List; @@ -75,56 +74,62 @@ class MLComputer { final args = message[1] as Map; final sendPort = message[2] as SendPort; + late final Object data; try { - switch (function) { - case MLComputerOperation.generateFaceThumbnails: - final imagePath = args['imagePath'] as String; - final Uint8List imageData = await File(imagePath).readAsBytes(); - final faceBoxesJson = - args['faceBoxesList'] as List>; - final List faceBoxes = - faceBoxesJson.map((json) => FaceBox.fromJson(json)).toList(); - final List results = - await generateFaceThumbnailsUsingCanvas( - imageData, - faceBoxes, - ); - sendPort.send(List.from(results)); - case MLComputerOperation.loadModel: - final modelName = args['modelName'] as String; - final modelPath = args['modelPath'] as String; - final int address = await MlModel.loadModel( - modelName, - modelPath, - ); - sendPort.send(address); - break; - case MLComputerOperation.initializeClipTokenizer: - final vocabPath = args["vocabPath"] as String; - await ClipTextTokenizer.instance.init(vocabPath); - sendPort.send(true); - break; - case MLComputerOperation.runClipText: - //TODO:lau check logging here - final textEmbedding = await ClipTextEncoder.predict(args); - sendPort.send(List.from(textEmbedding, growable: false)); - break; - case MLComputerOperation.testLogging: - final logger = Logger('XXX MLComputerTestLogging'); - logger.info("XXX logging from isolate is working!!!"); - final Queue logStrings = - isolateLogger.getLogStringsAndClear(); - final logs = List.from(logStrings); - sendPort.send({"data": true, "logs": logs}); - break; - } + data = await cases(function, args); } catch (e, stackTrace) { - sendPort - .send({'error': e.toString(), 'stackTrace': stackTrace.toString()}); + data = { + 'error': e.toString(), + 'stackTrace': stackTrace.toString(), + }; } + final logs = List.from(isolateLogger.getLogStringsAndClear()); + sendPort.send({"data": data, "logs": logs}); }); } + /// WARNING: Only return primitives: https://api.flutter.dev/flutter/dart-isolate/SendPort/send.html + static Future cases( + MLComputerOperation function, + Map args, + ) async { + switch (function) { + case MLComputerOperation.generateFaceThumbnails: + final imagePath = args['imagePath'] as String; + final Uint8List imageData = await File(imagePath).readAsBytes(); + final faceBoxesJson = + args['faceBoxesList'] as List>; + final List faceBoxes = + faceBoxesJson.map((json) => FaceBox.fromJson(json)).toList(); + final List results = await generateFaceThumbnailsUsingCanvas( + imageData, + faceBoxes, + ); + return List.from(results); + case MLComputerOperation.loadModel: + final modelName = args['modelName'] as String; + final modelPath = args['modelPath'] as String; + final int address = await MlModel.loadModel( + modelName, + modelPath, + ); + return address; + case MLComputerOperation.initializeClipTokenizer: + final vocabPath = args["vocabPath"] as String; + await ClipTextTokenizer.instance.init(vocabPath); + return true; + case MLComputerOperation.runClipText: + //TODO:lau check logging here + final textEmbedding = await ClipTextEncoder.predict(args); + return List.from(textEmbedding, growable: false); + case MLComputerOperation.testLogging: + final logger = Logger('XXX MLComputerTestLogging'); + logger.info("XXX logging from isolate is working!!!"); + throw Exception("XXX logging from isolate testing exception handling"); + return true; + } + } + /// The common method to run any operation in the isolate. It sends the [message] to [_isolateMain] and waits for the result. Future _runInIsolate( (MLComputerOperation, Map) message, @@ -137,15 +142,18 @@ class MLComputer { _mainSendPort.send([message.$1.index, message.$2, answerPort.sendPort]); answerPort.listen((receivedMessage) { - if (receivedMessage is Map && receivedMessage.containsKey('error')) { + final logs = receivedMessage['logs'] as List; + IsolateLogger.handLogStringsToMainLogger(logs); + final data = receivedMessage['data']; + if (data is Map && data.containsKey('error')) { // Handle the error - final errorMessage = receivedMessage['error']; - final errorStackTrace = receivedMessage['stackTrace']; + final errorMessage = data['error']; + final errorStackTrace = data['stackTrace']; final exception = Exception(errorMessage); final stackTrace = StackTrace.fromString(errorStackTrace); completer.completeError(exception, stackTrace); } else { - completer.complete(receivedMessage); + completer.complete(data); } }); @@ -240,10 +248,8 @@ class MLComputer { MLComputerOperation.testLogging, {}, ), - ) as Map; - final logs = result['logs'] as List; - IsolateLogger.handLogStringsToMainLogger(logs); - return result['data'] as bool; + ) as bool; + return result; } catch (e, s) { _logger.severe("XXX Could not test logging in isolate", e, s); rethrow; From 371dcf8ab9dfefca21555440703e7940d2b2b188 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Mon, 2 Sep 2024 16:47:49 +0530 Subject: [PATCH 203/275] More params --- web/apps/photos/src/pages/cluster-debug.tsx | 28 +++++++++- .../new/photos/services/ml/cluster.ts | 52 ++++++++----------- 2 files changed, 47 insertions(+), 33 deletions(-) diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index d2f921b532..90c0f91c42 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -114,7 +114,9 @@ const OptionsForm: React.FC = ({ onCluster }) => { minScore: 0.8, minClusterSize: 2, joinThreshold: 0.7, - batchSize: 12500, + earlyExitThreshold: 0.2, + batchSize: 10000, + lookbackSize: 2500, }, onSubmit: (values) => onCluster({ @@ -123,7 +125,9 @@ const OptionsForm: React.FC = ({ onCluster }) => { minScore: toFloat(values.minScore), minClusterSize: toFloat(values.minClusterSize), joinThreshold: toFloat(values.joinThreshold), + earlyExitThreshold: toFloat(values.earlyExitThreshold), batchSize: toFloat(values.batchSize), + lookbackSize: toFloat(values.lookbackSize), }), }); @@ -171,6 +175,12 @@ const OptionsForm: React.FC = ({ onCluster }) => { size="small" onChange={handleChange} /> +
+ = ({ onCluster }) => { size="small" onChange={handleChange} /> + = ({ onCluster }) => { size="small" onChange={handleChange} /> +