Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6644be92d9 | ||
|
|
f24fd8aad5 | ||
|
|
0ad6a7379a | ||
|
|
e83c236ca1 | ||
|
|
d4441ddf56 | ||
|
|
a6d8297d67 | ||
|
|
d1ff333930 | ||
|
|
205f121ac0 | ||
|
|
9f52e4fc17 | ||
|
|
b5ff7484b0 | ||
|
|
285da2e770 | ||
|
|
58be05cd67 |
No files matched your search
@@ -2,6 +2,38 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. For commit guidelines, please refer to [Standard Version](https://github.com/conventional-changelog/standard-version).
|
||||
|
||||
## v0.7.3-beta
|
||||
|
||||
Note: OIDC changes require config update.
|
||||
|
||||
**New Features**
|
||||
- Added code highlights to text editor and enabled text editor for all asci files under 25MB
|
||||
- Motion previews for videos -- cycles screenshots of vidoes. https://github.com/gtsteffaniak/filebrowser/issues/588
|
||||
- Optionally reset default admin username/password on startup, to guarentee a username/password on startup if needed. Use by setting `auth.resetAdminOnStart` true https://github.com/gtsteffaniak/filebrowser/issues/625
|
||||
|
||||
**Notes**:
|
||||
- Updated translations everywhere. https://github.com/gtsteffaniak/filebrowser/issues/627
|
||||
- Office viewer is now full-screen with floating close button. https://github.com/gtsteffaniak/filebrowser/issues/542
|
||||
- OIDC config additions
|
||||
- `issuerUrl` required now to get relevant oidc configurations.
|
||||
- `disableVerifyTLS` optionally, disable verifying HTTPS provider endpoints.
|
||||
- `logoutRedirectUrl` optionally, redirect the user to this URL on logout.
|
||||
- other URL config parameters are no longer accepted -- replace with issuerUrl.
|
||||
- Aadmins allowed to change user login methods in user settings when creating or updating users.
|
||||
- https://github.com/gtsteffaniak/filebrowser/issues/618
|
||||
- https://github.com/gtsteffaniak/filebrowser/issues/617
|
||||
- Hide header when showing only office https://github.com/gtsteffaniak/filebrowser/issues/542
|
||||
|
||||
**BugFixes**:
|
||||
- Editor save shows notification
|
||||
- Preview settings resetting on startup
|
||||
- Not all languages show correctly https://github.com/gtsteffaniak/filebrowser/issues/623
|
||||
- scopes sometimes reset on startup https://github.com/gtsteffaniak/filebrowser/issues/636
|
||||
- Update save password option
|
||||
- https://github.com/gtsteffaniak/filebrowser/issues/587
|
||||
- https://github.com/gtsteffaniak/filebrowser/issues/619
|
||||
- https://github.com/gtsteffaniak/filebrowser/issues/615
|
||||
|
||||
## v0.7.2-beta
|
||||
|
||||
The `media` tags introduced in 0.7.0 have been removed -- all docker images have media enabled now.
|
||||
|
||||
@@ -100,19 +100,19 @@ See the [Migration Wiki](https://github.com/gtsteffaniak/filebrowser/wiki/Migrat
|
||||
|
||||
Application Name | <img width="48" src="https://github.com/user-attachments/assets/59986a2a-f960-4536-aa35-4a9a7c98ad48" > Quantum | <img width="48" src="https://github.com/filebrowser/filebrowser/blob/master/frontend/public/img/logo.svg" > Filebrowser | <img width="48" src="https://github.com/mickael-kerjean/filestash/blob/master/public/assets/logo/app_icon.png?raw=true" > Filestash | <img width="48" src="https://avatars.githubusercontent.com/u/19211038?s=200&v=4" > Nextcloud | <img width="48" src="https://upload.wikimedia.org/wikipedia/commons/thumb/d/da/Google_Drive_logo.png/480px-Google_Drive_logo.png" > Google_Drive | <img width="48" src="https://avatars.githubusercontent.com/u/6422152?v=4" > FileRun
|
||||
--- | --- | --- | --- | --- | --- | --- |
|
||||
Filesystem support | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
Filesystem support | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
||||
Linux | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
|
||||
Windows | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
Mac | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
Windows | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
||||
Mac | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
||||
Self hostable | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
|
||||
Has Stable Release? | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
S3 support | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ |
|
||||
S3 support | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ |
|
||||
webdav support | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ |
|
||||
FTP support | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ |
|
||||
Dedicated docs site? | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ |
|
||||
Multiple sources at once | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ |
|
||||
Docker image size | 200 MB (with ffmpeg) | 31 MB | 240 MB (main image) | 250 MB | ❌ | > 2 GB |
|
||||
Min. Memory Requirements | 256 MB | 128 MB | 128 MB (main image) | 128 MB | ❌ | 4 GB |
|
||||
Min. Memory Requirements | 256 MB | 128 MB | 128 MB (main image) | 512 MB | ❌ | 512 MB |
|
||||
has standalone binary | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
price | free | free | free | free tier | free tier | $99+ |
|
||||
rich media preview | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
@@ -127,7 +127,7 @@ LDAP sign-on support | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ |
|
||||
Long-live API key support | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ |
|
||||
API documentation page | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ |
|
||||
Mobile App | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ |
|
||||
open source? | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
|
||||
open source? | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
tags support | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ |
|
||||
shareable web links? | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
Event-based notifications | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
|
||||
@@ -148,4 +148,4 @@ Can archive selected files | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
|
||||
Can browse archive files | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
|
||||
Can convert documents | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
|
||||
Can convert videos | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
Can convert photos | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
Can convert photos | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
@@ -68,16 +68,16 @@ func FileInfoFaster(opts iteminfo.FileOptions) (iteminfo.ExtendedFileInfo, error
|
||||
if !exists {
|
||||
return response, fmt.Errorf("could not get metadata for path: %v", opts.Path)
|
||||
}
|
||||
if opts.Content && strings.HasPrefix(info.Type, "text") {
|
||||
// Check file size
|
||||
if info.Size > 50*1024*1024 { // 50 megabytes in bytes
|
||||
logger.Debug(fmt.Sprintf("Reading large text file contents: "+info.Path, info.Name))
|
||||
if opts.Content {
|
||||
if info.Size < 20*1024*1024 { // 20 megabytes in bytes
|
||||
content, err := getContent(realPath)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
response.Content = content
|
||||
} else {
|
||||
logger.Debug(fmt.Sprintf("skipping large text file contents (20MB limit): "+info.Path, info.Name))
|
||||
}
|
||||
content, err := getContent(realPath)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
response.Content = content
|
||||
}
|
||||
response.FileInfo = *info
|
||||
response.RealPath = realPath
|
||||
@@ -268,12 +268,35 @@ func WriteFile(opts iteminfo.FileOptions, in io.Reader) error {
|
||||
return idx.RefreshFileInfo(opts)
|
||||
}
|
||||
|
||||
// addContent reads and sets content based on the file type.
|
||||
// getContent reads and returns the file content only if it's ASCII-readable.
|
||||
func getContent(realPath string) (string, error) {
|
||||
const headerSize = 4096
|
||||
|
||||
// Open file
|
||||
f, err := os.Open(realPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Read header
|
||||
buf := make([]byte, headerSize)
|
||||
n, err := f.Read(buf)
|
||||
if err != nil && err != io.EOF {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Check if header is ASCII
|
||||
if !isASCII(buf[:n]) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Now read full file
|
||||
content, err := os.ReadFile(realPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
stringContent := string(content)
|
||||
if !utf8.ValidString(stringContent) {
|
||||
return "", nil
|
||||
@@ -284,6 +307,15 @@ func getContent(realPath string) (string, error) {
|
||||
return stringContent, nil
|
||||
}
|
||||
|
||||
func isASCII(data []byte) bool {
|
||||
for _, b := range data {
|
||||
if b < 0x09 || (b > 0x0D && b < 0x20) || b > 0x7E {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func IsNamedPipe(mode os.FileMode) bool {
|
||||
return mode&os.ModeNamedPipe != 0
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ type HookAuth struct {
|
||||
// Auth authenticates the user via a json in content body.
|
||||
func (a *HookAuth) Auth(r *http.Request, usr *users.Storage) (*users.User, error) {
|
||||
var cred hookCred
|
||||
|
||||
if r.Body == nil {
|
||||
return nil, os.ErrPermission
|
||||
}
|
||||
@@ -52,6 +51,8 @@ func (a *HookAuth) Auth(r *http.Request, usr *users.Storage) (*users.User, error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logger.Debug(fmt.Sprintf("hook auth %v", action))
|
||||
|
||||
switch action {
|
||||
case "auth":
|
||||
u, err := a.SaveUser()
|
||||
@@ -167,7 +168,7 @@ func (a *HookAuth) SaveUser() (*users.User, error) {
|
||||
}
|
||||
u = a.GetUser(d)
|
||||
|
||||
err = a.Users.Save(u, false)
|
||||
err = a.Users.Save(u, false, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -2,65 +2,82 @@
|
||||
== Running benchmark ==
|
||||
/usr/local/go/bin/go
|
||||
? github.com/gtsteffaniak/filebrowser/backend [no test files]
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/adapters/fs/diskcache 0.004s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/adapters/fs/files 0.006s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/adapters/fs/fileutils 0.003s
|
||||
? github.com/gtsteffaniak/filebrowser/backend/auth [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/backend/cmd [no test files]
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/adapters/fs/diskcache 0.005s
|
||||
? github.com/gtsteffaniak/filebrowser/backend/common/cache [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/backend/common/errors [no test files]
|
||||
/home/graham/git/filebrowser /home/graham/git/filebrowser
|
||||
/home/graham/git/filebrowser/files/file.go /home/graham/git/filebrowser
|
||||
/home/graham/git/filebrowser/mnt/doesnt/exist /home/graham/git/filebrowser
|
||||
2025/01/04 14:04:55 Initializing index and assessing file system complexity
|
||||
2025/01/04 14:04:55 Starting full scan
|
||||
2025/01/04 14:04:55 Index assessment : complexity=simple directories=0 files=0
|
||||
2025/01/04 14:04:55 Time Spent Indexing : 0 seconds
|
||||
2025/01/04 14:04:55 Next scan in 1m0s
|
||||
2025/01/04 14:04:56 Initializing index and assessing file system complexity
|
||||
2025/01/04 14:04:56 Starting full scan
|
||||
2025/01/04 14:04:56 Index assessment : complexity=simple directories=0 files=0
|
||||
2025/01/04 14:04:56 Time Spent Indexing : 0 seconds
|
||||
2025/01/04 14:04:56 Next scan in 1m0s
|
||||
goos: linux
|
||||
goarch: amd64
|
||||
pkg: github.com/gtsteffaniak/filebrowser/backend/adapters/fs/files
|
||||
cpu: 11th Gen Intel(R) Core(TM) i5-11320H @ 3.20GHz
|
||||
BenchmarkFillIndex-8 2025/01/04 14:04:57 Initializing index and assessing file system complexity
|
||||
2025/01/04 14:04:57 Starting full scan
|
||||
2025/01/04 14:04:57 Index assessment : complexity=simple directories=0 files=0
|
||||
2025/01/04 14:04:57 Time Spent Indexing : 0 seconds
|
||||
2025/01/04 14:04:57 Next scan in 1m0s
|
||||
10 3515090 ns/op 34273 B/op 451 allocs/op
|
||||
BenchmarkCheckIndexExclude-8 10 156.2 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkCheckIndexConditionsInclude-8 10 98.00 ns/op 0 B/op 0 allocs/op
|
||||
2025/01/04 14:04:58 Initializing index and assessing file system complexity
|
||||
2025/01/04 14:04:58 Starting full scan
|
||||
2025/01/04 14:04:58 Index assessment : complexity=simple directories=0 files=0
|
||||
2025/01/04 14:04:58 Time Spent Indexing : 0 seconds
|
||||
2025/01/04 14:04:58 Next scan in 1m0s
|
||||
BenchmarkSearchAllIndexes-8 2025/01/04 14:04:59 Initializing index and assessing file system complexity
|
||||
2025/01/04 14:04:59 Starting full scan
|
||||
2025/01/04 14:04:59 Index assessment : complexity=simple directories=0 files=0
|
||||
2025/01/04 14:04:59 Time Spent Indexing : 0 seconds
|
||||
2025/01/04 14:04:59 Next scan in 1m0s
|
||||
10 766822 ns/op 34230 B/op 900 allocs/op
|
||||
? github.com/gtsteffaniak/filebrowser/backend/common/logger [no test files]
|
||||
2025/05/11 20:42:56 Using OnlyOffice secret from FILEBROWSER_ONLYOFFICE_SECRET environment variable
|
||||
2025/05/11 20:42:56 Using OnlyOffice secret from FILEBROWSER_ONLYOFFICE_SECRET environment variable
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/adapters/fs/files 5.094s
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/common/settings 0.006s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/adapters/fs/fileutils 0.002s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/http 0.184s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/preview/img 0.123s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/runner 0.004s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/common/settings 0.005s
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/common/utils 0.003s
|
||||
? github.com/gtsteffaniak/filebrowser/backend/common/version [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/backend/database/share [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/backend/database/storage [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/backend/database/storage/bolt [no test files]
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/database/users 0.002s
|
||||
? github.com/gtsteffaniak/filebrowser/backend/events [no test files]
|
||||
2025/05/11 20:42:56 [DEBUG] Saving user [admin] changepass: true
|
||||
2025/05/11 20:42:56 [DEBUG] Saving user [non-admin] changepass: true
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/http 0.197s
|
||||
2025/05/11 20:42:57 initializing index: [test]
|
||||
2025/05/11 20:42:57 [DEBUG] Skipping source update event for mock index.
|
||||
2025/05/11 20:42:57 [DEBUG] Starting full scan for [test]
|
||||
2025/05/11 20:42:57 Index assessment : [test] complexity=simple directories=0 files=0
|
||||
2025/05/11 20:42:57 [DEBUG] Time spent indexing [test]: 0 seconds
|
||||
2025/05/11 20:42:57 [DEBUG] Skipping source update event for mock index.
|
||||
2025/05/11 20:42:57 [DEBUG] Next scan in 1m0s
|
||||
2025/05/11 20:42:58 initializing index: [test]
|
||||
2025/05/11 20:42:58 [DEBUG] Skipping source update event for mock index.
|
||||
2025/05/11 20:42:58 [DEBUG] Starting full scan for [test]
|
||||
2025/05/11 20:42:58 Index assessment : [test] complexity=simple directories=0 files=0
|
||||
2025/05/11 20:42:58 [DEBUG] Time spent indexing [test]: 0 seconds
|
||||
2025/05/11 20:42:58 [DEBUG] Skipping source update event for mock index.
|
||||
2025/05/11 20:42:58 [DEBUG] Next scan in 1m0s
|
||||
goos: linux
|
||||
goarch: amd64
|
||||
pkg: github.com/gtsteffaniak/filebrowser/backend/indexing
|
||||
cpu: 11th Gen Intel(R) Core(TM) i5-11320H @ 3.20GHz
|
||||
BenchmarkFillIndex-8 2025/05/11 20:42:59 initializing index: [test]
|
||||
2025/05/11 20:42:59 [DEBUG] Skipping source update event for mock index.
|
||||
2025/05/11 20:42:59 [DEBUG] Starting full scan for [test]
|
||||
2025/05/11 20:42:59 Index assessment : [test] complexity=simple directories=0 files=0
|
||||
2025/05/11 20:42:59 [DEBUG] Time spent indexing [test]: 0 seconds
|
||||
2025/05/11 20:42:59 [DEBUG] Skipping source update event for mock index.
|
||||
2025/05/11 20:42:59 [DEBUG] Next scan in 1m0s
|
||||
10 3548759 ns/op 38032 B/op 452 allocs/op
|
||||
BenchmarkCheckIndexExclude-8 10 172.6 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkCheckIndexConditionsInclude-8 10 118.2 ns/op 0 B/op 0 allocs/op
|
||||
2025/05/11 20:43:01 initializing index: [test]
|
||||
2025/05/11 20:43:01 [DEBUG] Skipping source update event for mock index.
|
||||
2025/05/11 20:43:01 [DEBUG] Starting full scan for [test]
|
||||
2025/05/11 20:43:01 Index assessment : [test] complexity=simple directories=0 files=0
|
||||
2025/05/11 20:43:01 [DEBUG] Time spent indexing [test]: 0 seconds
|
||||
2025/05/11 20:43:01 [DEBUG] Skipping source update event for mock index.
|
||||
2025/05/11 20:43:01 [DEBUG] Next scan in 1m0s
|
||||
BenchmarkSearchAllIndexes-8 2025/05/11 20:43:02 initializing index: [test]
|
||||
2025/05/11 20:43:02 [DEBUG] Skipping source update event for mock index.
|
||||
2025/05/11 20:43:02 [DEBUG] Starting full scan for [test]
|
||||
2025/05/11 20:43:02 Index assessment : [test] complexity=simple directories=0 files=0
|
||||
2025/05/11 20:43:02 [DEBUG] Time spent indexing [test]: 0 seconds
|
||||
2025/05/11 20:43:02 [DEBUG] Skipping source update event for mock index.
|
||||
2025/05/11 20:43:02 [DEBUG] Next scan in 1m0s
|
||||
10 781119 ns/op 38515 B/op 900 allocs/op
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/indexing 5.097s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/indexing/iteminfo 0.005s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/preview 0.128s
|
||||
? github.com/gtsteffaniak/filebrowser/backend/swagger/docs [no test files]
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/database/users 0.003s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/backend/common/utils 0.002s
|
||||
? github.com/gtsteffaniak/filebrowser/backend/common/version [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/backend/tools [no test files]
|
||||
+1
-1
@@ -107,7 +107,7 @@ func runCLI() bool {
|
||||
if asAdmin {
|
||||
user.Permissions.Admin = true
|
||||
}
|
||||
err = store.Users.Save(user, true)
|
||||
err = store.Users.Save(user, true, false)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("could not update user: %v", err))
|
||||
}
|
||||
|
||||
+46
-72
@@ -2,7 +2,7 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"reflect"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/backend/adapters/fs/fileutils"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/logger"
|
||||
@@ -44,98 +44,72 @@ func validateUserInfo() {
|
||||
logger.Fatal(fmt.Sprintf("Unable to create automatic backup of database due to error: %v", err))
|
||||
}
|
||||
}
|
||||
err := store.Users.Save(user, false)
|
||||
err := store.Users.Save(user, false, true)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("could not update user: %v", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
if settings.Config.Auth.ResetAdminOnStart {
|
||||
logger.Info("Resetting admin user to default username and password.")
|
||||
adminUser, err := store.Users.Get(1)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Sprintf("could not load admin user: %v", err))
|
||||
}
|
||||
adminUser.Username = settings.Config.Auth.AdminUsername
|
||||
adminUser.Password = settings.Config.Auth.AdminPassword
|
||||
adminUser.Permissions.Admin = true
|
||||
err = store.Users.Save(adminUser, true, true)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("could not Save admin user: %v", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateUserScopes(user *users.User) bool {
|
||||
updateUser := false
|
||||
finalScopes := []users.SourceScope{}
|
||||
seenNames := make(map[string]bool)
|
||||
newScopes := []users.SourceScope{}
|
||||
seen := make(map[string]bool)
|
||||
|
||||
// Step 1: Start by including all existing scopes, updating Name if source.Path matches
|
||||
for _, existingScope := range user.Scopes {
|
||||
if existingScope.Scope != "/" {
|
||||
existingScope.Scope = strings.TrimSuffix(existingScope.Scope, "/")
|
||||
}
|
||||
if existingScope.Scope == "" {
|
||||
updateUser = true
|
||||
continue
|
||||
}
|
||||
if !seenNames[existingScope.Name] {
|
||||
finalScopes = append(finalScopes, existingScope)
|
||||
seenNames[existingScope.Name] = true
|
||||
}
|
||||
// Build map for existing scopes by Name
|
||||
existing := make(map[string]users.SourceScope)
|
||||
for _, s := range user.Scopes {
|
||||
existing[s.Name] = s
|
||||
}
|
||||
|
||||
// Step 2: Add missing scopes from SourceMap if admin or DefaultEnabled
|
||||
for _, source := range settings.Config.Server.SourceMap {
|
||||
if seenNames[source.Path] {
|
||||
// Preserve order by using Config.Server.Sources
|
||||
for _, src := range settings.Config.Server.Sources {
|
||||
realsource, ok := settings.Config.Server.NameToSource[src.Name]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
// Check if scope exists already via path
|
||||
scopePath, _ := settings.GetScopeFromSourcePath(user.Scopes, source.Path)
|
||||
if scopePath == "" {
|
||||
// must be new scope for user
|
||||
// If user has no access, skip unless default-enabled
|
||||
if !source.Config.DefaultEnabled {
|
||||
continue
|
||||
}
|
||||
// Determine scope path
|
||||
if scopePath == "" {
|
||||
scopePath = source.Config.DefaultUserScope
|
||||
}
|
||||
if scopePath == "" {
|
||||
scopePath = "/"
|
||||
}
|
||||
if scopePath != "/" {
|
||||
scopePath = strings.TrimSuffix(scopePath, "/")
|
||||
existingScope, ok := existing[realsource.Path]
|
||||
if ok {
|
||||
// If scope is empty and there's a default, apply default
|
||||
if existingScope.Scope == "" {
|
||||
existingScope.Scope = src.Config.DefaultUserScope
|
||||
}
|
||||
} else if realsource.Config.DefaultEnabled {
|
||||
existingScope.Scope = realsource.Config.DefaultUserScope
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
||||
// Add new scope
|
||||
finalScopes = append(finalScopes, users.SourceScope{
|
||||
Scope: scopePath,
|
||||
Name: source.Path,
|
||||
newScopes = append(newScopes, users.SourceScope{
|
||||
Name: realsource.Path,
|
||||
Scope: existingScope.Scope,
|
||||
})
|
||||
seenNames[source.Path] = true
|
||||
updateUser = true
|
||||
seen[realsource.Path] = true
|
||||
}
|
||||
|
||||
// Step 3: If no scopes, apply default
|
||||
if len(finalScopes) == 0 {
|
||||
defaultScope := users.SourceScope{
|
||||
Scope: settings.Config.Server.DefaultSource.Config.DefaultUserScope,
|
||||
Name: settings.Config.Server.DefaultSource.Path,
|
||||
}
|
||||
finalScopes = append(finalScopes, defaultScope)
|
||||
updateUser = true
|
||||
}
|
||||
|
||||
// Step 4: Assign only if different
|
||||
if !scopesEqual(user.Scopes, finalScopes) {
|
||||
user.Scopes = finalScopes
|
||||
updateUser = true
|
||||
}
|
||||
|
||||
return updateUser
|
||||
}
|
||||
|
||||
// scopesEqual does a deep comparison to avoid unnecessary writes
|
||||
func scopesEqual(a, b []users.SourceScope) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i := range a {
|
||||
if a[i].Scope != b[i].Scope || a[i].Name != b[i].Name {
|
||||
return false
|
||||
// Preserve user-defined scopes not matching current sources, append to end
|
||||
for _, s := range user.Scopes {
|
||||
if !seen[s.Name] {
|
||||
newScopes = append(newScopes, s)
|
||||
}
|
||||
}
|
||||
return true
|
||||
changed := !reflect.DeepEqual(user.Scopes, newScopes)
|
||||
user.Scopes = newScopes
|
||||
return changed
|
||||
}
|
||||
|
||||
// func to convert legacy user with perm key to permissions
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/settings"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/database/users"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUpdateUserScopes_Phases(t *testing.T) {
|
||||
|
||||
sourceA := settings.Source{Path: "/pathA", Name: "sourceA", Config: settings.SourceConfig{
|
||||
DefaultEnabled: false,
|
||||
DefaultUserScope: "/defaultA",
|
||||
}}
|
||||
sourceB := settings.Source{Path: "/pathB", Name: "sourceB", Config: settings.SourceConfig{DefaultEnabled: true, DefaultUserScope: "/defaultB"}}
|
||||
settings.Config.Server.Sources = []settings.Source{sourceA, sourceB}
|
||||
settings.Config.Server.DefaultSource = sourceB
|
||||
settings.Config.Server.SourceMap = map[string]settings.Source{
|
||||
"/pathA": sourceA,
|
||||
"/pathB": sourceB,
|
||||
}
|
||||
settings.Config.Server.NameToSource = map[string]settings.Source{
|
||||
"sourceA": sourceA,
|
||||
"sourceB": sourceB,
|
||||
}
|
||||
|
||||
// ---------------------
|
||||
// Test Cases Definition
|
||||
// ---------------------
|
||||
testCases := []struct {
|
||||
name string
|
||||
user *users.User
|
||||
expectedPhase1 []users.SourceScope
|
||||
expectedPhase2 []users.SourceScope
|
||||
}{
|
||||
{
|
||||
name: "Single valid scope",
|
||||
user: &users.User{
|
||||
Scopes: []users.SourceScope{
|
||||
{Scope: "/home", Name: "/pathA"},
|
||||
},
|
||||
},
|
||||
expectedPhase1: []users.SourceScope{
|
||||
{Scope: "/home", Name: "/pathA"},
|
||||
{Scope: "/defaultB", Name: "/pathB"},
|
||||
},
|
||||
expectedPhase2: []users.SourceScope{
|
||||
{Scope: "/home", Name: "/pathA"},
|
||||
{Scope: "/defaultB", Name: "/pathB"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Single empty scope path",
|
||||
user: &users.User{
|
||||
Scopes: []users.SourceScope{
|
||||
{Scope: "", Name: "/pathB"},
|
||||
},
|
||||
},
|
||||
expectedPhase1: []users.SourceScope{
|
||||
{Scope: "/defaultB", Name: "/pathB"},
|
||||
},
|
||||
expectedPhase2: []users.SourceScope{
|
||||
{Scope: "/defaultA", Name: "/pathA"},
|
||||
{Scope: "/defaultB", Name: "/pathB"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Two scopes, one includes username in path",
|
||||
user: &users.User{
|
||||
Username: "user123",
|
||||
Scopes: []users.SourceScope{
|
||||
{Scope: "/home/user123", Name: "/pathA"},
|
||||
{Scope: "/data", Name: "/pathB"},
|
||||
},
|
||||
},
|
||||
expectedPhase1: []users.SourceScope{
|
||||
{Scope: "/home/user123", Name: "/pathA"},
|
||||
{Scope: "/data", Name: "/pathB"},
|
||||
},
|
||||
expectedPhase2: []users.SourceScope{
|
||||
{Scope: "/home/user123", Name: "/pathA"},
|
||||
{Scope: "/data", Name: "/pathB"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Two scopes, one with empty name",
|
||||
user: &users.User{
|
||||
Scopes: []users.SourceScope{
|
||||
{Scope: "/home", Name: "/pathB"},
|
||||
{Scope: "/data", Name: "/somethingElse"},
|
||||
},
|
||||
},
|
||||
expectedPhase1: []users.SourceScope{
|
||||
{Scope: "/home", Name: "/pathB"},
|
||||
{Scope: "/data", Name: "/somethingElse"},
|
||||
},
|
||||
expectedPhase2: []users.SourceScope{
|
||||
{Scope: "/defaultA", Name: "/pathA"},
|
||||
{Scope: "/home", Name: "/pathB"},
|
||||
{Scope: "/data", Name: "/somethingElse"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "No scopes at all",
|
||||
user: &users.User{
|
||||
Scopes: []users.SourceScope{},
|
||||
},
|
||||
expectedPhase1: []users.SourceScope{
|
||||
{Scope: "/defaultB", Name: "/pathB"},
|
||||
},
|
||||
expectedPhase2: []users.SourceScope{
|
||||
{Scope: "/defaultA", Name: "/pathA"},
|
||||
{Scope: "/defaultB", Name: "/pathB"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "All user Scope and source change",
|
||||
user: &users.User{
|
||||
Username: "user123",
|
||||
Scopes: []users.SourceScope{
|
||||
{Scope: "/defaultC/user123", Name: "/pathC"},
|
||||
{Scope: "/defaultA/user123", Name: "/pathA"},
|
||||
{Scope: "/defaultB/user123", Name: "/pathB"},
|
||||
},
|
||||
},
|
||||
expectedPhase1: []users.SourceScope{
|
||||
{Scope: "/defaultA/user123", Name: "/pathA"},
|
||||
{Scope: "/defaultB/user123", Name: "/pathB"},
|
||||
{Scope: "/defaultC/user123", Name: "/pathC"},
|
||||
},
|
||||
expectedPhase2: []users.SourceScope{
|
||||
{Scope: "/defaultA/user123", Name: "/pathA"},
|
||||
{Scope: "/defaultB/user123", Name: "/pathB"},
|
||||
{Scope: "/defaultC/user123", Name: "/pathC"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// ---------------------
|
||||
// Phase 1 Tests
|
||||
// ---------------------
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name+"_Phase1", func(t *testing.T) {
|
||||
originalScopes := tc.user.Scopes
|
||||
updated := updateUserScopes(tc.user)
|
||||
assert.Equal(t, tc.expectedPhase1, tc.user.Scopes, "Phase1 scope mismatch for test case: %s", tc.name)
|
||||
assert.Equal(t, updated, !reflect.DeepEqual(originalScopes, tc.user.Scopes), "Phase2 scope change detection failed:\t %s vs expected:\t %s", tc.user.Scopes, tc.expectedPhase1)
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------
|
||||
// Phase 2: rename sources but keep same paths
|
||||
// ---------------------
|
||||
sourceA = settings.Source{Path: "/pathA", Name: "sourceA", Config: settings.SourceConfig{
|
||||
DefaultEnabled: true,
|
||||
DefaultUserScope: "/defaultA",
|
||||
CreateUserDir: true,
|
||||
}}
|
||||
sourceB = settings.Source{Path: "/pathB", Name: "sourceB", Config: settings.SourceConfig{DefaultEnabled: true, DefaultUserScope: "/defaultB"}}
|
||||
settings.Config.Server.Sources = []settings.Source{sourceA, sourceB}
|
||||
settings.Config.Server.DefaultSource = sourceB
|
||||
settings.Config.Server.SourceMap = map[string]settings.Source{
|
||||
"/pathA": sourceA,
|
||||
"/pathB": sourceB,
|
||||
}
|
||||
settings.Config.Server.NameToSource = map[string]settings.Source{
|
||||
"sourceA": sourceA,
|
||||
"sourceB": sourceB,
|
||||
}
|
||||
|
||||
// Run again without resetting user objects to test idempotency + renaming
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name+"_Phase2", func(t *testing.T) {
|
||||
originalScopes := tc.user.Scopes
|
||||
updated := updateUserScopes(tc.user)
|
||||
assert.Equal(t, tc.expectedPhase2, tc.user.Scopes, "Phase2 scope mismatch for test case: %s", tc.name)
|
||||
assert.Equal(t, updated, !reflect.DeepEqual(originalScopes, tc.user.Scopes), "Phase2 scope change detection failed:\t %s vs expected:\t %s", tc.user.Scopes, tc.expectedPhase1)
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package logger
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"slices"
|
||||
"time"
|
||||
)
|
||||
@@ -21,7 +22,7 @@ const (
|
||||
RED = "\033[31m"
|
||||
GREEN = "\033[32m"
|
||||
YELLOW = "\033[33m"
|
||||
GRAY = "\033[37m"
|
||||
GRAY = "\033[2;37m"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -72,9 +73,6 @@ func Log(level string, msg string, prefix, api bool, color string) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if logger.stdout && level == "FATAL" {
|
||||
continue
|
||||
}
|
||||
writeOut := msg
|
||||
formattedTime := time.Now().Format("2006/01/02 15:04:05")
|
||||
if logger.colors && color != "" {
|
||||
@@ -92,12 +90,16 @@ func Log(level string, msg string, prefix, api bool, color string) {
|
||||
if err != nil {
|
||||
log.Printf("failed to log message '%v' with error `%v`", msg, err)
|
||||
}
|
||||
if level == levels.FATAL {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Api(msg string, statusCode int) {
|
||||
// redirects are not warnings anymore
|
||||
if statusCode > 302 && statusCode < 500 {
|
||||
// content not modified is not a warning anymore
|
||||
if statusCode > 304 && statusCode < 500 {
|
||||
Log(levels.WARNING, msg, false, true, YELLOW)
|
||||
} else if statusCode >= 500 {
|
||||
Log(levels.ERROR, msg, false, true, RED)
|
||||
@@ -142,6 +144,7 @@ func Error(msg string) {
|
||||
func Fatal(msg string) {
|
||||
if len(loggers) > 0 {
|
||||
Log(levels.FATAL, msg, true, false, RED)
|
||||
} else {
|
||||
log.Fatal("[FATAL] ", msg)
|
||||
}
|
||||
log.Fatal("[FATAL] ", msg)
|
||||
}
|
||||
@@ -1,11 +1,23 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/logger"
|
||||
)
|
||||
|
||||
type Auth struct {
|
||||
TokenExpirationHours int `json:"tokenExpirationHours"` // the number of hours until the token expires. Default is 2 hours.
|
||||
Methods LoginMethods `json:"methods"`
|
||||
Key string `json:"key"` // the key used to sign the JWT tokens. If not set, a random key will be generated.
|
||||
AdminUsername string `json:"adminUsername"` // the username of the admin user. If not set, the default is "admin".
|
||||
AdminPassword string `json:"adminPassword"` // the password of the admin user. If not set, the default is "admin".
|
||||
Key string `json:"key"` // the key used to sign the JWT tokens. If not set, a random key will be generated.
|
||||
AdminUsername string `json:"adminUsername"` // the username of the admin user. If not set, the default is "admin".
|
||||
AdminPassword string `json:"adminPassword"` // the password of the admin user. If not set, the default is "admin".
|
||||
ResetAdminOnStart bool `json:"resetAdminOnStart"` // if set to true, the admin user will be reset to the default username and password on startup.
|
||||
AuthMethods []string `json:"-"`
|
||||
}
|
||||
|
||||
@@ -37,13 +49,55 @@ type Recaptcha struct {
|
||||
|
||||
// OpenID OAuth2.0
|
||||
type OidcConfig struct {
|
||||
Enabled bool `json:"enabled"` // whether to enable OIDC authentication
|
||||
ClientID string `json:"clientId" validate:"required"` // client id of the OIDC application
|
||||
ClientSecret string `json:"clientSecret" validate:"required"` // client secret of the OIDC application
|
||||
AuthorizationUrl string `json:"authorizationUrl" validate:"required"` // authorization URL of the OIDC provider
|
||||
TokenUrl string `json:"tokenUrl" validate:"required"` // token URL of the OIDC provider
|
||||
UserInfoUrl string `json:"userInfoUrl" validate:"required"` // user info URL of the OIDC provider
|
||||
Scopes string `json:"scopes" validate:"required"` // space separated list of scopes to request from the OIDC provider
|
||||
UserIdentifier string `json:"userIdentifier"` // optional: which attribute should be used as the username? options: email, username, name, phone_number, sub
|
||||
JwksUrl string `json:"jwksUrl"` // currently not used by filebrowser
|
||||
Enabled bool `json:"enabled"` // whether to enable OIDC authentication
|
||||
ClientID string `json:"clientId"` // client id of the OIDC application
|
||||
ClientSecret string `json:"clientSecret"` // client secret of the OIDC application
|
||||
IssuerUrl string `json:"issuerUrl"` // authorization URL of the OIDC provider
|
||||
Scopes string `json:"scopes"` // scopes to request from the OIDC provider
|
||||
UserIdentifier string `json:"userIdentifier"` // the user identifier to use for authentication. Default is "username", can be "email" or "username", or "phone"
|
||||
DisableVerifyTLS bool `json:"disableVerifyTLS"` // disable TLS verification for the OIDC provider. This is insecure and should only be used for testing.
|
||||
LogoutRedirectUrl string `json:"logoutRedirectUrl"` // if provider logout url is provided, filebrowser will also redirect to logout url. Custom logout query params are respected.
|
||||
Provider *oidc.Provider `json:"-"` // OIDC provider
|
||||
Verifier *oidc.IDTokenVerifier `json:"-"` // OIDC verifier
|
||||
}
|
||||
|
||||
// ValidateOidcAuth processes the OIDC callback and retrieves user identity
|
||||
func validateOidcAuth() error {
|
||||
oidcCfg := &Config.Auth.Methods.OidcAuth // Use a pointer to modify the original config
|
||||
if !oidcCfg.Enabled {
|
||||
return errors.New("OIDC is not enabled")
|
||||
}
|
||||
if oidcCfg.UserIdentifier == "" {
|
||||
oidcCfg.UserIdentifier = "username"
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// If disableVerifyTLS is true, create a custom HTTP client
|
||||
// and set it in the context for the OIDC provider.
|
||||
if oidcCfg.DisableVerifyTLS {
|
||||
// Create a custom transport with InsecureSkipVerify set to true
|
||||
transport := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
customClient := &http.Client{
|
||||
Transport: transport,
|
||||
}
|
||||
// Use oidc.ClientContext to pass the custom client to the OIDC library
|
||||
ctx = oidc.ClientContext(ctx, customClient)
|
||||
// Log that TLS verification is disabled (important for security awareness)
|
||||
logger.Warning("OIDC TLS verification is disabled.")
|
||||
}
|
||||
|
||||
provider, err := oidc.NewProvider(ctx, oidcCfg.IssuerUrl)
|
||||
if err != nil {
|
||||
return fmt.Errorf("url '%v' failed to create OIDC provider: %w", oidcCfg.IssuerUrl, err)
|
||||
}
|
||||
oidcCfg.Provider = provider
|
||||
oidcCfg.Verifier = provider.Verifier(&oidc.Config{ClientID: oidcCfg.ClientID})
|
||||
if oidcCfg.Scopes == "" {
|
||||
oidcCfg.Scopes = "openid email profile"
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -24,10 +24,9 @@ func Initialize(configFile string) {
|
||||
}
|
||||
err = ValidateConfig(Config)
|
||||
if err != nil {
|
||||
errmsg := "the provided config file failed validation. "
|
||||
errmsg := "The provided config file failed validation. "
|
||||
errmsg += "If you are seeing this on a config that worked previeously, "
|
||||
errmsg += "this is because v0.6.8 requires a fully validated config to run. "
|
||||
errmsg += "Please review your config for typos and invalid keys which are no longer supported. "
|
||||
errmsg += "please review your config for typos and invalid keys which are no longer supported. "
|
||||
errmsg += "visit https://github.com/gtsteffaniak/filebrowser/wiki/Full-Config-Example for more information."
|
||||
logger.Error(errmsg)
|
||||
logger.Fatal(err.Error())
|
||||
@@ -145,23 +144,33 @@ func setupUrls() {
|
||||
|
||||
func setupAuth() {
|
||||
if Config.Auth.Methods.PasswordAuth.Enabled {
|
||||
Config.Auth.AuthMethods = append(Config.Auth.AuthMethods, "Password")
|
||||
Config.Auth.AuthMethods = append(Config.Auth.AuthMethods, "password")
|
||||
}
|
||||
if Config.Auth.Methods.ProxyAuth.Enabled {
|
||||
Config.Auth.AuthMethods = append(Config.Auth.AuthMethods, "Proxy")
|
||||
Config.Auth.AuthMethods = append(Config.Auth.AuthMethods, "proxy")
|
||||
}
|
||||
if Config.Auth.Methods.OidcAuth.Enabled {
|
||||
Config.Auth.AuthMethods = append(Config.Auth.AuthMethods, "OIDC")
|
||||
Config.Auth.AuthMethods = append(Config.Auth.AuthMethods, "oidc")
|
||||
}
|
||||
if Config.Auth.Methods.NoAuth {
|
||||
logger.Warning("Configured with no authentication, this is not recommended.")
|
||||
Config.Auth.AuthMethods = []string{"Disabled"}
|
||||
Config.Auth.AuthMethods = []string{"disabled"}
|
||||
}
|
||||
if Config.Auth.Methods.OidcAuth.Enabled {
|
||||
err := validateOidcAuth()
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Sprintf("Error validating OIDC auth: %v", err))
|
||||
}
|
||||
logger.Info("OIDC Auth configured successfully")
|
||||
}
|
||||
|
||||
// use password auth as default if no auth methods are set
|
||||
if len(Config.Auth.AuthMethods) == 0 {
|
||||
Config.Auth.Methods.PasswordAuth.Enabled = true
|
||||
Config.Auth.AuthMethods = append(Config.Auth.AuthMethods, "Password")
|
||||
Config.Auth.AuthMethods = append(Config.Auth.AuthMethods, "password")
|
||||
}
|
||||
Config.UserDefaults.LoginMethod = Config.Auth.AuthMethods[0]
|
||||
|
||||
}
|
||||
|
||||
func setupLogging() {
|
||||
|
||||
@@ -46,6 +46,7 @@ func ApplyUserDefaults(u *users.User) {
|
||||
u.ViewMode = Config.UserDefaults.ViewMode
|
||||
u.SingleClick = Config.UserDefaults.SingleClick
|
||||
u.Permissions = Config.UserDefaults.Permissions
|
||||
u.Preview = Config.UserDefaults.Preview
|
||||
u.ShowHidden = Config.UserDefaults.ShowHidden
|
||||
u.DateFormat = Config.UserDefaults.DateFormat
|
||||
u.DisableOnlyOfficeExt = Config.UserDefaults.DisableOnlyOfficeExt
|
||||
|
||||
@@ -110,20 +110,21 @@ type ExternalLink struct {
|
||||
// UserDefaults is a type that holds the default values
|
||||
// for some fields on User.
|
||||
type UserDefaults struct {
|
||||
PreviewOptions users.PreviewOptions `json:"preview"`
|
||||
StickySidebar bool `json:"stickySidebar"`
|
||||
DarkMode bool `json:"darkMode"`
|
||||
LockPassword bool `json:"lockPassword"`
|
||||
DisableSettings bool `json:"disableSettings,omitempty"`
|
||||
Locale string `json:"locale"`
|
||||
ViewMode string `json:"viewMode"`
|
||||
GallerySize int `json:"gallerySize"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
Permissions users.Permissions `json:"permissions"`
|
||||
ShowHidden bool `json:"showHidden"`
|
||||
DateFormat bool `json:"dateFormat"`
|
||||
ThemeColor string `json:"themeColor"`
|
||||
QuickDownload bool `json:"quickDownload"`
|
||||
DisableOnlyOfficeExt string `json:"disableOnlyOfficeExt"`
|
||||
DefaultScopes []users.SourceScope `json:"-"`
|
||||
StickySidebar bool `json:"stickySidebar"` // keep sidebar open when navigating
|
||||
DarkMode bool `json:"darkMode"` // should dark mode be enabled
|
||||
Locale string `json:"locale"` // language to use: eg. de, en, or fr
|
||||
ViewMode string `json:"viewMode"` // view mode to use: eg. normal, list, grid, or compact
|
||||
SingleClick bool `json:"singleClick"` // open directory on single click, also enables middle click to open in new tab
|
||||
ShowHidden bool `json:"showHidden"` // show hidden files in the UI. On windows this includes files starting with a dot and windows hidden files
|
||||
DateFormat bool `json:"dateFormat"` // when false, the date is relative, when true, the date is an exact timestamp
|
||||
GallerySize int `json:"gallerySize"` // 0-9 - the size of the gallery thumbnails
|
||||
ThemeColor string `json:"themeColor"` // theme color to use: eg. #ff0000, or var(--red), var(--purple), etc
|
||||
QuickDownload bool `json:"quickDownload"` // show icon to download in one click
|
||||
DisableOnlyOfficeExt string `json:"disableOnlyOfficeExt"` // comma separated list of file extensions to disable onlyoffice preview for
|
||||
LockPassword bool `json:"lockPassword"` // disable the user from changing their password
|
||||
DisableSettings bool `json:"disableSettings,omitempty"` // disable the user from viewing the settings page
|
||||
Preview users.Preview `json:"preview"`
|
||||
DefaultScopes []users.SourceScope `json:"-"`
|
||||
Permissions users.Permissions `json:"permissions"`
|
||||
LoginMethod string `json:"loginMethod,omitempty"` // login method to use: eg. password, proxy, oidc
|
||||
}
|
||||
@@ -32,6 +32,7 @@ func (st usersBackend) GetBy(i interface{}) (user *users.User, err error) {
|
||||
arg = "ID"
|
||||
case int:
|
||||
val = uint(i)
|
||||
arg = "ID"
|
||||
case string:
|
||||
arg = "Username"
|
||||
val = i
|
||||
@@ -136,7 +137,7 @@ func (st usersBackend) Update(user *users.User, actorIsAdmin bool, fields ...str
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st usersBackend) Save(user *users.User, changePass bool) error {
|
||||
func (st usersBackend) Save(user *users.User, changePass, disableScopeChange bool) error {
|
||||
if user.LoginMethod == "" {
|
||||
user.LoginMethod = users.LoginMethodPassword
|
||||
}
|
||||
@@ -159,13 +160,13 @@ func (st usersBackend) Save(user *users.User, changePass bool) error {
|
||||
return err
|
||||
}
|
||||
user.Scopes = adjustedScopes
|
||||
err = files.MakeUserDirs(user, false)
|
||||
err = files.MakeUserDirs(user, disableScopeChange)
|
||||
if err != nil {
|
||||
logger.Error(err.Error())
|
||||
}
|
||||
err = st.db.Save(user)
|
||||
if err == storm.ErrAlreadyExists {
|
||||
return errors.ErrExist
|
||||
return fmt.Errorf("user with provided username already exists")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
storm "github.com/asdine/storm/v3"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/auth"
|
||||
@@ -33,13 +34,16 @@ func InitializeDb(path string) (*Storage, bool, error) {
|
||||
panic(err)
|
||||
}
|
||||
db, err := storm.Open(path)
|
||||
|
||||
utils.CheckErr(fmt.Sprintf("storm.Open path %v", path), err)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "timeout") {
|
||||
logger.Fatal("the database is locked, please close all other instances of filebrowser before starting.")
|
||||
}
|
||||
logger.Fatal(fmt.Sprintf("could not open database: %v", err))
|
||||
}
|
||||
authStore, userStore, shareStore, settingsStore, err := bolt.NewStorage(db)
|
||||
if err != nil {
|
||||
return nil, exists, err
|
||||
}
|
||||
|
||||
err = bolt.Save(db, "version", 2)
|
||||
if err != nil {
|
||||
return nil, exists, err
|
||||
@@ -98,15 +102,26 @@ func quickSetup(store *Storage) {
|
||||
user.LockPassword = false
|
||||
user.Permissions = settings.AdminPerms()
|
||||
logger.Debug(fmt.Sprintf("Creating user as admin: %v %v", user.Username, user.Password))
|
||||
err = store.Users.Save(user, true)
|
||||
err = store.Users.Save(user, true, true)
|
||||
utils.CheckErr("store.Users.Save", err)
|
||||
}
|
||||
|
||||
// create new user
|
||||
func CreateUser(userInfo users.User, asAdmin bool) error {
|
||||
newUser := &userInfo
|
||||
if userInfo.LoginMethod == "password" {
|
||||
if userInfo.Password != "" {
|
||||
return errors.ErrInvalidRequestParams
|
||||
}
|
||||
} else {
|
||||
hashpass, err := users.HashPwd(userInfo.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
userInfo.Password = hashpass
|
||||
}
|
||||
// must have username or password to create
|
||||
if userInfo.Username == "" || userInfo.Password == "" {
|
||||
if userInfo.Username == "" {
|
||||
return errors.ErrInvalidRequestParams
|
||||
}
|
||||
logger.Debug(fmt.Sprintf("Creating user: %v %v", userInfo.Username, userInfo.Scopes))
|
||||
@@ -115,7 +130,7 @@ func CreateUser(userInfo users.User, asAdmin bool) error {
|
||||
userInfo.Permissions = settings.AdminPerms()
|
||||
}
|
||||
// create new home directories
|
||||
err := store.Users.Save(newUser, true)
|
||||
err := store.Users.Save(newUser, true, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
type StorageBackend interface {
|
||||
GetBy(interface{}) (*User, error)
|
||||
Gets() ([]*User, error)
|
||||
Save(u *User, changePass bool) error
|
||||
Save(u *User, changePass bool, disableScopeChange bool) error
|
||||
Update(u *User, adminActor bool, fields ...string) error
|
||||
DeleteByID(uint) error
|
||||
DeleteByUsername(string) error
|
||||
@@ -22,7 +22,7 @@ type Store interface {
|
||||
Get(id interface{}) (user *User, err error)
|
||||
Gets() ([]*User, error)
|
||||
Update(user *User, adminActor bool, fields ...string) error
|
||||
Save(user *User, changePass bool) error
|
||||
Save(user *User, changePass bool, disableScopeChange bool) error
|
||||
Delete(id interface{}) error
|
||||
LastUpdate(id uint) int64
|
||||
AddApiKey(username uint, name string, key AuthToken) error
|
||||
@@ -114,8 +114,8 @@ func (s *Storage) DeleteApiKey(userID uint, name string) error {
|
||||
}
|
||||
|
||||
// Save saves the user in a storage.
|
||||
func (s *Storage) Save(user *User, changePass bool) error {
|
||||
return s.back.Save(user, changePass)
|
||||
func (s *Storage) Save(user *User, changePass, disableScopeChange bool) error {
|
||||
return s.back.Save(user, changePass, disableScopeChange)
|
||||
}
|
||||
|
||||
// Delete allows you to delete a user by its name or username. The provided
|
||||
|
||||
@@ -40,12 +40,13 @@ type Sorting struct {
|
||||
Asc bool `json:"asc"`
|
||||
}
|
||||
|
||||
type PreviewOptions struct {
|
||||
HighQuality bool `json:"highQuality"`
|
||||
Image bool `json:"image"`
|
||||
Video bool `json:"video"`
|
||||
Office bool `json:"office"`
|
||||
PopUp bool `json:"popup"`
|
||||
type Preview struct {
|
||||
HighQuality bool `json:"highQuality"` // generate high quality preview images
|
||||
Image bool `json:"image"` // show real image as icon instead of generic photo icon
|
||||
Video bool `json:"video"` // show preview image for video files
|
||||
MotionVideoPreview bool `json:"motionVideoPreview"` // show multiple frames for videos in preview when hovering
|
||||
Office bool `json:"office"` // show preview image for office files
|
||||
PopUp bool `json:"popup"` // show larger popup preview when hovering
|
||||
}
|
||||
|
||||
// User describes a user.
|
||||
@@ -69,21 +70,22 @@ type SourceScope struct {
|
||||
Scope string `json:"scope"`
|
||||
}
|
||||
|
||||
// json tags must match variable name with smaller case first letter
|
||||
type NonAdminEditable struct {
|
||||
Preview PreviewOptions `json:"preview"`
|
||||
StickySidebar bool `json:"stickySidebar"`
|
||||
DarkMode bool `json:"darkMode"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Locale string `json:"locale"`
|
||||
ViewMode string `json:"viewMode"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
Sorting Sorting `json:"sorting"`
|
||||
ShowHidden bool `json:"showHidden"`
|
||||
DateFormat bool `json:"dateFormat"`
|
||||
GallerySize int `json:"gallerySize"`
|
||||
ThemeColor string `json:"themeColor"`
|
||||
QuickDownload bool `json:"quickDownload"`
|
||||
DisableOnlyOfficeExt string `json:"disableOnlyOfficeExt"`
|
||||
Preview Preview `json:"preview"`
|
||||
StickySidebar bool `json:"stickySidebar"` // keep sidebar open when navigating
|
||||
DarkMode bool `json:"darkMode"` // should dark mode be enabled
|
||||
Password string `json:"password,omitempty"`
|
||||
Locale string `json:"locale"` // language to use: eg. de, en, or fr
|
||||
ViewMode string `json:"viewMode"` // view mode to use: eg. normal, list, grid, or compact
|
||||
SingleClick bool `json:"singleClick"` // open directory on single click, also enables middle click to open in new tab
|
||||
Sorting Sorting `json:"sorting"`
|
||||
ShowHidden bool `json:"showHidden"` // show hidden files in the UI. On windows this includes files starting with a dot and windows hidden files
|
||||
DateFormat bool `json:"dateFormat"` // when false, the date is relative, when true, the date is an exact timestamp
|
||||
GallerySize int `json:"gallerySize"` // 0-9 - the size of the gallery thumbnails
|
||||
ThemeColor string `json:"themeColor"` // theme color to use: eg. #ff0000, or var(--red), var(--purple), etc
|
||||
QuickDownload bool `json:"quickDownload"` // show icon to download in one click
|
||||
DisableOnlyOfficeExt string `json:"disableOnlyOfficeExt"` // comma separated list of file extensions to disable onlyoffice preview for
|
||||
}
|
||||
|
||||
var PublicUser = User{
|
||||
|
||||
@@ -57,6 +57,7 @@ require (
|
||||
github.com/charithe/durationcheck v0.0.10 // indirect
|
||||
github.com/chavacava/garif v0.1.0 // indirect
|
||||
github.com/ckaznocha/intrange v0.3.0 // indirect
|
||||
github.com/coreos/go-oidc/v3 v3.14.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
||||
github.com/curioswitch/go-reassign v0.3.0 // indirect
|
||||
github.com/daixiang0/gci v0.13.5 // indirect
|
||||
@@ -75,6 +76,7 @@ require (
|
||||
github.com/ghostiam/protogetter v0.3.9 // indirect
|
||||
github.com/go-critic/go-critic v0.12.0 // indirect
|
||||
github.com/go-errors/errors v1.5.1 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.1 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
@@ -229,6 +231,7 @@ require (
|
||||
golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac // indirect
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
golang.org/x/net v0.40.0 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/sync v0.14.0 // indirect
|
||||
golang.org/x/text v0.25.0 // indirect
|
||||
golang.org/x/tools v0.33.0 // indirect
|
||||
|
||||
@@ -130,6 +130,8 @@ github.com/ckaznocha/intrange v0.3.0 h1:VqnxtK32pxgkhJgYQEeOArVidIPg+ahLP7WBOXZd
|
||||
github.com/ckaznocha/intrange v0.3.0/go.mod h1:+I/o2d2A1FBHgGELbGxzIcyd3/9l9DuwjM8FsbSS3Lo=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/coreos/go-oidc/v3 v3.14.1 h1:9ePWwfdwC4QKRlCXsJGou56adA/owXczOzwKdOumLqk=
|
||||
github.com/coreos/go-oidc/v3 v3.14.1/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
@@ -198,6 +200,8 @@ github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3Bop
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
|
||||
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
@@ -835,6 +839,8 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
||||
+165
-218
@@ -1,21 +1,21 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
libError "errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
jwt "github.com/golang-jwt/jwt/v4"
|
||||
"github.com/golang-jwt/jwt/v4/request"
|
||||
"github.com/lestrrat-go/jwx/v3/jwk"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/cache"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/errors"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/logger"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/settings"
|
||||
@@ -79,16 +79,9 @@ func setupProxyUser(r *http.Request, data *requestContext, proxyUser string) (*u
|
||||
return nil, err
|
||||
}
|
||||
if config.Auth.Methods.ProxyAuth.CreateUser {
|
||||
hashpass, err := users.HashPwd(proxyUser)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = storage.CreateUser(users.User{
|
||||
LoginMethod: users.LoginMethodProxy,
|
||||
Username: proxyUser,
|
||||
NonAdminEditable: users.NonAdminEditable{
|
||||
Password: hashpass, // hashed password that can't actually be used
|
||||
},
|
||||
}, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -153,7 +146,6 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Authenticate the user based on the request
|
||||
user, err := auther.Auth(r, store.Users)
|
||||
if err != nil {
|
||||
logger.Debug(err.Error())
|
||||
http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
@@ -175,6 +167,29 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// logoutHandler handles user logout, specifically used for OIDC.
|
||||
// @Summary User Logout
|
||||
// @Description logs a user out of the application.
|
||||
// @Tags Auth
|
||||
// @Success 302 {string} string "Redirect to redirect URL if configured in oidc config."
|
||||
// @Router /api/auth/logout [get]
|
||||
func logoutHandler(w http.ResponseWriter, r *http.Request) {
|
||||
origin := r.Header.Get("Origin")
|
||||
if origin == "" {
|
||||
origin = fmt.Sprintf("%s://%s", getScheme(r), r.Host)
|
||||
}
|
||||
logoutUrl := fmt.Sprintf("%s/login", origin)
|
||||
|
||||
oidcCfg := settings.Config.Auth.Methods.OidcAuth
|
||||
if oidcCfg.Enabled && oidcCfg.LogoutRedirectUrl != "" {
|
||||
logoutUrl = oidcCfg.LogoutRedirectUrl
|
||||
http.Redirect(w, r, logoutUrl, http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, logoutUrl, http.StatusFound)
|
||||
}
|
||||
|
||||
type signupBody struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
@@ -220,7 +235,7 @@ func signupHandler(w http.ResponseWriter, r *http.Request) {
|
||||
user.Username = info.Username
|
||||
user.Password = info.Password
|
||||
|
||||
err = store.Users.Save(user, true)
|
||||
err = store.Users.Save(user, true, false)
|
||||
if err == errors.ErrExist {
|
||||
http.Error(w, http.StatusText(http.StatusConflict), http.StatusConflict)
|
||||
return
|
||||
@@ -332,155 +347,84 @@ type userInfo struct {
|
||||
Phone string `json:"phone_number"`
|
||||
}
|
||||
|
||||
// getKeySet fetches the JWKS from the given URL, using the provided cache.
|
||||
func getKeySet(jwksUrl string) (jwk.Set, error) {
|
||||
// Check cache first
|
||||
value := cache.JwtCache.Get(jwksUrl)
|
||||
jwks, ok := value.(jwk.Set)
|
||||
if ok {
|
||||
return jwks, nil
|
||||
}
|
||||
logger.Debug("JWKS not found in cache for, fetching...")
|
||||
// Fetch the JWKS from the URL
|
||||
resp, err := http.Get(jwksUrl)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch JWKS from %s: %v", jwksUrl, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
bodyBytes, _ := io.ReadAll(resp.Body)
|
||||
return nil, fmt.Errorf("failed to fetch JWKS from %s: received status code %d with body: %s", jwksUrl, resp.StatusCode, string(bodyBytes))
|
||||
}
|
||||
|
||||
// Decode the JWKS using jwk.ParseReader
|
||||
jwks, err = jwk.ParseReader(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode JWKS: %v", err)
|
||||
}
|
||||
|
||||
// Store in cache. Assuming your cache handles expiration (e.g., 1 hour).
|
||||
cache.JwtCache.Set(jwksUrl, jwks) // Store the jwk.Set
|
||||
return jwks, nil // Return the jwk.Set after type assertion
|
||||
}
|
||||
|
||||
// oidcCallbackHandler handles the OIDC callback after the user authenticates with the provider.
|
||||
// It exchanges the authorization code for tokens, then attempts to verify the ID token using JWKS
|
||||
// if configured, falling back to the UserInfo endpoint if necessary.
|
||||
// It exchanges the authorization code for tokens, attempts to verify the ID token.
|
||||
// If ID token verification or essential claims extraction fails, it falls back to the UserInfo endpoint.
|
||||
func oidcCallbackHandler(w http.ResponseWriter, r *http.Request, d *requestContext) (int, error) {
|
||||
ctx := r.Context()
|
||||
|
||||
oidcCfg := settings.Config.Auth.Methods.OidcAuth
|
||||
if oidcCfg.Provider == nil || oidcCfg.Verifier == nil {
|
||||
// Ensure Provider and Verifier are initialized on application startup
|
||||
// This check is good, keep it.
|
||||
logger.Error("OIDC provider or verifier not initialized.")
|
||||
return http.StatusInternalServerError, fmt.Errorf("OIDC provider or verifier not initialized")
|
||||
}
|
||||
// If disableVerifyTLS is true, create a custom HTTP client
|
||||
// and set it in the context for the OIDC provider.
|
||||
if oidcCfg.DisableVerifyTLS {
|
||||
// Create a custom transport with InsecureSkipVerify set to true
|
||||
transport := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
customClient := &http.Client{
|
||||
Transport: transport,
|
||||
}
|
||||
ctx = oidc.ClientContext(ctx, customClient)
|
||||
}
|
||||
code := r.URL.Query().Get("code")
|
||||
// state := r.URL.Query().Get("state") // You might want to validate the state parameter for CSRF protection
|
||||
|
||||
origin := r.Header.Get("Origin")
|
||||
if origin == "" {
|
||||
origin = fmt.Sprintf("%s://%s", getScheme(r), r.Host)
|
||||
// The redirect URI MUST match the one registered with the OIDC provider
|
||||
// and used in the initial /api/auth/oidc/login handler.
|
||||
// Using r.Host here might be tricky if running behind a proxy.
|
||||
// Consider using a fixed redirect URL from settings if possible.
|
||||
redirectURL := fmt.Sprintf("%s://%s/api/auth/oidc/callback", getScheme(r), r.Host)
|
||||
|
||||
oauth2Config := &oauth2.Config{
|
||||
ClientID: oidcCfg.ClientID,
|
||||
ClientSecret: oidcCfg.ClientSecret,
|
||||
Endpoint: oidcCfg.Provider.Endpoint(), // Use endpoint from discovered provider
|
||||
RedirectURL: redirectURL, // Use the dynamically determined redirect URL
|
||||
Scopes: strings.Split(oidcCfg.Scopes, " "),
|
||||
}
|
||||
|
||||
redirectURI := fmt.Sprintf("%s/api/auth/oidc/callback", origin)
|
||||
|
||||
// Step 1: Exchange the code for tokens
|
||||
data := url.Values{}
|
||||
data.Set("grant_type", "authorization_code")
|
||||
data.Set("code", code)
|
||||
data.Set("client_id", config.Auth.Methods.OidcAuth.ClientID)
|
||||
data.Set("client_secret", config.Auth.Methods.OidcAuth.ClientSecret)
|
||||
data.Set("redirect_uri", redirectURI)
|
||||
|
||||
req, _ := http.NewRequest("POST", config.Auth.Methods.OidcAuth.TokenUrl, strings.NewReader(data.Encode()))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
client := &http.Client{} // Consider using a client with a timeout
|
||||
resp, err := client.Do(req)
|
||||
// Exchange the authorization code for tokens
|
||||
token, err := oauth2Config.Exchange(ctx, code)
|
||||
if err != nil {
|
||||
logger.Debug(fmt.Sprintf("failed to send token request: %v", err))
|
||||
return 500, fmt.Errorf("token request failed: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
logger.Debug(fmt.Sprintf("failed to fetch token: %v %v", resp.StatusCode, string(body)))
|
||||
return 500, fmt.Errorf("failed to fetch token: %v %v", resp.StatusCode, string(body))
|
||||
logger.Error(fmt.Sprintf("failed to exchange token: %v", err))
|
||||
return http.StatusInternalServerError, fmt.Errorf("failed to exchange token: %v", err)
|
||||
}
|
||||
|
||||
// Decode the token response, expecting access_token and potentially id_token
|
||||
var tokenResp struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
IDToken string `json:"id_token"` // OIDC providers include id_token here
|
||||
}
|
||||
rawIDToken, ok := token.Extra("id_token").(string)
|
||||
// accessToken := token.AccessToken // Access token is needed for UserInfo, already in 'token'
|
||||
|
||||
if err = json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
|
||||
logger.Debug(fmt.Sprintf("failed to parse token response: %v", err))
|
||||
return 500, fmt.Errorf("failed to parse token response: %v", err)
|
||||
}
|
||||
var userdata userInfo // Declare userdata here to be populated by either source
|
||||
claimsFromIDToken := false // Flag to track if we successfully got claims from ID token
|
||||
loginUsername := "" // Variable to hold the login username
|
||||
|
||||
var userdata userInfo // This will hold the user claims, using the original struct
|
||||
useUserInfoEndpoint := true // Flag to determine if we need to call the UserInfo endpoint
|
||||
// --- Attempt to process ID Token ---
|
||||
if ok && rawIDToken != "" {
|
||||
logger.Debug("ID token found in token response, attempting verification.")
|
||||
|
||||
// Step 2: Process ID Token if available and JWKS URL is configured
|
||||
if tokenResp.IDToken != "" && config.Auth.Methods.OidcAuth.JwksUrl != "" {
|
||||
logger.Debug(fmt.Sprintf("ID token received `%v` attempting to verify using JWKS URL", tokenResp.IDToken))
|
||||
// getKeySet now returns jwk.Set (interface)
|
||||
var jwks jwk.Set
|
||||
jwks, err = getKeySet(config.Auth.Methods.OidcAuth.JwksUrl)
|
||||
// Verify the ID token
|
||||
// This uses the verifier initialized with the provider's JWKS endpoint and client ID
|
||||
idToken, err := oidcCfg.Verifier.Verify(ctx, rawIDToken)
|
||||
if err != nil {
|
||||
// Log the error but don't fail yet, try UserInfo endpoint as a fallback
|
||||
logger.Warning("Failed to fetch or decode JWKS: %v. Falling back to UserInfo endpoint. Ensure your OidcAuth.JwksUrl is correct.")
|
||||
logger.Warning(fmt.Sprintf("failed to verify ID token: %v. Falling back to UserInfo endpoint.", err))
|
||||
// Verification failed, claimsFromIDToken remains false
|
||||
} else {
|
||||
var token *jwt.Token
|
||||
// Parse the ID token. We need to provide a key function to `jwt.Parse`
|
||||
// that looks up the key in the JWKS based on the token's `kid`.
|
||||
token, err = jwt.Parse(tokenResp.IDToken, func(token *jwt.Token) (interface{}, error) {
|
||||
switch alg := token.Method.Alg(); alg {
|
||||
case "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "PS256", "PS384", "PS512", "EdDSA":
|
||||
// accepted
|
||||
default:
|
||||
logger.Debug(fmt.Sprintf("unsupported signing method recieved `%v`", alg))
|
||||
return nil, fmt.Errorf("unsupported signing method recieved: %v", alg)
|
||||
}
|
||||
// Find the key in the JWKS that matches the token's kid (Key ID)
|
||||
keyID, ok := token.Header["kid"].(string)
|
||||
if !ok {
|
||||
logger.Debug("kid header not found in ID token")
|
||||
return nil, fmt.Errorf("kid header not found in ID token")
|
||||
}
|
||||
// Use the jwk.Set interface to find the key
|
||||
// LookupKeyID returns a slice of jwk.Key and a boolean indicating if any keys were found.
|
||||
key, found := jwks.LookupKeyID(keyID) // Called on the jwk.Set interface
|
||||
if !found {
|
||||
logger.Debug(fmt.Sprintf("key with kid %s not found in JWKS", keyID))
|
||||
return nil, fmt.Errorf("key with kid %s not found in JWKS", keyID)
|
||||
}
|
||||
// Return the public key from the first matching JWK
|
||||
// In a real scenario, you might need more sophisticated key selection logic.
|
||||
// The jwk.Key interface has a PublicKey() method to get the public key.
|
||||
publicKey, publicKeyErr := key.PublicKey()
|
||||
if publicKeyErr != nil {
|
||||
logger.Debug(fmt.Sprintf("failed to get public key from JWK: %v", publicKeyErr))
|
||||
return nil, fmt.Errorf("failed to get public key from JWK: %v", err)
|
||||
}
|
||||
return publicKey, nil
|
||||
})
|
||||
var claims map[string]interface{}
|
||||
// Decode the ID token claims into a map to handle arbitrary structure
|
||||
// This is where the JWE unmarshalling error occurs if the token is encrypted
|
||||
if err := idToken.Claims(&claims); err != nil {
|
||||
logger.Warning(fmt.Sprintf("failed to decode ID token claims: %v. Falling back to UserInfo endpoint.", err))
|
||||
// Claims decoding failed, claimsFromIDToken remains false
|
||||
} else {
|
||||
// Successfully verified and decoded ID token claims
|
||||
logger.Debug(fmt.Sprintf("ID Token verified and claims decoded: %+v", claims))
|
||||
|
||||
if err != nil {
|
||||
// Log the verification error but fall back to UserInfo endpoint
|
||||
logger.Error(fmt.Sprintf("failed to parse or verify ID token: %v. Falling back to UserInfo endpoint.", err))
|
||||
} else if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
||||
logger.Debug("ID token verified successfully, claims extracted.")
|
||||
|
||||
// --- IMPORTANT OIDC VALIDATION ---
|
||||
// In a production application, you MUST perform additional validations on the ID token claims:
|
||||
// - Issuer (iss): Must match the expected issuer URL.
|
||||
// - Audience (aud): Must contain your client ID.
|
||||
// - Expiration Time (exp): Token must not be expired (jwt.Parse handles this if clock skew is accounted for).
|
||||
// - Issued At Time (iat): Token must not be issued in the future.
|
||||
// - Nonce (nonce): If a nonce was sent in the authorization request, it must match the 'nonce' claim in the ID token.
|
||||
// - Authorized Party (azp): If 'aud' has multiple values, 'azp' must be present and equal to your client ID.
|
||||
// - at_hash and c_hash: If the access token or authorization code were issued, validate their hashes if present in the ID token.
|
||||
// A dedicated OIDC library handles these validations correctly and securely.
|
||||
// This simplified example only verifies the signature and basic validity.
|
||||
// --- END IMPORTANT OIDC VALIDATION ---
|
||||
|
||||
// Populate the userInfo struct from the ID token claims (map)
|
||||
// Populate userdata from ID token claims
|
||||
if name, ok := claims["name"].(string); ok {
|
||||
userdata.Name = name
|
||||
}
|
||||
@@ -496,110 +440,113 @@ func oidcCallbackHandler(w http.ResponseWriter, r *http.Request, d *requestConte
|
||||
if phone, ok := claims["phone_number"].(string); ok {
|
||||
userdata.Phone = phone
|
||||
}
|
||||
|
||||
useUserInfoEndpoint = false // Successfully processed ID token, no need for UserInfo endpoint
|
||||
|
||||
} else {
|
||||
// ID token signature verification failed or token is invalid for other reasons
|
||||
logger.Error("id token signature verification failed or token is invalid. Falling back to UserInfo endpoint.")
|
||||
// Decide if we rely on ID token claims or still need UserInfo
|
||||
// Even if parsing succeeded, if essential claims are missing, use UserInfo
|
||||
switch oidcCfg.UserIdentifier {
|
||||
case "email":
|
||||
if userdata.Email != "" {
|
||||
claimsFromIDToken = true
|
||||
loginUsername = userdata.Email
|
||||
}
|
||||
case "username":
|
||||
if userdata.PreferredUsername != "" {
|
||||
claimsFromIDToken = true
|
||||
loginUsername = userdata.PreferredUsername
|
||||
}
|
||||
case "phone":
|
||||
if userdata.Phone != "" {
|
||||
claimsFromIDToken = true
|
||||
loginUsername = userdata.Phone
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.Debug("No ID token found in token response or it was empty. Falling back to UserInfo endpoint.")
|
||||
// claimsFromIDToken remains false
|
||||
}
|
||||
|
||||
// Step 3: Use the access token to fetch user info from the UserInfo URL if needed
|
||||
// This step is skipped if the ID token was successfully processed and verified.
|
||||
if useUserInfoEndpoint {
|
||||
userInfoURL := config.Auth.Methods.OidcAuth.UserInfoUrl
|
||||
req, _ = http.NewRequest("GET", userInfoURL, nil)
|
||||
req.Header.Set("Authorization", "Bearer "+tokenResp.AccessToken)
|
||||
|
||||
resp, err = client.Do(req)
|
||||
// --- Fallback to UserInfo endpoint if ID token processing did not provide essential claims ---
|
||||
if !claimsFromIDToken {
|
||||
// Use the access token obtained from the initial exchange
|
||||
// oauth2Config.TokenSource creates a token source that uses the provided token.
|
||||
userInfoResp, err := oidcCfg.Provider.UserInfo(ctx, oauth2Config.TokenSource(ctx, token))
|
||||
if err != nil {
|
||||
return 500, fmt.Errorf("failed to fetch user info: %v", err)
|
||||
logger.Error(fmt.Sprintf("failed to fetch user info from endpoint: %v", err))
|
||||
return http.StatusInternalServerError, fmt.Errorf("failed to fetch user info from endpoint: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
bodyBytes, _ := io.ReadAll(resp.Body)
|
||||
return 500, fmt.Errorf("failed to fetch user info: received status code %d with body: %s", resp.StatusCode, string(bodyBytes))
|
||||
// Decode the UserInfo response directly into the userdata struct
|
||||
// The UserInfo endpoint is expected to return standard JSON
|
||||
if err := userInfoResp.Claims(&userdata); err != nil {
|
||||
logger.Error(fmt.Sprintf("failed to decode user info from endpoint: %v", err))
|
||||
return http.StatusInternalServerError, fmt.Errorf("failed to decode user info from endpoint: %v", err)
|
||||
}
|
||||
|
||||
// Decode the UserInfo response directly into the original userdata struct
|
||||
if err = json.NewDecoder(resp.Body).Decode(&userdata); err != nil {
|
||||
return 500, fmt.Errorf("failed to parse user info: %v", err)
|
||||
// Decide if we rely on ID token claims or still need UserInfo
|
||||
// Even if parsing succeeded, if essential claims are missing, use UserInfo
|
||||
switch oidcCfg.UserIdentifier {
|
||||
case "email":
|
||||
loginUsername = userdata.Email
|
||||
case "username":
|
||||
loginUsername = userdata.PreferredUsername
|
||||
case "phone":
|
||||
loginUsername = userdata.Phone
|
||||
}
|
||||
}
|
||||
|
||||
// Now userdata contains claims from either the verified ID token or the UserInfo endpoint.
|
||||
// Proceed with logging in the user based on the extracted claims.
|
||||
return loginWithOidcUser(w, r, userdata)
|
||||
if loginUsername == "" {
|
||||
logger.Error("No valid username found in ID token or UserInfo response.")
|
||||
return http.StatusInternalServerError, fmt.Errorf("no valid username found in ID token or UserInfo response from claims")
|
||||
}
|
||||
// Proceed to log the user in with the OIDC data
|
||||
// userdata struct now contains info from either verified ID token or UserInfo endpoint
|
||||
return loginWithOidcUser(w, r, loginUsername)
|
||||
}
|
||||
|
||||
// oidcLoginHandler redirects the user to the OIDC provider's authorization endpoint.
|
||||
// This function remains largely the same, but includes the 'fb_redirect' parameter
|
||||
// to redirect the user back to the original page after successful login.
|
||||
func oidcLoginHandler(w http.ResponseWriter, r *http.Request, d *requestContext) (int, error) {
|
||||
if config.Auth.Methods.OidcAuth.Enabled {
|
||||
origin := r.Header.Get("Origin")
|
||||
if origin == "" {
|
||||
origin = fmt.Sprintf("%s://%s", getScheme(r), r.Host)
|
||||
}
|
||||
|
||||
// Generate a nonce for CSRF protection (optional but recommended)
|
||||
// You should store this nonce and validate it in the callback handler.
|
||||
nonce := utils.InsecureRandomIdentifier(16)
|
||||
// For state parameter, you might include the nonce and the original redirect URL
|
||||
state := fmt.Sprintf("%s:%s", nonce, r.URL.Query().Get("fb_redirect")) // Example state parameter structure
|
||||
|
||||
redirectURI := fmt.Sprintf("%s/api/auth/oidc/callback", origin)
|
||||
|
||||
// Construct the authorization URL
|
||||
authURL := fmt.Sprintf("%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s&redirect_uris=%s&state=%s",
|
||||
config.Auth.Methods.OidcAuth.AuthorizationUrl,
|
||||
url.QueryEscape(config.Auth.Methods.OidcAuth.ClientID),
|
||||
url.QueryEscape(config.Auth.Methods.OidcAuth.Scopes),
|
||||
url.QueryEscape(redirectURI),
|
||||
url.QueryEscape(redirectURI),
|
||||
url.QueryEscape(state), // Use the state parameter
|
||||
)
|
||||
|
||||
// Redirect the user to the OIDC provider
|
||||
http.Redirect(w, r, authURL, http.StatusFound)
|
||||
return 0, nil // Indicate that the request has been handled by the redirect
|
||||
oidcCfg := settings.Config.Auth.Methods.OidcAuth
|
||||
if !oidcCfg.Enabled {
|
||||
return http.StatusForbidden, fmt.Errorf("oidc authentication is not enabled")
|
||||
}
|
||||
|
||||
// OIDC authentication is not enabled
|
||||
return http.StatusForbidden, fmt.Errorf("oidc authentication is not enabled")
|
||||
origin := r.Header.Get("Origin")
|
||||
if origin == "" {
|
||||
origin = fmt.Sprintf("%s://%s", getScheme(r), r.Host)
|
||||
}
|
||||
|
||||
oauth2Config := &oauth2.Config{
|
||||
ClientID: oidcCfg.ClientID,
|
||||
ClientSecret: oidcCfg.ClientSecret,
|
||||
Endpoint: oidcCfg.Provider.Endpoint(),
|
||||
RedirectURL: fmt.Sprintf("%s/api/auth/oidc/callback", origin),
|
||||
Scopes: strings.Split(oidcCfg.Scopes, " "),
|
||||
}
|
||||
|
||||
nonce := utils.InsecureRandomIdentifier(16)
|
||||
fbRedirect := r.URL.Query().Get("fb_redirect")
|
||||
state := fmt.Sprintf("%s:%s", nonce, fbRedirect)
|
||||
|
||||
authURL := oauth2Config.AuthCodeURL(state)
|
||||
http.Redirect(w, r, authURL, http.StatusFound)
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// loginWithOidcUser extracts the username from the user claims (userInfo)
|
||||
// based on the configured UserIdentifier and logs the user into the application.
|
||||
// It creates a new user if one doesn't exist.
|
||||
func loginWithOidcUser(w http.ResponseWriter, r *http.Request, userInfo userInfo) (int, error) {
|
||||
username := userInfo.PreferredUsername
|
||||
switch config.Auth.Methods.OidcAuth.UserIdentifier {
|
||||
case "email":
|
||||
username = userInfo.Email
|
||||
case "username":
|
||||
username = userInfo.PreferredUsername
|
||||
}
|
||||
func loginWithOidcUser(w http.ResponseWriter, r *http.Request, username string) (int, error) {
|
||||
logger.Debug(fmt.Sprintf("Successfully authenticated OIDC username: %s", username))
|
||||
// Retrieve the user from the store and store it in the context
|
||||
user, err := store.Users.Get(username)
|
||||
if err != nil {
|
||||
if err.Error() != "the resource does not exist" {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
hashpass := ""
|
||||
hashpass, err = users.HashPwd(username) // hashed password that can't actually be used, gets double hashed
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
err = storage.CreateUser(users.User{
|
||||
LoginMethod: users.LoginMethodOidc,
|
||||
Username: username,
|
||||
NonAdminEditable: users.NonAdminEditable{
|
||||
Password: hashpass, // hashed password that can't actually be used
|
||||
},
|
||||
}, false)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
|
||||
@@ -73,6 +73,8 @@ func StartHttp(ctx context.Context, storage *storage.Storage, shutdownComplete c
|
||||
|
||||
// Auth routes
|
||||
api.HandleFunc("POST /auth/login", loginHandler)
|
||||
api.HandleFunc("GET /auth/logout", logoutHandler)
|
||||
|
||||
api.HandleFunc("GET /auth/signup", signupHandler)
|
||||
api.HandleFunc("POST /auth/renew", withUser(renewHandler))
|
||||
api.HandleFunc("PUT /auth/token", withUser(createApiKeyHandler))
|
||||
|
||||
@@ -77,10 +77,10 @@ func TestWithAdminHelper(t *testing.T) {
|
||||
Permissions: users.Permissions{Admin: false}, // Non-admin user
|
||||
}
|
||||
// Save the users to the mock database
|
||||
if err := store.Users.Save(adminUser, true); err != nil {
|
||||
if err := store.Users.Save(adminUser, true, true); err != nil {
|
||||
t.Fatal("failed to save admin user:", err)
|
||||
}
|
||||
if err := store.Users.Save(nonAdminUser, true); err != nil {
|
||||
if err := store.Users.Save(nonAdminUser, true, true); err != nil {
|
||||
t.Fatal("failed to save non-admin user:", err)
|
||||
}
|
||||
// Test cases for different scenarios
|
||||
|
||||
+30
-10
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/backend/adapters/fs/files"
|
||||
@@ -39,6 +40,7 @@ type FileCache interface {
|
||||
// @Failure 501 {object} map[string]string "Preview generation not implemented"
|
||||
// @Router /api/preview [get]
|
||||
func previewHandler(w http.ResponseWriter, r *http.Request, d *requestContext) (int, error) {
|
||||
|
||||
if config.Server.DisablePreviews {
|
||||
return http.StatusNotImplemented, fmt.Errorf("preview is disabled")
|
||||
}
|
||||
@@ -88,6 +90,7 @@ func rawFileHandler(w http.ResponseWriter, r *http.Request, file iteminfo.Extend
|
||||
}
|
||||
|
||||
func previewHelperFunc(w http.ResponseWriter, r *http.Request, d *requestContext) (int, error) {
|
||||
|
||||
previewSize := r.URL.Query().Get("size")
|
||||
if previewSize != "small" {
|
||||
previewSize = "large"
|
||||
@@ -106,18 +109,35 @@ func previewHelperFunc(w http.ResponseWriter, r *http.Request, d *requestContext
|
||||
}
|
||||
return http.StatusNotImplemented, fmt.Errorf("can't create preview for %s type", d.fileInfo.Type)
|
||||
}
|
||||
pathUrl := fmt.Sprintf("/api/raw?files=%s::%s", d.fileInfo.Source, d.fileInfo.Path)
|
||||
pathUrl = pathUrl + "&auth=" + d.token
|
||||
if settings.Config.Server.InternalUrl != "" {
|
||||
pathUrl = config.Server.InternalUrl + pathUrl
|
||||
} else {
|
||||
scheme := "http"
|
||||
if r.TLS != nil {
|
||||
scheme = "https"
|
||||
seekPercentage := 0
|
||||
percentage := r.URL.Query().Get("atPercentage")
|
||||
if percentage != "" {
|
||||
var err error
|
||||
// convert string to int
|
||||
seekPercentage, err = strconv.Atoi(percentage)
|
||||
if err != nil {
|
||||
seekPercentage = 10
|
||||
}
|
||||
if seekPercentage < 0 || seekPercentage > 100 {
|
||||
seekPercentage = 10
|
||||
}
|
||||
pathUrl = scheme + "://" + r.Host + pathUrl
|
||||
}
|
||||
previewImg, err := preview.GetPreviewForFile(d.fileInfo, previewSize, pathUrl)
|
||||
|
||||
officeUrl := ""
|
||||
if d.fileInfo.OnlyOfficeId != "" {
|
||||
pathUrl := fmt.Sprintf("/api/raw?files=%s::%s", d.fileInfo.Source, d.fileInfo.Path)
|
||||
pathUrl = pathUrl + "&auth=" + d.token
|
||||
if settings.Config.Server.InternalUrl != "" {
|
||||
officeUrl = config.Server.InternalUrl + pathUrl
|
||||
} else {
|
||||
scheme := "http"
|
||||
if r.TLS != nil {
|
||||
scheme = "https"
|
||||
}
|
||||
officeUrl = scheme + "://" + r.Host + pathUrl
|
||||
}
|
||||
}
|
||||
previewImg, err := preview.GetPreviewForFile(d.fileInfo, previewSize, officeUrl, seekPercentage)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ func handleWithStaticData(w http.ResponseWriter, r *http.Request, file, contentT
|
||||
"StaticURL": config.Server.BaseURL + "static",
|
||||
"Signup": settings.Config.Auth.Methods.PasswordAuth.Signup,
|
||||
"NoAuth": config.Auth.Methods.NoAuth,
|
||||
"PasswordAuth": config.Auth.Methods.PasswordAuth,
|
||||
"LoginPage": auther.LoginPage(),
|
||||
"CSS": false,
|
||||
"EnableThumbs": !config.Server.DisablePreviews,
|
||||
|
||||
@@ -158,7 +158,7 @@ func usersPostHandler(w http.ResponseWriter, r *http.Request, d *requestContext)
|
||||
return http.StatusBadRequest, nil
|
||||
}
|
||||
|
||||
if req.Data.Password == "" {
|
||||
if req.Data.Password == "" && req.Data.LoginMethod == "password" {
|
||||
return http.StatusBadRequest, errors.ErrEmptyPassword
|
||||
}
|
||||
|
||||
|
||||
+16
-12
@@ -73,20 +73,21 @@ func Start(concurrencyLimit int, ffmpegPath, cacheDir string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetPreviewForFile(file iteminfo.ExtendedFileInfo, previewSize, rawUrl string) ([]byte, error) {
|
||||
func GetPreviewForFile(file iteminfo.ExtendedFileInfo, previewSize, url string, seekPercentage int) ([]byte, error) {
|
||||
if !AvailablePreview(file) {
|
||||
return nil, ErrUnsupportedMedia
|
||||
}
|
||||
cacheKey := CacheKey(file.RealPath, previewSize, file.ItemInfo.ModTime)
|
||||
cacheKey := CacheKey(file.RealPath, previewSize, file.ItemInfo.ModTime, seekPercentage)
|
||||
if data, found, err := service.fileCache.Load(context.Background(), cacheKey); err != nil {
|
||||
return nil, fmt.Errorf("failed to load from cache: %w", err)
|
||||
} else if found {
|
||||
return data, nil
|
||||
}
|
||||
return GeneratePreview(file, previewSize, rawUrl)
|
||||
|
||||
return GeneratePreview(file, previewSize, url, seekPercentage)
|
||||
}
|
||||
|
||||
func GeneratePreview(file iteminfo.ExtendedFileInfo, previewSize, rawUrl string) ([]byte, error) {
|
||||
func GeneratePreview(file iteminfo.ExtendedFileInfo, previewSize, officeUrl string, seekPercentage int) ([]byte, error) {
|
||||
ext := strings.ToLower(filepath.Ext(file.Name))
|
||||
var (
|
||||
err error
|
||||
@@ -95,7 +96,7 @@ func GeneratePreview(file iteminfo.ExtendedFileInfo, previewSize, rawUrl string)
|
||||
|
||||
// Generate an image from office document
|
||||
if file.OnlyOfficeId != "" {
|
||||
imageBytes, err = service.GenerateOfficePreview(filepath.Ext(file.Name), file.OnlyOfficeId, file.Name, rawUrl)
|
||||
imageBytes, err = service.GenerateOfficePreview(filepath.Ext(file.Name), file.OnlyOfficeId, file.Name, officeUrl)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create image for office file: %w", err)
|
||||
}
|
||||
@@ -106,10 +107,13 @@ func GeneratePreview(file iteminfo.ExtendedFileInfo, previewSize, rawUrl string)
|
||||
return nil, fmt.Errorf("failed to read image file: %w", err)
|
||||
}
|
||||
} else if strings.HasPrefix(file.Type, "video") {
|
||||
if seekPercentage == 0 {
|
||||
seekPercentage = 10
|
||||
}
|
||||
// Generate thumbnail image from video
|
||||
outPathPattern := filepath.Join(settings.Config.Server.CacheDir, "thumbnails", "video", CacheKey(file.RealPath, previewSize, file.ItemInfo.ModTime)+".jpg")
|
||||
outPathPattern := filepath.Join(settings.Config.Server.CacheDir, "thumbnails", "video", CacheKey(file.RealPath, previewSize, file.ItemInfo.ModTime, seekPercentage)+".jpg")
|
||||
defer os.Remove(outPathPattern) // cleanup
|
||||
if err = service.GenerateVideoPreview(file.RealPath, outPathPattern); err != nil {
|
||||
if err = service.GenerateVideoPreview(file.RealPath, outPathPattern, seekPercentage); err != nil {
|
||||
return nil, fmt.Errorf("failed to generate video preview: %w", err)
|
||||
}
|
||||
imageBytes, err = os.ReadFile(outPathPattern)
|
||||
@@ -124,7 +128,7 @@ func GeneratePreview(file iteminfo.ExtendedFileInfo, previewSize, rawUrl string)
|
||||
return nil, fmt.Errorf("failed to resize preview image: %w", err)
|
||||
}
|
||||
// Cache and return
|
||||
cacheKey := CacheKey(file.RealPath, previewSize, file.ItemInfo.ModTime)
|
||||
cacheKey := CacheKey(file.RealPath, previewSize, file.ItemInfo.ModTime, seekPercentage)
|
||||
if err := service.fileCache.Store(context.Background(), cacheKey, resizedBytes); err != nil {
|
||||
logger.Error(fmt.Sprintf("failed to cache resized image: %v", err))
|
||||
}
|
||||
@@ -159,14 +163,14 @@ func (s *Service) CreatePreview(data []byte, previewSize string) ([]byte, error)
|
||||
return output.Bytes(), nil
|
||||
}
|
||||
|
||||
func CacheKey(realPath, previewSize string, modTime time.Time) string {
|
||||
return fmt.Sprintf("%x%x%x", realPath, modTime.Unix(), previewSize)
|
||||
func CacheKey(realPath, previewSize string, modTime time.Time, percentage int) string {
|
||||
return fmt.Sprintf("%x%x%x%x", realPath, modTime.Unix(), previewSize, percentage)
|
||||
}
|
||||
|
||||
func DelThumbs(ctx context.Context, file iteminfo.ExtendedFileInfo) {
|
||||
errSmall := service.fileCache.Delete(ctx, CacheKey(file.RealPath, "small", file.ItemInfo.ModTime))
|
||||
errSmall := service.fileCache.Delete(ctx, CacheKey(file.RealPath, "small", file.ItemInfo.ModTime, 0))
|
||||
if errSmall != nil {
|
||||
errLarge := service.fileCache.Delete(ctx, CacheKey(file.RealPath, "large", file.ItemInfo.ModTime))
|
||||
errLarge := service.fileCache.Delete(ctx, CacheKey(file.RealPath, "large", file.ItemInfo.ModTime, 0))
|
||||
if errLarge != nil {
|
||||
logger.Debug(fmt.Sprintf("Could not delete thumbnail: %v", file.Name))
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
// videoPath: path to the input video file.
|
||||
// outputPath: path where the generated preview image will be saved (e.g., "/tmp/preview.jpg").
|
||||
// seekTime: how many seconds into the video to seek before capturing the frame.
|
||||
func (s *Service) GenerateVideoPreview(videoPath, outputPath string) error {
|
||||
func (s *Service) GenerateVideoPreview(videoPath, outputPath string, percentageSeek int) error {
|
||||
// Step 1: Get video stream duration (v:0)
|
||||
probeCmd := exec.Command(
|
||||
s.ffprobePath,
|
||||
@@ -37,12 +37,15 @@ func (s *Service) GenerateVideoPreview(videoPath, outputPath string) error {
|
||||
return fmt.Errorf("invalid duration: %v", err)
|
||||
}
|
||||
|
||||
// Step 2: Truncate and compute 10% of video length
|
||||
// Step 2: Get the duration of the video in whole seconds
|
||||
duration := int(durationFloat)
|
||||
seekSeconds := duration / 10
|
||||
seekTime := strconv.Itoa(seekSeconds)
|
||||
|
||||
// Step 3: Extract frame at seek time
|
||||
// Step 3: Calculate seek time based on percentageSeek (percentage value)
|
||||
seekSeconds := duration * percentageSeek / 100
|
||||
|
||||
// Step 4: Convert seekSeconds to string for ffmpeg command
|
||||
seekTime := strconv.Itoa(seekSeconds)
|
||||
// Step 5: Extract frame at seek time
|
||||
cmd := exec.Command(
|
||||
s.ffmpegPath,
|
||||
"-ss", seekTime,
|
||||
|
||||
@@ -15,6 +15,23 @@ const docTemplate = `{
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/api/auth/logout": {
|
||||
"get": {
|
||||
"description": "logs a user out of the application.",
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "User Logout",
|
||||
"responses": {
|
||||
"302": {
|
||||
"description": "Redirect to redirect URL if configured in oidc config.",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/createApiKey": {
|
||||
"post": {
|
||||
"description": "Create an API key with specified name, duration, and permissions.",
|
||||
@@ -1653,6 +1670,10 @@ const docTemplate = `{
|
||||
"methods": {
|
||||
"$ref": "#/definitions/settings.LoginMethods"
|
||||
},
|
||||
"resetAdminOnStart": {
|
||||
"description": "if set to true, the admin user will be reset to the default username and password on startup.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"tokenExpirationHours": {
|
||||
"description": "the number of hours until the token expires. Default is 2 hours.",
|
||||
"type": "integer"
|
||||
@@ -1794,19 +1815,7 @@ const docTemplate = `{
|
||||
},
|
||||
"settings.OidcConfig": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"authorizationUrl",
|
||||
"clientId",
|
||||
"clientSecret",
|
||||
"scopes",
|
||||
"tokenUrl",
|
||||
"userInfoUrl"
|
||||
],
|
||||
"properties": {
|
||||
"authorizationUrl": {
|
||||
"description": "authorization URL of the OIDC provider",
|
||||
"type": "string"
|
||||
},
|
||||
"clientId": {
|
||||
"description": "client id of the OIDC application",
|
||||
"type": "string"
|
||||
@@ -1815,28 +1824,28 @@ const docTemplate = `{
|
||||
"description": "client secret of the OIDC application",
|
||||
"type": "string"
|
||||
},
|
||||
"disableVerifyTLS": {
|
||||
"description": "disable TLS verification for the OIDC provider. This is insecure and should only be used for testing.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"enabled": {
|
||||
"description": "whether to enable OIDC authentication",
|
||||
"type": "boolean"
|
||||
},
|
||||
"jwksUrl": {
|
||||
"description": "currently not used by filebrowser",
|
||||
"issuerUrl": {
|
||||
"description": "authorization URL of the OIDC provider",
|
||||
"type": "string"
|
||||
},
|
||||
"logoutRedirectUrl": {
|
||||
"description": "if provider logout url is provided, filebrowser will also redirect to logout url. Custom logout query params are respected.",
|
||||
"type": "string"
|
||||
},
|
||||
"scopes": {
|
||||
"description": "space separated list of scopes to request from the OIDC provider",
|
||||
"type": "string"
|
||||
},
|
||||
"tokenUrl": {
|
||||
"description": "token URL of the OIDC provider",
|
||||
"description": "scopes to request from the OIDC provider",
|
||||
"type": "string"
|
||||
},
|
||||
"userIdentifier": {
|
||||
"description": "optional: which attribute should be used as the username? options: email, username, name, phone_number, sub",
|
||||
"type": "string"
|
||||
},
|
||||
"userInfoUrl": {
|
||||
"description": "user info URL of the OIDC provider",
|
||||
"description": "the user identifier to use for authentication. Default is \"username\", can be \"email\" or \"username\", or \"phone\"",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
@@ -2099,48 +2108,65 @@ const docTemplate = `{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"darkMode": {
|
||||
"description": "should dark mode be enabled",
|
||||
"type": "boolean"
|
||||
},
|
||||
"dateFormat": {
|
||||
"description": "when false, the date is relative, when true, the date is an exact timestamp",
|
||||
"type": "boolean"
|
||||
},
|
||||
"disableOnlyOfficeExt": {
|
||||
"description": "comma separated list of file extensions to disable onlyoffice preview for",
|
||||
"type": "string"
|
||||
},
|
||||
"disableSettings": {
|
||||
"description": "disable the user from viewing the settings page",
|
||||
"type": "boolean"
|
||||
},
|
||||
"gallerySize": {
|
||||
"description": "0-9 - the size of the gallery thumbnails",
|
||||
"type": "integer"
|
||||
},
|
||||
"locale": {
|
||||
"description": "language to use: eg. de, en, or fr",
|
||||
"type": "string"
|
||||
},
|
||||
"lockPassword": {
|
||||
"description": "disable the user from changing their password",
|
||||
"type": "boolean"
|
||||
},
|
||||
"loginMethod": {
|
||||
"description": "login method to use: eg. password, proxy, oidc",
|
||||
"type": "string"
|
||||
},
|
||||
"permissions": {
|
||||
"$ref": "#/definitions/users.Permissions"
|
||||
},
|
||||
"preview": {
|
||||
"$ref": "#/definitions/users.PreviewOptions"
|
||||
"$ref": "#/definitions/users.Preview"
|
||||
},
|
||||
"quickDownload": {
|
||||
"description": "show icon to download in one click",
|
||||
"type": "boolean"
|
||||
},
|
||||
"showHidden": {
|
||||
"description": "show hidden files in the UI. On windows this includes files starting with a dot and windows hidden files",
|
||||
"type": "boolean"
|
||||
},
|
||||
"singleClick": {
|
||||
"description": "open directory on single click, also enables middle click to open in new tab",
|
||||
"type": "boolean"
|
||||
},
|
||||
"stickySidebar": {
|
||||
"description": "keep sidebar open when navigating",
|
||||
"type": "boolean"
|
||||
},
|
||||
"themeColor": {
|
||||
"description": "theme color to use: eg. #ff0000, or var(--red), var(--purple), etc",
|
||||
"type": "string"
|
||||
},
|
||||
"viewMode": {
|
||||
"description": "view mode to use: eg. normal, list, grid, or compact",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
@@ -2242,22 +2268,31 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"users.PreviewOptions": {
|
||||
"users.Preview": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"highQuality": {
|
||||
"description": "generate high quality preview images",
|
||||
"type": "boolean"
|
||||
},
|
||||
"image": {
|
||||
"description": "show real image as icon instead of generic photo icon",
|
||||
"type": "boolean"
|
||||
},
|
||||
"motionVideoPreview": {
|
||||
"description": "show multiple frames for videos in preview when hovering",
|
||||
"type": "boolean"
|
||||
},
|
||||
"office": {
|
||||
"description": "show preview image for office files",
|
||||
"type": "boolean"
|
||||
},
|
||||
"popup": {
|
||||
"description": "show larger popup preview when hovering",
|
||||
"type": "boolean"
|
||||
},
|
||||
"video": {
|
||||
"description": "show preview image for video files",
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
@@ -2294,24 +2329,29 @@ const docTemplate = `{
|
||||
}
|
||||
},
|
||||
"darkMode": {
|
||||
"description": "should dark mode be enabled",
|
||||
"type": "boolean"
|
||||
},
|
||||
"dateFormat": {
|
||||
"description": "when false, the date is relative, when true, the date is an exact timestamp",
|
||||
"type": "boolean"
|
||||
},
|
||||
"disableOnlyOfficeExt": {
|
||||
"description": "comma separated list of file extensions to disable onlyoffice preview for",
|
||||
"type": "string"
|
||||
},
|
||||
"disableSettings": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"gallerySize": {
|
||||
"description": "0-9 - the size of the gallery thumbnails",
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"locale": {
|
||||
"description": "language to use: eg. de, en, or fr",
|
||||
"type": "string"
|
||||
},
|
||||
"lockPassword": {
|
||||
@@ -2335,9 +2375,10 @@ const docTemplate = `{
|
||||
"$ref": "#/definitions/users.Permissions"
|
||||
},
|
||||
"preview": {
|
||||
"$ref": "#/definitions/users.PreviewOptions"
|
||||
"$ref": "#/definitions/users.Preview"
|
||||
},
|
||||
"quickDownload": {
|
||||
"description": "show icon to download in one click",
|
||||
"type": "boolean"
|
||||
},
|
||||
"scope": {
|
||||
@@ -2350,24 +2391,29 @@ const docTemplate = `{
|
||||
}
|
||||
},
|
||||
"showHidden": {
|
||||
"description": "show hidden files in the UI. On windows this includes files starting with a dot and windows hidden files",
|
||||
"type": "boolean"
|
||||
},
|
||||
"singleClick": {
|
||||
"description": "open directory on single click, also enables middle click to open in new tab",
|
||||
"type": "boolean"
|
||||
},
|
||||
"sorting": {
|
||||
"$ref": "#/definitions/users.Sorting"
|
||||
},
|
||||
"stickySidebar": {
|
||||
"description": "keep sidebar open when navigating",
|
||||
"type": "boolean"
|
||||
},
|
||||
"themeColor": {
|
||||
"description": "theme color to use: eg. #ff0000, or var(--red), var(--purple), etc",
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
"viewMode": {
|
||||
"description": "view mode to use: eg. normal, list, grid, or compact",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,23 @@
|
||||
"contact": {}
|
||||
},
|
||||
"paths": {
|
||||
"/api/auth/logout": {
|
||||
"get": {
|
||||
"description": "logs a user out of the application.",
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "User Logout",
|
||||
"responses": {
|
||||
"302": {
|
||||
"description": "Redirect to redirect URL if configured in oidc config.",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/createApiKey": {
|
||||
"post": {
|
||||
"description": "Create an API key with specified name, duration, and permissions.",
|
||||
@@ -1642,6 +1659,10 @@
|
||||
"methods": {
|
||||
"$ref": "#/definitions/settings.LoginMethods"
|
||||
},
|
||||
"resetAdminOnStart": {
|
||||
"description": "if set to true, the admin user will be reset to the default username and password on startup.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"tokenExpirationHours": {
|
||||
"description": "the number of hours until the token expires. Default is 2 hours.",
|
||||
"type": "integer"
|
||||
@@ -1783,19 +1804,7 @@
|
||||
},
|
||||
"settings.OidcConfig": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"authorizationUrl",
|
||||
"clientId",
|
||||
"clientSecret",
|
||||
"scopes",
|
||||
"tokenUrl",
|
||||
"userInfoUrl"
|
||||
],
|
||||
"properties": {
|
||||
"authorizationUrl": {
|
||||
"description": "authorization URL of the OIDC provider",
|
||||
"type": "string"
|
||||
},
|
||||
"clientId": {
|
||||
"description": "client id of the OIDC application",
|
||||
"type": "string"
|
||||
@@ -1804,28 +1813,28 @@
|
||||
"description": "client secret of the OIDC application",
|
||||
"type": "string"
|
||||
},
|
||||
"disableVerifyTLS": {
|
||||
"description": "disable TLS verification for the OIDC provider. This is insecure and should only be used for testing.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"enabled": {
|
||||
"description": "whether to enable OIDC authentication",
|
||||
"type": "boolean"
|
||||
},
|
||||
"jwksUrl": {
|
||||
"description": "currently not used by filebrowser",
|
||||
"issuerUrl": {
|
||||
"description": "authorization URL of the OIDC provider",
|
||||
"type": "string"
|
||||
},
|
||||
"logoutRedirectUrl": {
|
||||
"description": "if provider logout url is provided, filebrowser will also redirect to logout url. Custom logout query params are respected.",
|
||||
"type": "string"
|
||||
},
|
||||
"scopes": {
|
||||
"description": "space separated list of scopes to request from the OIDC provider",
|
||||
"type": "string"
|
||||
},
|
||||
"tokenUrl": {
|
||||
"description": "token URL of the OIDC provider",
|
||||
"description": "scopes to request from the OIDC provider",
|
||||
"type": "string"
|
||||
},
|
||||
"userIdentifier": {
|
||||
"description": "optional: which attribute should be used as the username? options: email, username, name, phone_number, sub",
|
||||
"type": "string"
|
||||
},
|
||||
"userInfoUrl": {
|
||||
"description": "user info URL of the OIDC provider",
|
||||
"description": "the user identifier to use for authentication. Default is \"username\", can be \"email\" or \"username\", or \"phone\"",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
@@ -2088,48 +2097,65 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"darkMode": {
|
||||
"description": "should dark mode be enabled",
|
||||
"type": "boolean"
|
||||
},
|
||||
"dateFormat": {
|
||||
"description": "when false, the date is relative, when true, the date is an exact timestamp",
|
||||
"type": "boolean"
|
||||
},
|
||||
"disableOnlyOfficeExt": {
|
||||
"description": "comma separated list of file extensions to disable onlyoffice preview for",
|
||||
"type": "string"
|
||||
},
|
||||
"disableSettings": {
|
||||
"description": "disable the user from viewing the settings page",
|
||||
"type": "boolean"
|
||||
},
|
||||
"gallerySize": {
|
||||
"description": "0-9 - the size of the gallery thumbnails",
|
||||
"type": "integer"
|
||||
},
|
||||
"locale": {
|
||||
"description": "language to use: eg. de, en, or fr",
|
||||
"type": "string"
|
||||
},
|
||||
"lockPassword": {
|
||||
"description": "disable the user from changing their password",
|
||||
"type": "boolean"
|
||||
},
|
||||
"loginMethod": {
|
||||
"description": "login method to use: eg. password, proxy, oidc",
|
||||
"type": "string"
|
||||
},
|
||||
"permissions": {
|
||||
"$ref": "#/definitions/users.Permissions"
|
||||
},
|
||||
"preview": {
|
||||
"$ref": "#/definitions/users.PreviewOptions"
|
||||
"$ref": "#/definitions/users.Preview"
|
||||
},
|
||||
"quickDownload": {
|
||||
"description": "show icon to download in one click",
|
||||
"type": "boolean"
|
||||
},
|
||||
"showHidden": {
|
||||
"description": "show hidden files in the UI. On windows this includes files starting with a dot and windows hidden files",
|
||||
"type": "boolean"
|
||||
},
|
||||
"singleClick": {
|
||||
"description": "open directory on single click, also enables middle click to open in new tab",
|
||||
"type": "boolean"
|
||||
},
|
||||
"stickySidebar": {
|
||||
"description": "keep sidebar open when navigating",
|
||||
"type": "boolean"
|
||||
},
|
||||
"themeColor": {
|
||||
"description": "theme color to use: eg. #ff0000, or var(--red), var(--purple), etc",
|
||||
"type": "string"
|
||||
},
|
||||
"viewMode": {
|
||||
"description": "view mode to use: eg. normal, list, grid, or compact",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
@@ -2231,22 +2257,31 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"users.PreviewOptions": {
|
||||
"users.Preview": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"highQuality": {
|
||||
"description": "generate high quality preview images",
|
||||
"type": "boolean"
|
||||
},
|
||||
"image": {
|
||||
"description": "show real image as icon instead of generic photo icon",
|
||||
"type": "boolean"
|
||||
},
|
||||
"motionVideoPreview": {
|
||||
"description": "show multiple frames for videos in preview when hovering",
|
||||
"type": "boolean"
|
||||
},
|
||||
"office": {
|
||||
"description": "show preview image for office files",
|
||||
"type": "boolean"
|
||||
},
|
||||
"popup": {
|
||||
"description": "show larger popup preview when hovering",
|
||||
"type": "boolean"
|
||||
},
|
||||
"video": {
|
||||
"description": "show preview image for video files",
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
@@ -2283,24 +2318,29 @@
|
||||
}
|
||||
},
|
||||
"darkMode": {
|
||||
"description": "should dark mode be enabled",
|
||||
"type": "boolean"
|
||||
},
|
||||
"dateFormat": {
|
||||
"description": "when false, the date is relative, when true, the date is an exact timestamp",
|
||||
"type": "boolean"
|
||||
},
|
||||
"disableOnlyOfficeExt": {
|
||||
"description": "comma separated list of file extensions to disable onlyoffice preview for",
|
||||
"type": "string"
|
||||
},
|
||||
"disableSettings": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"gallerySize": {
|
||||
"description": "0-9 - the size of the gallery thumbnails",
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"locale": {
|
||||
"description": "language to use: eg. de, en, or fr",
|
||||
"type": "string"
|
||||
},
|
||||
"lockPassword": {
|
||||
@@ -2324,9 +2364,10 @@
|
||||
"$ref": "#/definitions/users.Permissions"
|
||||
},
|
||||
"preview": {
|
||||
"$ref": "#/definitions/users.PreviewOptions"
|
||||
"$ref": "#/definitions/users.Preview"
|
||||
},
|
||||
"quickDownload": {
|
||||
"description": "show icon to download in one click",
|
||||
"type": "boolean"
|
||||
},
|
||||
"scope": {
|
||||
@@ -2339,24 +2380,29 @@
|
||||
}
|
||||
},
|
||||
"showHidden": {
|
||||
"description": "show hidden files in the UI. On windows this includes files starting with a dot and windows hidden files",
|
||||
"type": "boolean"
|
||||
},
|
||||
"singleClick": {
|
||||
"description": "open directory on single click, also enables middle click to open in new tab",
|
||||
"type": "boolean"
|
||||
},
|
||||
"sorting": {
|
||||
"$ref": "#/definitions/users.Sorting"
|
||||
},
|
||||
"stickySidebar": {
|
||||
"description": "keep sidebar open when navigating",
|
||||
"type": "boolean"
|
||||
},
|
||||
"themeColor": {
|
||||
"description": "theme color to use: eg. #ff0000, or var(--red), var(--purple), etc",
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
"viewMode": {
|
||||
"description": "view mode to use: eg. normal, list, grid, or compact",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,10 @@ definitions:
|
||||
type: string
|
||||
methods:
|
||||
$ref: '#/definitions/settings.LoginMethods'
|
||||
resetAdminOnStart:
|
||||
description: if set to true, the admin user will be reset to the default username
|
||||
and password on startup.
|
||||
type: boolean
|
||||
tokenExpirationHours:
|
||||
description: the number of hours until the token expires. Default is 2 hours.
|
||||
type: integer
|
||||
@@ -199,41 +203,33 @@ definitions:
|
||||
type: object
|
||||
settings.OidcConfig:
|
||||
properties:
|
||||
authorizationUrl:
|
||||
description: authorization URL of the OIDC provider
|
||||
type: string
|
||||
clientId:
|
||||
description: client id of the OIDC application
|
||||
type: string
|
||||
clientSecret:
|
||||
description: client secret of the OIDC application
|
||||
type: string
|
||||
disableVerifyTLS:
|
||||
description: disable TLS verification for the OIDC provider. This is insecure
|
||||
and should only be used for testing.
|
||||
type: boolean
|
||||
enabled:
|
||||
description: whether to enable OIDC authentication
|
||||
type: boolean
|
||||
jwksUrl:
|
||||
description: currently not used by filebrowser
|
||||
issuerUrl:
|
||||
description: authorization URL of the OIDC provider
|
||||
type: string
|
||||
logoutRedirectUrl:
|
||||
description: if provider logout url is provided, filebrowser will also redirect
|
||||
to logout url. Custom logout query params are respected.
|
||||
type: string
|
||||
scopes:
|
||||
description: space separated list of scopes to request from the OIDC provider
|
||||
type: string
|
||||
tokenUrl:
|
||||
description: token URL of the OIDC provider
|
||||
description: scopes to request from the OIDC provider
|
||||
type: string
|
||||
userIdentifier:
|
||||
description: 'optional: which attribute should be used as the username? options:
|
||||
email, username, name, phone_number, sub'
|
||||
description: the user identifier to use for authentication. Default is "username",
|
||||
can be "email" or "username", or "phone"
|
||||
type: string
|
||||
userInfoUrl:
|
||||
description: user info URL of the OIDC provider
|
||||
type: string
|
||||
required:
|
||||
- authorizationUrl
|
||||
- clientId
|
||||
- clientSecret
|
||||
- scopes
|
||||
- tokenUrl
|
||||
- userInfoUrl
|
||||
type: object
|
||||
settings.OnlyOffice:
|
||||
properties:
|
||||
@@ -421,34 +417,55 @@ definitions:
|
||||
settings.UserDefaults:
|
||||
properties:
|
||||
darkMode:
|
||||
description: should dark mode be enabled
|
||||
type: boolean
|
||||
dateFormat:
|
||||
description: when false, the date is relative, when true, the date is an exact
|
||||
timestamp
|
||||
type: boolean
|
||||
disableOnlyOfficeExt:
|
||||
description: comma separated list of file extensions to disable onlyoffice
|
||||
preview for
|
||||
type: string
|
||||
disableSettings:
|
||||
description: disable the user from viewing the settings page
|
||||
type: boolean
|
||||
gallerySize:
|
||||
description: 0-9 - the size of the gallery thumbnails
|
||||
type: integer
|
||||
locale:
|
||||
description: 'language to use: eg. de, en, or fr'
|
||||
type: string
|
||||
lockPassword:
|
||||
description: disable the user from changing their password
|
||||
type: boolean
|
||||
loginMethod:
|
||||
description: 'login method to use: eg. password, proxy, oidc'
|
||||
type: string
|
||||
permissions:
|
||||
$ref: '#/definitions/users.Permissions'
|
||||
preview:
|
||||
$ref: '#/definitions/users.PreviewOptions'
|
||||
$ref: '#/definitions/users.Preview'
|
||||
quickDownload:
|
||||
description: show icon to download in one click
|
||||
type: boolean
|
||||
showHidden:
|
||||
description: show hidden files in the UI. On windows this includes files starting
|
||||
with a dot and windows hidden files
|
||||
type: boolean
|
||||
singleClick:
|
||||
description: open directory on single click, also enables middle click to
|
||||
open in new tab
|
||||
type: boolean
|
||||
stickySidebar:
|
||||
description: keep sidebar open when navigating
|
||||
type: boolean
|
||||
themeColor:
|
||||
description: 'theme color to use: eg. #ff0000, or var(--red), var(--purple),
|
||||
etc'
|
||||
type: string
|
||||
viewMode:
|
||||
description: 'view mode to use: eg. normal, list, grid, or compact'
|
||||
type: string
|
||||
type: object
|
||||
share.CreateBody:
|
||||
@@ -519,17 +536,25 @@ definitions:
|
||||
share:
|
||||
type: boolean
|
||||
type: object
|
||||
users.PreviewOptions:
|
||||
users.Preview:
|
||||
properties:
|
||||
highQuality:
|
||||
description: generate high quality preview images
|
||||
type: boolean
|
||||
image:
|
||||
description: show real image as icon instead of generic photo icon
|
||||
type: boolean
|
||||
motionVideoPreview:
|
||||
description: show multiple frames for videos in preview when hovering
|
||||
type: boolean
|
||||
office:
|
||||
description: show preview image for office files
|
||||
type: boolean
|
||||
popup:
|
||||
description: show larger popup preview when hovering
|
||||
type: boolean
|
||||
video:
|
||||
description: show preview image for video files
|
||||
type: boolean
|
||||
type: object
|
||||
users.Sorting:
|
||||
@@ -553,18 +578,25 @@ definitions:
|
||||
$ref: '#/definitions/users.AuthToken'
|
||||
type: object
|
||||
darkMode:
|
||||
description: should dark mode be enabled
|
||||
type: boolean
|
||||
dateFormat:
|
||||
description: when false, the date is relative, when true, the date is an exact
|
||||
timestamp
|
||||
type: boolean
|
||||
disableOnlyOfficeExt:
|
||||
description: comma separated list of file extensions to disable onlyoffice
|
||||
preview for
|
||||
type: string
|
||||
disableSettings:
|
||||
type: boolean
|
||||
gallerySize:
|
||||
description: 0-9 - the size of the gallery thumbnails
|
||||
type: integer
|
||||
id:
|
||||
type: integer
|
||||
locale:
|
||||
description: 'language to use: eg. de, en, or fr'
|
||||
type: string
|
||||
lockPassword:
|
||||
type: boolean
|
||||
@@ -579,8 +611,9 @@ definitions:
|
||||
permissions:
|
||||
$ref: '#/definitions/users.Permissions'
|
||||
preview:
|
||||
$ref: '#/definitions/users.PreviewOptions'
|
||||
$ref: '#/definitions/users.Preview'
|
||||
quickDownload:
|
||||
description: show icon to download in one click
|
||||
type: boolean
|
||||
scope:
|
||||
type: string
|
||||
@@ -589,23 +622,42 @@ definitions:
|
||||
$ref: '#/definitions/users.SourceScope'
|
||||
type: array
|
||||
showHidden:
|
||||
description: show hidden files in the UI. On windows this includes files starting
|
||||
with a dot and windows hidden files
|
||||
type: boolean
|
||||
singleClick:
|
||||
description: open directory on single click, also enables middle click to
|
||||
open in new tab
|
||||
type: boolean
|
||||
sorting:
|
||||
$ref: '#/definitions/users.Sorting'
|
||||
stickySidebar:
|
||||
description: keep sidebar open when navigating
|
||||
type: boolean
|
||||
themeColor:
|
||||
description: 'theme color to use: eg. #ff0000, or var(--red), var(--purple),
|
||||
etc'
|
||||
type: string
|
||||
username:
|
||||
type: string
|
||||
viewMode:
|
||||
description: 'view mode to use: eg. normal, list, grid, or compact'
|
||||
type: string
|
||||
type: object
|
||||
info:
|
||||
contact: {}
|
||||
paths:
|
||||
/api/auth/logout:
|
||||
get:
|
||||
description: logs a user out of the application.
|
||||
responses:
|
||||
"302":
|
||||
description: Redirect to redirect URL if configured in oidc config.
|
||||
schema:
|
||||
type: string
|
||||
summary: User Logout
|
||||
tags:
|
||||
- Auth
|
||||
/api/createApiKey:
|
||||
post:
|
||||
consumes:
|
||||
|
||||
@@ -116,12 +116,13 @@ func buildNode(v reflect.Value, comm commentsMap) (*yaml.Node, error) {
|
||||
|
||||
// attach validate and comments inline
|
||||
var parts []string
|
||||
if vt := sf.Tag.Get("validate"); vt != "" {
|
||||
parts = append(parts, fmt.Sprintf("validate:%s", vt))
|
||||
}
|
||||
if cm := comm[typeName][sf.Name]; cm != "" {
|
||||
parts = append(parts, fmt.Sprintf("comments:\"%s\"", cm))
|
||||
parts = append(parts, fmt.Sprintf("\"%s\"", cm))
|
||||
}
|
||||
if vt := sf.Tag.Get("validate"); vt != "" {
|
||||
parts = append(parts, fmt.Sprintf(" validate:%s", vt))
|
||||
}
|
||||
|
||||
if len(parts) > 0 {
|
||||
keyNode.LineComment = strings.Join(parts, " ")
|
||||
}
|
||||
|
||||
+40
-1
@@ -6,9 +6,48 @@
|
||||
"extends": [
|
||||
"plugin:vue/vue3-essential",
|
||||
"eslint:recommended",
|
||||
"@vue/eslint-config-typescript"
|
||||
"@vue/eslint-config-typescript",
|
||||
"plugin:@intlify/vue-i18n/recommended"
|
||||
],
|
||||
"settings": {
|
||||
"vue-i18n": {
|
||||
// Path to your locale message directory or a glob pattern.
|
||||
// The plugin will use these files to determine available keys.
|
||||
// Make sure 'en.json' is present here.
|
||||
"localeDir": "./src/i18n/*.json"
|
||||
|
||||
// If your i18n instance is initialized with a fallbackLocale,
|
||||
// the linter might use that. Ensure 'en' is effectively the master.
|
||||
// fallbackLocale: 'en', // This might be part of your i18n setup, not ESLint settings
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
// vue-i18n rules:
|
||||
// This rule will check if the key used in $t() exists in your locale messages.
|
||||
// By default, it checks against all locales. We want it to primarily use 'en.json'
|
||||
// as the source of truth. The plugin often infers this from your i18n setup,
|
||||
// but we want to be explicit or ensure our sync script makes 'en.json' the master.
|
||||
"@intlify/vue-i18n/no-missing-keys": "error",
|
||||
// Optional: Warn about unused keys in your 'en.json'
|
||||
// This requires configuring the `localeDir` setting below.
|
||||
"@intlify/vue-i18n/no-unused-keys": ["warn", {
|
||||
"src": "./src", // Path to your source files
|
||||
"extensions": [".js", ".vue"]
|
||||
// Important: This tells the rule to check unused keys specifically in en.json
|
||||
// by making it the single source of truth for what "should" exist.
|
||||
// However, the rule usually checks keys NOT used in your Vue code.
|
||||
// The primary goal is `no-missing-keys` for keys used in the template.
|
||||
}],
|
||||
|
||||
"@intlify/vue-i18n/no-raw-text": [
|
||||
"warn",
|
||||
{
|
||||
"ignoreNodes": ["i", "v-icon"]
|
||||
}
|
||||
],
|
||||
|
||||
// If you have your sync script, you might not need this one for other locales.
|
||||
"@intlify/vue-i18n/no-missing-keys-in-other-locales": "off",
|
||||
"vue/multi-word-component-names": "off",
|
||||
"vue/no-mutating-props": [
|
||||
"error",
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"typecheck": "vue-tsc -p ./tsconfig.json --noEmit",
|
||||
"lint": "eslint --ext .js,.vue,ts src",
|
||||
"lint:fix": "eslint --fix src/",
|
||||
"i18n:sync": "node ./scripts/sync-translations.js",
|
||||
"format": "prettier --write .",
|
||||
"test": "vitest run "
|
||||
},
|
||||
@@ -37,13 +38,16 @@
|
||||
"vue-router": "^4.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@intlify/eslint-plugin-vue-i18n": "^3.2.0",
|
||||
"@intlify/unplugin-vue-i18n": "^4.0.0",
|
||||
"@playwright/test": "^1.49.1",
|
||||
"@vitejs/plugin-vue": "^5.0.4",
|
||||
"@vue/eslint-config-typescript": "^13.0.0",
|
||||
"deepl-node": "^1.18.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-vue": "^9.24.0",
|
||||
"fs-extra": "^11.3.0",
|
||||
"jsdom": "^25.0.1",
|
||||
"vite": "^6.2.0",
|
||||
"vite-plugin-compression2": "^1.0.0",
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
server:
|
||||
numImageProcessors: 0 # "number of concurrent image processing jobs"
|
||||
socket: "" # "socket to listen on"
|
||||
tlsKey: "" # "path to TLS key"
|
||||
tlsCert: "" # "path to TLS cert"
|
||||
disablePreviews: false # "disable all previews thumbnails, simple icons will be used"
|
||||
disablePreviewResize: false # "disable resizing of previews for faster loading over slow connections"
|
||||
disableTypeDetectionByHeader: false # "disable type detection by header, useful if filesystem is slow."
|
||||
port: 0 # "port to listen on"
|
||||
baseURL: "" # "base URL for the server, the subpath that the server is running on."
|
||||
logging:
|
||||
- levels: "" # "separated list of log levels to enable. (eg. "info|warning|error|debug")"
|
||||
apiLevels: "" # "separated list of log levels to enable for the API. (eg. "info|warning|error")"
|
||||
output: "" # "output location. (eg. "stdout" or "path/to/file.log")"
|
||||
noColors: false # "disable colors in the output"
|
||||
json: false # "output in json format, currently not supported"
|
||||
database: "" # "path to the database file"
|
||||
sources: # validate:required,dive
|
||||
- path: "" # "file system path. (Can be relative)" validate:required
|
||||
name: "" # "display name"
|
||||
config:
|
||||
indexingInterval: 0 # "optional manual overide interval in seconds to re-index the source"
|
||||
disabled: false # "disable the indexing of this source"
|
||||
maxWatchers: 0 # "number of concurrent watchers to use for this source, currently not supported"
|
||||
neverWatchPaths: []
|
||||
ignoreHidden: false # "ignore hidden files and folders."
|
||||
ignoreZeroSizeFolders: false # "ignore folders with 0 size"
|
||||
exclude: # "exclude files and folders from indexing, if include is not set"
|
||||
files: []
|
||||
folders: []
|
||||
fileEndsWith: []
|
||||
include: # "include files and folders from indexing, if exclude is not set"
|
||||
files: []
|
||||
folders: []
|
||||
fileEndsWith: []
|
||||
defaultUserScope: "" # "default "/" should match folders under path"
|
||||
defaultEnabled: false # "should be added as a default source for new users?"
|
||||
createUserDir: false # "create a user directory for each user"
|
||||
externalUrl: "" # "used by share links if set"
|
||||
internalUrl: "" # "used by integrations if set, this is the url that an integration service will use to communicate with filebrowser"
|
||||
cacheDir: "" # "path to the cache directory, used for thumbnails and other cached files"
|
||||
maxArchiveSize: 0 # "max pre-archive combined size of files/folder that are allowed to be archived (in GB)"
|
||||
auth:
|
||||
tokenExpirationHours: 0 # "the number of hours until the token expires. Default is 2 hours."
|
||||
methods:
|
||||
proxy: # validate:omitempty
|
||||
enabled: false
|
||||
createUser: false # "create user if not exists"
|
||||
header: "" # "required header to use for authentication. Security Warning: FileBrowser blindly accepts the header value as username."
|
||||
noauth: false # "if set to true, overrides all other auth methods and disables authentication"
|
||||
password: # validate:omitempty
|
||||
enabled: false
|
||||
minLength: 0 # validate:omitempty,min=5
|
||||
signup: false # "currently not used by filebrowser" validate:omitempty
|
||||
recaptcha: # "recaptcha config, only used if signup is enabled" validate:omitempty
|
||||
host: "" # validate:required
|
||||
key: "" # validate:required
|
||||
secret: "" # validate:required
|
||||
oidc: # validate:omitempty
|
||||
enabled: false # "whether to enable OIDC authentication"
|
||||
clientId: "" # "client id of the OIDC application"
|
||||
clientSecret: "" # "client secret of the OIDC application"
|
||||
issuerUrl: "" # "authorization URL of the OIDC provider"
|
||||
scopes: "" # "scopes to request from the OIDC provider"
|
||||
userIdentifier: "" # "the user identifier to use for authentication. Default is "username", can be "email" or "username", or "phone""
|
||||
disableVerifyTLS: false # "disable TLS verification for the OIDC provider. This is insecure and should only be used for testing."
|
||||
logoutRedirectUrl: "" # "if provider logout url is provided, filebrowser will also redirect to logout url. Custom logout query params are respected."
|
||||
key: "" # "the key used to sign the JWT tokens. If not set, a random key will be generated."
|
||||
adminUsername: "" # "the username of the admin user. If not set, the default is "admin"."
|
||||
adminPassword: "" # "the password of the admin user. If not set, the default is "admin"."
|
||||
resetAdminOnStart: false # "if set to true, the admin user will be reset to the default username and password on startup."
|
||||
frontend:
|
||||
name: "" # "display name"
|
||||
disableDefaultLinks: false # "disable default links in the sidebar"
|
||||
disableUsedPercentage: false # "disable used percentage for the sources in the sidebar"
|
||||
externalLinks:
|
||||
- text: "" # "the text to display on the link" validate:required
|
||||
title: "" # "the title to display on hover"
|
||||
url: "" # "the url to link to" validate:required
|
||||
userDefaults:
|
||||
stickySidebar: false # "keep sidebar open when navigating"
|
||||
darkMode: false # "should dark mode be enabled"
|
||||
locale: "" # "language to use: eg. de, en, or fr"
|
||||
viewMode: "" # "view mode to use: eg. normal, list, grid, or compact"
|
||||
singleClick: false # "open directory on single click, also enables middle click to open in new tab"
|
||||
showHidden: false # "show hidden files in the UI. On windows this includes files starting with a dot and windows hidden files"
|
||||
dateFormat: false # "when false, the date is relative, when true, the date is an exact timestamp"
|
||||
gallerySize: 0 # "0-9 - the size of the gallery thumbnails"
|
||||
themeColor: "" # "theme color to use: eg. #ff0000, or var(--red), var(--purple), etc"
|
||||
quickDownload: false # "show icon to download in one click"
|
||||
disableOnlyOfficeExt: "" # "comma separated list of file extensions to disable onlyoffice preview for"
|
||||
lockPassword: false # "disable the user from changing their password"
|
||||
disableSettings: false # "disable the user from viewing the settings page"
|
||||
preview:
|
||||
highQuality: false
|
||||
image: false
|
||||
video: false
|
||||
motionVideoPreview: false
|
||||
office: false
|
||||
popup: false
|
||||
permissions:
|
||||
api: false
|
||||
admin: false
|
||||
modify: false
|
||||
share: false
|
||||
realtime: false
|
||||
loginMethod: "" # "login method to use: eg. password, proxy, oidc"
|
||||
integrations:
|
||||
office: # validate:omitempty
|
||||
url: "" # "The URL to the OnlyOffice Document Server, needs to be accessible to the user." validate:required
|
||||
internalUrl: "" # "An optional internal address that the filebrowser server can use to communicate with the OnlyOffice Document Server, could be useful to bypass proxy."
|
||||
secret: "" # validate:required
|
||||
media: # validate:omitempty
|
||||
ffmpegPath: "" # "path to ffmpeg directory with ffmpeg and ffprobe (eg. /usr/local/bin)"
|
||||
@@ -0,0 +1,152 @@
|
||||
// scripts/sync-translations.js
|
||||
import fs from 'fs-extra';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import glob from 'glob';
|
||||
import * as deepl from 'deepl-node';
|
||||
|
||||
// --- Configuration ---
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const localesDir = path.resolve(__dirname, '../src/i18n');
|
||||
const masterLocaleFile = path.join(localesDir, 'en.json');
|
||||
const masterLanguageCode = 'en';
|
||||
const targetLocaleFiles = glob.sync(path.join(localesDir, '*.json'))
|
||||
.filter(file => path.basename(file) !== `${masterLanguageCode}.json`);
|
||||
|
||||
const DEEPL_API_KEY = process.env.DEEPL_API_KEY;
|
||||
if (!DEEPL_API_KEY) {
|
||||
console.error("❌ Missing DEEPL_API_KEY in environment.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const translator = new deepl.Translator(DEEPL_API_KEY);
|
||||
|
||||
// --- Translation Function using DeepL ---
|
||||
async function translateText(text, targetLanguage, keyPath = '') {
|
||||
if (!text || typeof text !== 'string' || text.trim() === '') {
|
||||
console.warn(`Skipping translation for empty or non-string text: "${text}"`);
|
||||
return text;
|
||||
}
|
||||
|
||||
if (keyPath === 'languages' || keyPath.startsWith('languages.')) {
|
||||
return text;
|
||||
}
|
||||
|
||||
if (/\{[^}]+\}/.test(text)) {
|
||||
console.log(`Skipping translation for placeholder string: "${text}"`);
|
||||
return text;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(`Translating "${text}" from '${masterLanguageCode}' to '${targetLanguage}'...`);
|
||||
|
||||
const result = await translator.translateText(text, masterLanguageCode, targetLanguage.toUpperCase());
|
||||
|
||||
// Delay to avoid rate-limiting
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
return result.text;
|
||||
|
||||
} catch (err) {
|
||||
console.error(`⚠️ Translation failed for "${text}" (${keyPath}):`, err?.message || err);
|
||||
return ``;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Recursive key processor ---
|
||||
async function processKeys(masterObj, targetObj, targetLangCode, currentPathParts = []) {
|
||||
let changesMade = false;
|
||||
for (const key in masterObj) {
|
||||
if (Object.prototype.hasOwnProperty.call(masterObj, key)) {
|
||||
const currentPathPartsNext = [...currentPathParts, key];
|
||||
const currentKeyPath = currentPathPartsNext.join('.');
|
||||
if (currentPathParts[0] === 'languages') continue;
|
||||
|
||||
const masterValue = masterObj[key];
|
||||
|
||||
if (typeof masterValue === 'object' && masterValue !== null && !Array.isArray(masterValue)) {
|
||||
if (!targetObj[key] || typeof targetObj[key] !== 'object') {
|
||||
console.log(`Creating missing object structure for "${currentKeyPath}" in ${targetLangCode}.json`);
|
||||
targetObj[key] = {};
|
||||
changesMade = true;
|
||||
}
|
||||
const result = await processKeys(masterValue, targetObj[key], targetLangCode, currentPathPartsNext);
|
||||
if (result == "UNSUPPORTED") {
|
||||
console.log(`Skipping translation for "${targetLangCode}" due to unsupported structure.`);
|
||||
return "UNSUPPORTED";
|
||||
}
|
||||
if (result) {
|
||||
changesMade = true;
|
||||
}
|
||||
} else if (typeof masterValue === 'string') {
|
||||
if (!targetObj.hasOwnProperty(key) || targetObj[key] === '' || targetObj[key] === null) {
|
||||
const result = await translateText(masterValue, targetLangCode, currentKeyPath);
|
||||
if (result == "") {
|
||||
return "UNSUPPORTED";
|
||||
}
|
||||
targetObj[key] = result;
|
||||
changesMade = true;
|
||||
}
|
||||
} else {
|
||||
if (!targetObj.hasOwnProperty(key)) {
|
||||
console.log(`Key "${currentKeyPath}" (non-string) missing in ${targetLangCode}.json. Copying from English.`);
|
||||
targetObj[key] = masterValue;
|
||||
changesMade = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return changesMade;
|
||||
}
|
||||
|
||||
// --- Main synchronization ---
|
||||
async function syncAllTranslations() {
|
||||
console.warn("--- Using DeepL API for translation ---");
|
||||
|
||||
if (!await fs.pathExists(masterLocaleFile)) {
|
||||
console.error(`Master locale file not found: ${masterLocaleFile}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const masterContent = await fs.readJson(masterLocaleFile);
|
||||
console.log(`Loaded master translations from ${masterLocaleFile}`);
|
||||
|
||||
for (const targetFile of targetLocaleFiles) {
|
||||
const targetLangCode = path.basename(targetFile, '.json');
|
||||
let targetContent = {};
|
||||
let fileExisted = await fs.pathExists(targetFile);
|
||||
|
||||
if (fileExisted) {
|
||||
try {
|
||||
targetContent = await fs.readJson(targetFile);
|
||||
console.log(`\nProcessing target language: ${targetLangCode} (from ${targetFile})`);
|
||||
} catch (e) {
|
||||
console.warn(`Warning: Could not parse ${targetFile}. Starting fresh. Error: ${e.message}`);
|
||||
targetContent = {};
|
||||
}
|
||||
} else {
|
||||
console.log(`\nTarget file ${targetFile} not found. Will create for language: ${targetLangCode}.`);
|
||||
}
|
||||
|
||||
const wasUpdated = await processKeys(masterContent, targetContent, targetLangCode);
|
||||
|
||||
if (wasUpdated || !fileExisted) {
|
||||
try {
|
||||
await fs.writeJson(targetFile, targetContent, { spaces: 2 });
|
||||
console.log(`Successfully ${wasUpdated ? 'updated' : 'created'} ${targetFile}`);
|
||||
} catch (error) {
|
||||
console.error(`Error writing to ${targetFile}:`, error);
|
||||
}
|
||||
} else {
|
||||
console.log(`No changes needed for ${targetFile}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n✅ Translation synchronization complete (via DeepL).');
|
||||
}
|
||||
|
||||
syncAllTranslations().catch(error => {
|
||||
console.error("\n❌ An error occurred during translation synchronization:", error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -230,7 +230,7 @@ export function getPreviewURL(source, path, modified) {
|
||||
const params = {
|
||||
path: encodeURIComponent(path),
|
||||
size: state.user.preview.highQuality ? 'large' : 'small',
|
||||
key: Date.parse(modified),
|
||||
key: Date.parse(modified), // Use modified date as cache key
|
||||
source: source,
|
||||
inline: 'true'
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ export default {
|
||||
return state.req;
|
||||
},
|
||||
multistate() {
|
||||
if (!state.multiButtonState) {
|
||||
if (!state.multiButtonState && getters.currentView() == "settings") {
|
||||
return "close";
|
||||
}
|
||||
return state.multiButtonState;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
<div v-if="isCardView" class="gallery-size">
|
||||
Size:
|
||||
{{ $t('files.size') }}:<span class="sr-only">:</span> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<input
|
||||
v-model="gallerySize"
|
||||
type="range"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
:class="{ 'dark-mode': isDarkMode, centered: centered }"
|
||||
>
|
||||
<div v-if="selectedCount > 0" class="button selected-count-header">
|
||||
<span>{{ selectedCount }} selected</span>
|
||||
<span>{{ selectedCount }} {{ $t('prompts.selected') }} </span>
|
||||
</div>
|
||||
|
||||
<action
|
||||
@@ -265,7 +265,8 @@ export default {
|
||||
buttons.done(button);
|
||||
notify.showError("Error saving file: ", e);
|
||||
}
|
||||
mutations.closeHovers();
|
||||
|
||||
mutations.closeHovers();
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="card" id="popup-notification">
|
||||
<i v-on:click="closePopUp" class="material-icons">close</i>
|
||||
<canvas class="notification-spinner hidden" width="100" height="100"></canvas>
|
||||
<div id="popup-notification-content">no info</div>
|
||||
<div id="popup-notification-content"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
<!-- Inputs for filtering by file size -->
|
||||
<div class="sizeConstraints">
|
||||
<div class="sizeInputWrapper">
|
||||
<p>Smaller Than:</p>
|
||||
<p> {{ $t('search.smallerThan') }} </p>
|
||||
<input
|
||||
class="sizeInput"
|
||||
v-model="smallerThan"
|
||||
@@ -89,17 +89,17 @@
|
||||
min="0"
|
||||
placeholder="number"
|
||||
/>
|
||||
<p>MB</p>
|
||||
<p>MB</p> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
</div>
|
||||
<div class="sizeInputWrapper">
|
||||
<p>Larger Than:</p>
|
||||
<p> {{ $t('search.largerThan') }} </p>
|
||||
<input
|
||||
class="sizeInput"
|
||||
v-model="largerThan"
|
||||
type="number"
|
||||
placeholder="number"
|
||||
/>
|
||||
<p>MB</p>
|
||||
<p>MB</p> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -112,27 +112,12 @@
|
||||
<!-- Message when no results are found -->
|
||||
<div class="searchPrompt" v-show="isEmpty && !isRunning">
|
||||
<p>{{ noneMessage }}</p>
|
||||
<div class="helpButton" @click="toggleHelp()">Help</div>
|
||||
<div class="helpButton" @click="toggleHelp()"> {{ $t('sidebar.help') }} </div>
|
||||
</div>
|
||||
<!-- Help text section -->
|
||||
<div class="helpText" v-if="showHelp">
|
||||
<p>
|
||||
Search occurs on each character you type (3 character minimum for search
|
||||
terms).
|
||||
</p>
|
||||
<p>
|
||||
<b>The index:</b> Search utilizes the index which automatically gets updated
|
||||
on the configured interval (default: 5 minutes). Searching when the program
|
||||
has just started may result in incomplete results.
|
||||
</p>
|
||||
<p>
|
||||
<b>Filter by type:</b> You can have multiple type filters by adding
|
||||
<code>type:condition</code> followed by search terms.
|
||||
</p>
|
||||
<p>
|
||||
<b>Multiple Search terms:</b> Additional terms separated by <code>|</code>,
|
||||
for example <code>"test|not"</code> searches for both terms independently.
|
||||
</p>
|
||||
<p>{{ $t('search.helpText1') }}</p>
|
||||
<p>{{ $t('search.helpText2') }}</p>
|
||||
</div>
|
||||
<!-- List of search results -->
|
||||
<ul v-show="results.length > 0">
|
||||
@@ -146,7 +131,7 @@
|
||||
<a :href="getRelative(s.path)" @contextmenu="addSelected(event, s)">
|
||||
<Icon :mimetype="s.type" />
|
||||
<span class="text-container">
|
||||
{{ basePath(s.path, s.type == "directory") }}/{{ baseName(s.path) }}/
|
||||
{{ basePath(s.path, s.type == "directory") }}/{{ baseName(s.path) }}/ <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
</span>
|
||||
<div class="filesize">{{ humanSize(s.size) }}</div>
|
||||
</a>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="image-ex-container" ref="container" @touchstart="touchStart" @touchmove="touchMove" @dblclick="zoomAuto"
|
||||
@mousedown="mousedownStart" @mousemove="mouseMove" @mouseup="mouseUp" @wheel="wheelMove">
|
||||
<div v-if="!isLoaded">Loading image...</div>
|
||||
<div v-if="!isLoaded">{{ $t('files.loading') }}</div>
|
||||
|
||||
<img v-if="!isTiff && isLoaded" :src="src" class="image-ex-img" ref="imgex" @load="onLoad" />
|
||||
<canvas v-else-if="isLoaded" ref="imgex" class="image-ex-img"></canvas>
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
<template>
|
||||
<span v-if="isPreviewImg">
|
||||
<i
|
||||
v-if="hasMotion"
|
||||
class="material-icons"
|
||||
:class="{ larger: showLarger, smaller: !showLarger }"
|
||||
>animation</i
|
||||
>
|
||||
<img
|
||||
@mouseenter="handleMouseEnter($event)"
|
||||
@mouseleave="handleMouseLeave($event)"
|
||||
v-lazy="thumbnailUrl"
|
||||
:src="currentThumbnail"
|
||||
class="icon"
|
||||
ref="thumbnail"
|
||||
/>
|
||||
@@ -38,9 +45,22 @@ export default {
|
||||
materialIcon: "",
|
||||
classes: "",
|
||||
svgPath: "",
|
||||
previewTimeouts: [], // Store timeout IDs
|
||||
currentThumbnail: this.thumbnailUrl,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
showLarger() {
|
||||
return state.user.viewMode === "gallery" || state.user.viewMode === "normal";
|
||||
},
|
||||
hasMotion() {
|
||||
return (
|
||||
this.getIconForType().simpleType === "video" &&
|
||||
state.user.preview?.video &&
|
||||
mediaAvailable &&
|
||||
state.user.preview.motionVideoPreview
|
||||
);
|
||||
},
|
||||
isMaterialIcon() {
|
||||
return this.materialIcon !== "";
|
||||
},
|
||||
@@ -81,14 +101,64 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
handleMouseEnter() {
|
||||
if (state.user.viewMode == "gallery" && !state.user.preview.highQuality) {
|
||||
// skip popup for gallary view with small images
|
||||
if (state.user.viewMode === "gallery" && !state.user.preview.highQuality) {
|
||||
return;
|
||||
}
|
||||
|
||||
mutations.setPreviewSource(this.thumbnailUrl);
|
||||
|
||||
if (!state.user.preview.motionVideoPreview) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sequence = [
|
||||
this.thumbnailUrl,
|
||||
this.thumbnailUrl + "&atPercentage=25",
|
||||
this.thumbnailUrl + "&atPercentage=50",
|
||||
this.thumbnailUrl + "&atPercentage=75",
|
||||
];
|
||||
|
||||
let index = 0;
|
||||
|
||||
const updateThumbnailUrl = () => {
|
||||
if (state.popupPreviewSource === "") {
|
||||
this.previewTimeouts.forEach(clearTimeout);
|
||||
this.previewTimeouts = [];
|
||||
return;
|
||||
}
|
||||
|
||||
const currentUrl = sequence[index];
|
||||
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
// Set the thumbnail or popup preview
|
||||
if (state.user.preview.popup) {
|
||||
mutations.setPreviewSource(currentUrl);
|
||||
} else {
|
||||
this.currentThumbnail = currentUrl;
|
||||
}
|
||||
|
||||
// Preload the next image if it exists
|
||||
const nextIndex = (index + 1) % sequence.length;
|
||||
const nextUrl = sequence[nextIndex];
|
||||
const preloadImg = new Image();
|
||||
preloadImg.src = nextUrl;
|
||||
|
||||
// Schedule next update
|
||||
index = nextIndex;
|
||||
const timeoutId = setTimeout(updateThumbnailUrl, 750);
|
||||
this.previewTimeouts.push(timeoutId);
|
||||
};
|
||||
|
||||
img.src = currentUrl;
|
||||
};
|
||||
updateThumbnailUrl();
|
||||
},
|
||||
handleMouseLeave() {
|
||||
this.previewTimeouts.forEach(clearTimeout);
|
||||
this.previewTimeouts = [];
|
||||
mutations.setPreviewSource("");
|
||||
this.currentThumbnail = this.thumbnailUrl;
|
||||
},
|
||||
getIconForType() {
|
||||
return getTypeInfo(this.mimetype);
|
||||
@@ -105,6 +175,20 @@ export default {
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.larger {
|
||||
position: absolute;
|
||||
opacity: 0.5;
|
||||
padding: 0.1em !important;
|
||||
font-size: 2em !important;
|
||||
}
|
||||
|
||||
.smaller {
|
||||
position: absolute;
|
||||
opacity: 0.5;
|
||||
padding: 0.1em !important;
|
||||
font-size: 1em !important;
|
||||
}
|
||||
|
||||
.file-icons [aria-label^="."] {
|
||||
opacity: 0.33;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
</div>
|
||||
<div v-else class="thumb-letters no-select">
|
||||
<i class="material-icons" :class="{ 'primary-icons': isFolder }">
|
||||
{{ isFolder ? "folder" : "description" }}
|
||||
{{ isFolder ? "folder" : "description" }} <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="card floating">
|
||||
<div class="card-title">
|
||||
<h2>API Key Details</h2>
|
||||
<h2>{{ $t('api.title') }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
@@ -11,20 +11,20 @@
|
||||
:aria-label="$t('buttons.copyToClipboard')"
|
||||
:title="$t('buttons.copyToClipboard')"
|
||||
>
|
||||
API Key Name : {{ name }}
|
||||
{{ $t('api.keyName') }}{{ name }}
|
||||
<i class="material-icons">content_paste</i>
|
||||
</button>
|
||||
|
||||
<h3>Created At :</h3>
|
||||
<h3>{{ $t('api.createdAt') }}</h3>
|
||||
{{ formatTime(info.created) }}
|
||||
<h3>Expires At :</h3>
|
||||
<h3>{{ $t('api.expiresAt') }}</h3>
|
||||
{{ formatTime(info.expires) }}
|
||||
<h3>Permissions:</h3>
|
||||
<h3>{{ $t('api.permissions') }}</h3>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr v-for="(isEnabled, permission) in info.Permissions" :key="permission">
|
||||
<td>{{ permission }}</td>
|
||||
<td>{{ isEnabled ? "✓" : "✗" }}</td>
|
||||
<td>{{ isEnabled ? '✓' : '✗' }}</td> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -37,14 +37,14 @@
|
||||
:aria-label="$t('buttons.close')"
|
||||
:title="$t('buttons.close')"
|
||||
>
|
||||
{{ $t("buttons.close") }}
|
||||
{{ $t('buttons.close') }}
|
||||
</button>
|
||||
<button
|
||||
class="button button--flat button--red"
|
||||
@click="deleteApi"
|
||||
:title="$t('buttons.delete')"
|
||||
>
|
||||
{{ $t("buttons.delete") }}
|
||||
{{ $t('buttons.delete') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,40 +1,37 @@
|
||||
<template>
|
||||
<div class="card floating create-api__prompt__card" id="create-api">
|
||||
<div class="card-title">
|
||||
<h2>Create API Key</h2>
|
||||
<h2>{{ $t('api.createTitle') }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
<!-- API Key Name Input -->
|
||||
<p>API Key Name</p>
|
||||
<p>{{ $t('api.keyName') }}</p>
|
||||
<input
|
||||
class="input input--block"
|
||||
type="text"
|
||||
v-model.trim="apiName"
|
||||
placeholder="enter a uinque api key name"
|
||||
:placeholder="$t('api.keyNamePlaceholder')"
|
||||
/>
|
||||
|
||||
<!-- Duration Input -->
|
||||
<p>Token Duration</p>
|
||||
<p>{{ $t('api.tokenDuration') }}</p>
|
||||
<div class="inputWrapper">
|
||||
<input
|
||||
class="sizeInput roundedInputLeft input"
|
||||
v-model.number="duration"
|
||||
type="number"
|
||||
min="1"
|
||||
placeholder="number"
|
||||
:placeholder="$t('api.durationNumberPlaceholder')"
|
||||
/>
|
||||
<select v-model="unit" class="roundedInputRight input">
|
||||
<option value="days">days</option>
|
||||
<option value="months">months</option>
|
||||
<option value="days">{{ $t('api.days') }}</option>
|
||||
<option value="months">{{ $t('api.months') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Permissions Input -->
|
||||
<p>
|
||||
Choose at least one permission for the key. Your User must also have the
|
||||
permission.
|
||||
</p>
|
||||
<p>{{ $t('api.permissionNote') }}</p>
|
||||
<div class="settings-items">
|
||||
<ToggleSwitch
|
||||
v-for="(isEnabled, permission) in permissions"
|
||||
@@ -114,10 +111,10 @@ export default {
|
||||
};
|
||||
|
||||
await usersApi.createApiKey(params);
|
||||
notify.showSuccess("successfully created!");
|
||||
notify.showSuccess($t("api.createKeySuccess"));
|
||||
window.location.reload();
|
||||
} catch (error) {
|
||||
notify.showError(this.$t("errors.createKeyFailed"));
|
||||
notify.showError($t("api.createKeyFailed"));
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="card floating">
|
||||
<div class="card-content">
|
||||
<p>Are you sure you want to delete this user?</p>
|
||||
<p>{{$t('prompts.deleteUserMessage')}}</p>
|
||||
</div>
|
||||
<div class="card-action">
|
||||
<button
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<div aria-label="filelist-path" class="searchContext">Path: {{ nav }}</div>
|
||||
<div aria-label="filelist-path" class="searchContext">{{$t('search.path')}} {{ nav }}</div>
|
||||
<ul class="file-list">
|
||||
<li
|
||||
@click="itemClick"
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
|
||||
<div class="card-content">
|
||||
<ul>
|
||||
<li><strong>F1</strong> - {{ $t("help.f1") }}</li>
|
||||
<li><strong>F2</strong> - {{ $t("help.f2") }}</li>
|
||||
<li><strong>DEL</strong> - {{ $t("help.del") }}</li>
|
||||
<li><strong>ESC</strong> - {{ $t("help.esc") }}</li>
|
||||
<li><strong>CTRL + S</strong> - {{ $t("help.ctrl.s") }}</li>
|
||||
<li><strong>CTRL + F</strong> - {{ $t("help.ctrl.f") }}</li>
|
||||
<li><strong>CTRL + Click</strong> - {{ $t("help.ctrl.click") }}</li>
|
||||
<li><strong>Click</strong> - {{ $t("help.click") }}</li>
|
||||
<li><strong>Double click</strong> - {{ $t("help.doubleClick") }}</li>
|
||||
<li><strong>F1</strong> - {{ $t("help.f1") }}</li> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<li><strong>F2</strong> - {{ $t("help.f2") }}</li> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<li><strong>DEL</strong> - {{ $t("help.del") }}</li> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<li><strong>ESC</strong> - {{ $t("help.esc") }}</li> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<li><strong>CTRL + S</strong> - {{ $t("help.ctrl.s") }}</li> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<li><strong>CTRL + F</strong> - {{ $t("help.ctrl.f") }}</li> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<li><strong>CTRL + Click</strong> - {{ $t("help.ctrl.click") }}</li> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<li><strong>Click</strong> - {{ $t("help.click") }}</li> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<li><strong>Double click</strong> - {{ $t("help.doubleClick") }}</li> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -13,48 +13,48 @@
|
||||
<strong>{{ $t("prompts.displayName") }}</strong> {{ name }}
|
||||
</p>
|
||||
<p v-if="!dir || selected.length > 1">
|
||||
<strong>{{ $t("prompts.size") }}:</strong>
|
||||
<strong>{{ $t("prompts.size") }}:</strong> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<span id="content_length"></span> {{ humanSize }}
|
||||
</p>
|
||||
<p v-if="!dir || selected.length > 1">
|
||||
<strong>Type:</strong>
|
||||
<strong>{{$t('prompts.typeName')}}</strong>
|
||||
<span id="content_length"></span> {{ type }}
|
||||
</p>
|
||||
<p v-if="selected.length < 2" :title="modTime">
|
||||
<strong>{{ $t("prompts.lastModified") }}:</strong> {{ humanTime }}
|
||||
<strong>{{ $t("prompts.lastModified") }}:</strong> {{ humanTime }} <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
</p>
|
||||
|
||||
<template v-if="dir && selected.length === 0">
|
||||
<p>
|
||||
<strong>{{ $t("prompts.numberFiles") }}:</strong> {{ req.numFiles }}
|
||||
<strong>{{ $t("prompts.numberFiles") }}:</strong> {{ req.numFiles }} <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
</p>
|
||||
<p>
|
||||
<strong>{{ $t("prompts.numberDirs") }}:</strong> {{ req.numDirs }}
|
||||
<strong>{{ $t("prompts.numberDirs") }}:</strong> {{ req.numDirs }} <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<template v-if="!dir">
|
||||
<p>
|
||||
<strong>MD5: </strong
|
||||
><code
|
||||
<strong>MD5: </strong> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<code
|
||||
><a @click="checksum($event, 'md5')">{{ $t("prompts.show") }}</a></code
|
||||
>
|
||||
</p>
|
||||
<p>
|
||||
<strong>SHA1: </strong
|
||||
><code
|
||||
<strong>SHA1: </strong> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<code
|
||||
><a @click="checksum($event, 'sha1')">{{ $t("prompts.show") }}</a></code
|
||||
>
|
||||
</p>
|
||||
<p>
|
||||
<strong>SHA256: </strong
|
||||
><code
|
||||
<strong>SHA256: </strong> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<code
|
||||
><a @click="checksum($event, 'sha256')">{{ $t("prompts.show") }}</a></code
|
||||
>
|
||||
</p>
|
||||
<p>
|
||||
<strong>SHA512: </strong
|
||||
><code
|
||||
<strong>SHA512: </strong> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<code
|
||||
><a @click="checksum($event, 'sha512')">{{ $t("prompts.show") }}</a></code
|
||||
>
|
||||
</p>
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
|
||||
<div class="card-content">
|
||||
<p>
|
||||
{{ $t("prompts.renameMessage") }} <code>{{ oldName() }}</code
|
||||
>:
|
||||
{{ $t("prompts.renameMessage") }} <code>{{ oldName() }}</code>: <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
</p>
|
||||
<input
|
||||
class="input input--block"
|
||||
|
||||
@@ -3,17 +3,14 @@
|
||||
<div class="card-title">
|
||||
<h2>{{ $t("buttons.share") }}</h2>
|
||||
</div>
|
||||
<div aria-label="share-path" class="searchContext">Path: {{ subpath }}</div>
|
||||
<p>
|
||||
Note: anyone who has access to the link (and optional password) can access the
|
||||
shared files. There is no requirement to be logged in.
|
||||
</p>
|
||||
<div aria-label="share-path" class="searchContext"> {{$t('search.path')}} {{ subpath }}</div>
|
||||
<p> {{ $t('share.notice') }} </p>
|
||||
<template v-if="listing">
|
||||
<div class="card-content">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>#</th> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<th>{{ $t("settings.shareDuration") }}</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<select @change="change" :value="locale">
|
||||
<option v-for="(value, label) in locales" :key="label" :value="label">
|
||||
{{ $t("languages." + label) }}
|
||||
{{ $t("languages." + value) }}
|
||||
</option>
|
||||
</select>
|
||||
</template>
|
||||
|
||||
@@ -1,18 +1,43 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="!stateUser.permissions.admin && !isNew && stateUser.loginMethod == 'password'"
|
||||
<h2
|
||||
class="message"
|
||||
v-if="user.loginMethod != 'password' && !stateUser.permissions.admin"
|
||||
>
|
||||
<i class="material-icons">sentiment_dissatisfied</i>
|
||||
<span>{{ $t("files.lonely") }}</span>
|
||||
</h2>
|
||||
<div v-if="user.loginMethod == 'password' && passwordAvailable && !isNew">
|
||||
<label for="password">{{ $t("settings.password") }}</label>
|
||||
<input
|
||||
class="input input--block"
|
||||
type="password"
|
||||
placeholder="enter new password"
|
||||
v-model="user.password"
|
||||
id="password"
|
||||
@input="setUpdatePassword"
|
||||
/>
|
||||
<div class="form-group">
|
||||
<input
|
||||
class="input input--block form-form"
|
||||
:class="{ 'invalid-form': invalidPassword }"
|
||||
type="password"
|
||||
:placeholder="$t('settings.enterPassword')"
|
||||
v-model="passwordRef"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input
|
||||
class="input input--block form-form"
|
||||
:class="{ 'flat-right': !isNew, 'invalid-form': invalidPassword }"
|
||||
type="password"
|
||||
:placeholder="$t('settings.enterPasswordAgain')"
|
||||
v-model="user.password"
|
||||
id="password"
|
||||
/>
|
||||
<button
|
||||
v-if="!isNew"
|
||||
type="button"
|
||||
class="button form-button"
|
||||
@click="submitUpdatePassword"
|
||||
>
|
||||
{{ $t("buttons.update") }}
|
||||
</button>
|
||||
</div>
|
||||
<hr />
|
||||
</div>
|
||||
<div v-else>
|
||||
<div v-if="stateUser.permissions.admin">
|
||||
<p v-if="isNew">
|
||||
<label for="username">{{ $t("settings.username") }}</label>
|
||||
<input
|
||||
@@ -24,26 +49,41 @@
|
||||
/>
|
||||
</p>
|
||||
|
||||
<p v-if="stateUser.loginMethod == 'password'">
|
||||
<label for="password">{{ $t("settings.password") }}</label>
|
||||
<div v-if="user.loginMethod == 'password' && passwordAvailable && isNew">
|
||||
<label for="password">{{ $t("settings.password") }}</label>
|
||||
<div class="form-group">
|
||||
<input
|
||||
class="input input--block"
|
||||
class="input input--block form-form"
|
||||
:class="{ 'invalid-form': invalidPassword }"
|
||||
type="password"
|
||||
:placeholder="passwordPlaceholder"
|
||||
:placeholder="$t('settings.enterPassword')"
|
||||
v-model="passwordRef"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input
|
||||
class="input input--block form-form"
|
||||
:class="{ 'flat-right': !isNew, 'invalid-form': invalidPassword }"
|
||||
type="password"
|
||||
:placeholder="$t('settings.enterPasswordAgain')"
|
||||
v-model="user.password"
|
||||
id="password"
|
||||
@input="emitUpdate"
|
||||
/>
|
||||
</p>
|
||||
<button
|
||||
v-if="!isNew"
|
||||
type="button"
|
||||
class="button form-button"
|
||||
@click="submitUpdatePassword"
|
||||
>
|
||||
{{ $t("buttons.update") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-items">
|
||||
<ToggleSwitch
|
||||
class="item"
|
||||
v-if="user.loginMethod === 'password'"
|
||||
:modelValue="updatePassword"
|
||||
@update:modelValue="$emit('update:updatePassword', $event)"
|
||||
:name="$t('settings.changePassword')"
|
||||
/>
|
||||
<div
|
||||
v-if="user.loginMethod == 'password' && passwordAvailable"
|
||||
class="settings-items"
|
||||
>
|
||||
<ToggleSwitch
|
||||
v-if="user.loginMethod === 'password' && stateUser.permissions?.admin"
|
||||
class="item"
|
||||
@@ -53,7 +93,7 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="stateUser.permissions.admin">
|
||||
<div style="padding-bottom: 1em" v-if="stateUser.permissions.admin">
|
||||
<label for="scopes">{{ $t("settings.scopes") }}</label>
|
||||
<div
|
||||
class="scope-list"
|
||||
@@ -110,7 +150,14 @@
|
||||
@input="emitUpdate"
|
||||
></languages>
|
||||
</p>
|
||||
|
||||
<div v-if="stateUser.permissions.admin">
|
||||
<label for="loginMethod">{{ $t("settings.loginMethodDescription") }}</label>
|
||||
<select v-model="user.loginMethod" class="input input--block" id="loginMethod">
|
||||
<option value="password">Password</option>
|
||||
<option value="oidc">OIDC</option>
|
||||
<option value="proxy">Proxy</option>
|
||||
</select>
|
||||
</div>
|
||||
<permissions v-if="stateUser.permissions.admin" :permissions="user.permissions" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -119,8 +166,10 @@
|
||||
import Languages from "./Languages.vue";
|
||||
import Permissions from "./Permissions.vue";
|
||||
import { state } from "@/store";
|
||||
import { settingsApi } from "@/api";
|
||||
import ToggleSwitch from "@/components/settings/ToggleSwitch.vue";
|
||||
import { notify } from "@/notify";
|
||||
import { usersApi, settingsApi } from "@/api";
|
||||
import { passwordAvailable } from "@/utils/constants";
|
||||
|
||||
export default {
|
||||
name: "UserForm",
|
||||
@@ -131,7 +180,6 @@ export default {
|
||||
},
|
||||
props: {
|
||||
user: Object,
|
||||
updatePassword: Boolean,
|
||||
isNew: Boolean,
|
||||
},
|
||||
data() {
|
||||
@@ -141,6 +189,7 @@ export default {
|
||||
sourceList: [],
|
||||
availableSources: [],
|
||||
selectedSources: [],
|
||||
passwordRef: "",
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
@@ -150,6 +199,7 @@ export default {
|
||||
this.sourceList = await settingsApi.get("sources");
|
||||
}
|
||||
|
||||
this.user.password = this.user.password || "";
|
||||
this.selectedSources = this.user.scopes || [];
|
||||
this.availableSources = this.sourceList.filter(
|
||||
(s) => !this.selectedSources.some((sel) => sel.name === s.name)
|
||||
@@ -170,6 +220,11 @@ export default {
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
invalidPassword() {
|
||||
const matching = this.user.password != this.passwordRef && this.user.password.length > 0 ;
|
||||
return matching;
|
||||
},
|
||||
passwordAvailable: () => passwordAvailable,
|
||||
duplicateSources() {
|
||||
const names = this.selectedSources.map((s) => s.name);
|
||||
return names.filter((name, idx) => names.indexOf(name) !== idx);
|
||||
@@ -188,6 +243,19 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async submitUpdatePassword() {
|
||||
event.preventDefault();
|
||||
if (this.invalidPassword) {
|
||||
notify.showError(this.$t("settings.passwordsDoNotMatch"));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await usersApi.update(this.user, ["password"]);
|
||||
notify.showSuccess(this.$t("settings.userUpdated"));
|
||||
} catch (e) {
|
||||
notify.showError(e);
|
||||
}
|
||||
},
|
||||
emitUserUpdate() {
|
||||
this.$emit("update:user", { ...this.user, scopes: this.selectedSources });
|
||||
},
|
||||
@@ -239,14 +307,7 @@ export default {
|
||||
.scope-list {
|
||||
display: flex;
|
||||
}
|
||||
.flat-right {
|
||||
border-top-right-radius: 0 !important;
|
||||
border-bottom-right-radius: 0 !important;
|
||||
}
|
||||
.flat-left {
|
||||
border-top-left-radius: 0 !important;
|
||||
border-bottom-left-radius: 0 !important;
|
||||
}
|
||||
|
||||
.scope-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<template>
|
||||
<div class="tooltip">
|
||||
<span class="tooltiptext-first" :class="{ visible: hoverText != '' }">{{
|
||||
this.hoverText
|
||||
}}</span>
|
||||
<span class="tooltiptext-first" :class="{ visible: hoverText != '' }">
|
||||
{{ hoverText }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-if="hasSourceInfo" class="tooltip-sources">
|
||||
<div
|
||||
class="tooltiptext-sources"
|
||||
@@ -18,37 +19,38 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Status</td>
|
||||
<td>{{ $t("index.status") }}</td>
|
||||
<td>{{ sourceInfoTooltip.status }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Assessment</td>
|
||||
<td>{{ $t("index.assessment") }}</td>
|
||||
<td>{{ sourceInfoTooltip.assessment }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Files</td>
|
||||
<td>{{ $t("index.files") }}</td>
|
||||
<td>{{ sourceInfoTooltip.files }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Folders</td>
|
||||
<td>{{ $t("index.folders") }}</td>
|
||||
<td>{{ sourceInfoTooltip.folders }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Last Scanned</td>
|
||||
<td>{{ $t("index.lastScanned") }}</td>
|
||||
<td>{{ gethumanReadable }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Quick Scan Seconds</td>
|
||||
<td>{{ $t("index.quickScan") }}</td>
|
||||
<td>{{ humanReadableQuickScan }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Full Scan Seconds</td>
|
||||
<td>{{ $t("index.fullScan") }}</td>
|
||||
<td>{{ humanReadableFullScan }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card headline-card">
|
||||
<div class="card-wrapper user-card">
|
||||
<div
|
||||
@@ -58,12 +60,12 @@
|
||||
>
|
||||
<button
|
||||
class="person-button action"
|
||||
@mouseover="updateHoverText('Settings For User')"
|
||||
@mouseover="updateHoverText($t('index.settingsHover'))"
|
||||
@mouseleave="resetHoverTextToDefault"
|
||||
>
|
||||
<i class="material-icons">person</i>
|
||||
{{ user.username }}
|
||||
<i aria-label="settings" class="material-icons"> settings</i>
|
||||
<i aria-label="settings" class="material-icons">settings</i>
|
||||
</button>
|
||||
</div>
|
||||
<div v-else class="inner-card">
|
||||
@@ -77,19 +79,20 @@
|
||||
<button
|
||||
aria-label="logout-button"
|
||||
class="logout-button action"
|
||||
@mouseover="updateHoverText('Logout')"
|
||||
@mouseover="updateHoverText($t('index.logout'))"
|
||||
@mouseleave="resetHoverTextToDefault"
|
||||
>
|
||||
<i v-if="canLogout" class="material-icons">exit_to_app</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-wrapper" @mouseleave="resetHoverTextToDefault">
|
||||
<div class="quick-toggles">
|
||||
<div
|
||||
:class="{ active: user?.singleClick }"
|
||||
@click="toggleClick"
|
||||
@mouseover="updateHoverText('Toggle Single Click')"
|
||||
@mouseover="updateHoverText($t('index.toggleClick'))"
|
||||
@mouseleave="resetHoverTextToDefault"
|
||||
>
|
||||
<i class="material-icons">ads_click</i>
|
||||
@@ -97,7 +100,7 @@
|
||||
<div
|
||||
:class="{ active: user?.darkMode }"
|
||||
@click="toggleDarkMode"
|
||||
@mouseover="updateHoverText('Toggle Dark Mode')"
|
||||
@mouseover="updateHoverText($t('index.toggleDark'))"
|
||||
@mouseleave="resetHoverTextToDefault"
|
||||
>
|
||||
<i class="material-icons">dark_mode</i>
|
||||
@@ -105,7 +108,7 @@
|
||||
<div
|
||||
:class="{ active: isStickySidebar }"
|
||||
@click="toggleSticky"
|
||||
@mouseover="updateHoverText('Toggle Sticky Mode')"
|
||||
@mouseover="updateHoverText($t('index.toggleSticky'))"
|
||||
@mouseleave="resetHoverTextToDefault"
|
||||
v-if="!isMobile"
|
||||
>
|
||||
@@ -114,11 +117,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Section for logged-in users -->
|
||||
<div v-if="loginCheck" class="sidebar-scroll-list">
|
||||
<div class="sources card">
|
||||
<span>Sources</span>
|
||||
<span> {{ $t("sidebar.sources") }}</span>
|
||||
<div class="inner-card">
|
||||
<!-- My Files button -->
|
||||
<button
|
||||
@@ -147,18 +149,18 @@
|
||||
<span>{{ name }}</span>
|
||||
</div>
|
||||
<div v-if="hasSourceInfo" class="usage-info">
|
||||
<progress-bar
|
||||
<ProgressBar
|
||||
:val="info.usedPercentage"
|
||||
text-position="inside"
|
||||
:text="info.usedPercentage + '%'"
|
||||
size="large"
|
||||
text-fg-color="white"
|
||||
></progress-bar>
|
||||
></ProgressBar>
|
||||
<div class="usage-info">
|
||||
<span
|
||||
>{{ getHumanReadableFilesize(info.used) }} of
|
||||
{{ getHumanReadableFilesize(info.total) }} used</span
|
||||
>
|
||||
<span>
|
||||
{{ getHumanReadableFilesize(info.used) }} {{ $t("index.of") }}
|
||||
{{ getHumanReadableFilesize(info.total) }} {{ $t("index.used") }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
+116
-20
@@ -31,17 +31,24 @@
|
||||
"switchView": "تغيير العرض",
|
||||
"toggleSidebar": "تبديل الشريط الجانبي",
|
||||
"update": "تحديث",
|
||||
"upload": "رفع"
|
||||
"upload": "رفع",
|
||||
"copyDownloadLinkToClipboard": "نسخ رابط التحميل إلى الحافظة",
|
||||
"file": "ملف",
|
||||
"folder": "المجلد",
|
||||
"submit": "إرسال",
|
||||
"openFile": "فتح الملف",
|
||||
"continue": "تابع"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Download File",
|
||||
"downloadFolder": "Download Folder",
|
||||
"downloadSelected": ""
|
||||
"downloadSelected": "تنزيل محدد"
|
||||
},
|
||||
"errors": {
|
||||
"forbidden": "You don't have permissions to access this.",
|
||||
"internal": "لقد حدث خطأ ما.",
|
||||
"notFound": "لا يمكن الوصول لهذا المحتوى."
|
||||
"notFound": "لا يمكن الوصول لهذا المحتوى.",
|
||||
"connection": "لا يمكن الوصول إلى الخادم"
|
||||
},
|
||||
"files": {
|
||||
"body": "الصفحة",
|
||||
@@ -59,7 +66,8 @@
|
||||
"size": "الحجم",
|
||||
"sortByLastModified": "الترتيب بآخر تعديل",
|
||||
"sortByName": "الترتيب بالإسم",
|
||||
"sortBySize": "الترتيب بالحجم"
|
||||
"sortBySize": "الترتيب بالحجم",
|
||||
"noPreview": "المعاينة غير متوفرة لهذا الملف."
|
||||
},
|
||||
"help": {
|
||||
"click": "حدد الملف أو المجلد",
|
||||
@@ -95,7 +103,7 @@
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "",
|
||||
"tr" : "Türkçe",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
@@ -110,7 +118,8 @@
|
||||
"submit": "تسجيل دخول",
|
||||
"username": "إسم المستخدم",
|
||||
"usernameTaken": "Username already taken",
|
||||
"wrongCredentials": "بيانات دخول خاطئة"
|
||||
"wrongCredentials": "بيانات دخول خاطئة",
|
||||
"or": "أو"
|
||||
},
|
||||
"permanent": "دائم",
|
||||
"prompts": {
|
||||
@@ -125,7 +134,6 @@
|
||||
"downloadMessage": "حدد إمتداد الملف المراد تحميله.",
|
||||
"error": "لقد حدث خطأ ما",
|
||||
"fileInfo": "معلومات الملف",
|
||||
"filesSelected": "تم تحديد {count} ملفات.",
|
||||
"lastModified": "آخر تعديل",
|
||||
"move": "نقل",
|
||||
"moveMessage": "إختر مكان جديد للملفات أو المجلدات المراد نقلها:",
|
||||
@@ -144,8 +152,15 @@
|
||||
"scheduleMessage": "أختر الوقت والتاريخ لجدولة نشر هذا المقال.",
|
||||
"show": "عرض",
|
||||
"size": "الحجم",
|
||||
"upload": "",
|
||||
"uploadMessage": ""
|
||||
"upload": "التحميل",
|
||||
"uploadMessage": "حدد خياراً للتحميل.",
|
||||
"deleteMessageShare": "Are you sure you want to delete this share: {path} ?",
|
||||
"deleteUserMessage": "هل أنت متأكد من رغبتك في حذف هذا المستخدم؟",
|
||||
"filesSelected": "الملفات المحددة",
|
||||
"uploadFiles": "Uploading {files} files...",
|
||||
"optionalPassword": "كلمة مرور اختيارية",
|
||||
"typeName": "النوع:",
|
||||
"selected": "مختارة"
|
||||
},
|
||||
"search": {
|
||||
"images": "الصور",
|
||||
@@ -155,7 +170,12 @@
|
||||
"search": "البحث...",
|
||||
"typeToSearch": "Type to search...",
|
||||
"types": "الأنواع",
|
||||
"video": "فيديوهات"
|
||||
"video": "فيديوهات",
|
||||
"path": "المسار:",
|
||||
"smallerThan": "أصغر من:",
|
||||
"largerThan": "أكبر من:",
|
||||
"helpText1": "يحدث البحث على كل حرف تكتبه (3 أحرف كحد أدنى لمصطلحات البحث).",
|
||||
"helpText2": "الفهرس: يستخدم البحث الفهرس الذي يتم تحديثه تلقائيًا على الفاصل الزمني الذي تم تكوينه (افتراضيًا: 5 دقائق). قد يؤدي البحث عندما يكون البرنامج قد بدأ للتو إلى نتائج غير مكتملة."
|
||||
},
|
||||
"settings": {
|
||||
"admin": "Admin",
|
||||
@@ -194,7 +214,7 @@
|
||||
"newUser": "مستخدم جديد",
|
||||
"password": "كلمة المرور",
|
||||
"passwordUpdated": "تم تغيير كلمة المرور",
|
||||
"path": "",
|
||||
"path": "المسار",
|
||||
"permissions": {
|
||||
"create": "Create files and directories",
|
||||
"delete": "Delete files and directories",
|
||||
@@ -202,7 +222,10 @@
|
||||
"execute": "Execute commands",
|
||||
"modify": "Edit files",
|
||||
"rename": "Rename or move files and directories",
|
||||
"share": "Share files"
|
||||
"share": "Share files",
|
||||
"admin": "المدير",
|
||||
"api": "إنشاء مفاتيح API طويلة الأمد وإدارتها",
|
||||
"realtime": "تمكين الاتصالات والتحديثات في الوقت الفعلي"
|
||||
},
|
||||
"permissions-name": "الصلاحيات",
|
||||
"permissionsHelp": "يمكنك تعيين المستخدم كـ \"مدير\" أو تحديد الصلاحيات بشكل منفرد.\n إذا قمت بتحديد المستخدم كـ \"مدير\"، باقي الخيارات سيتم تحديدها تلقائياً.\n إدارة المستخدمين تبقى صلاحية فريدة للـ \"مدير\" فقط.\n",
|
||||
@@ -213,13 +236,13 @@
|
||||
"rulesHelp": "يمكنك هنا تحديد مجموعة من شروط السماح والمنع لهذا المستخدم. الملفات الممنوعة لن تظهر ضمن القائمة لهذا المستخدم ولن يستطيع الوصول لها. هنا ندعم الـ regex والـ relative path لنطاق المستخدمين.\n",
|
||||
"scope": "نطاق",
|
||||
"settingsUpdated": "تم تعديل الإعدادات",
|
||||
"shareDuration": "",
|
||||
"shareManagement": "",
|
||||
"singleClick": "",
|
||||
"shareDuration": "مدة المشاركة",
|
||||
"shareManagement": "إدارة المشاركة",
|
||||
"singleClick": "استخدام نقرات واحدة لفتح الملفات والدلائل",
|
||||
"themes": {
|
||||
"dark": "",
|
||||
"light": "",
|
||||
"title": ""
|
||||
"dark": "داكن",
|
||||
"light": "خفيف",
|
||||
"title": "الموضوع"
|
||||
},
|
||||
"user": "المستخدم",
|
||||
"userCommands": "الأوامر",
|
||||
@@ -230,7 +253,33 @@
|
||||
"userManagement": "إدارة المستخدمين",
|
||||
"userUpdated": "تم تعديل المستخدم",
|
||||
"username": "إسم المستخدم",
|
||||
"users": "المستخدمين"
|
||||
"users": "المستخدمين",
|
||||
"loginMethod": "طريقة تسجيل الدخول",
|
||||
"modifyOtherUser": "تعديل المستخدم:",
|
||||
"modifyCurrentUser": "تعديل المستخدم الحالي",
|
||||
"themeColor": "لون السمة",
|
||||
"disableOfficePreviewDescription": "قائمة مفصولة بمسافات لامتدادات الملفات لتعطيل عارض OnlyOffice لها. (على سبيل المثال، \".txt .html\").",
|
||||
"disableOfficePreview": "تعطيل عارض Onlyoffice لامتدادات ملفات معينة",
|
||||
"filePreviewOptions": "خيارات معاينة الملف",
|
||||
"listingOptions": "خيارات الإدراج",
|
||||
"emptyGlobal": "لا توجد خيارات تهيئة عامة حاليًا، يمكنك تحرير yaml التكوين لضبط إعدادات النظام.",
|
||||
"scopes": "تحديد المصادر المسموح بها ونطاق المستخدم داخلها",
|
||||
"UserManagement": "إدارة المستخدمين",
|
||||
"tusUploads": "التحميلات المقطوعة",
|
||||
"tusUploadsHelp": "يدعم متصفح الملفات عمليات تحميل الملفات المقطعة، مما يسمح بإنشاء عمليات تحميل ملفات فعالة وموثوقة وقابلة للاستئناف ومقطعة حتى على الشبكات غير الموثوقة.",
|
||||
"tusUploadsChunkSize": "يشير إلى الحد الأقصى لحجم الطلب (سيتم استخدام التحميل المباشر للتحميلات الأصغر حجماً). يمكنك إدخال عدد صحيح عادي يشير إلى إدخال بايت أو سلسلة مثل 10 ميغابايت، 1 غيغابايت، إلخ.",
|
||||
"tusUploadsRetryCount": "عدد مرات إعادة المحاولة التي يجب إجراؤها في حالة فشل تحميل قطعة ما.",
|
||||
"userHomeBasePath": "المسار الأساسي للدلائل الرئيسية للمستخدم",
|
||||
"userScopeGenerationPlaceholder": "سيتم إنشاء النطاق تلقائيًا",
|
||||
"createUserHomeDirectory": "إنشاء الدليل الرئيسي للمستخدم",
|
||||
"api": "مفاتيح واجهة برمجة التطبيقات",
|
||||
"setDateFormat": "تعيين تنسيق التاريخ الدقيق",
|
||||
"shareDeleted": "تم حذف المشاركة",
|
||||
"loginMethodDescription": "طريقة تسجيل الدخول المسموح بها للمستخدم.",
|
||||
"userNotAdmin": "المستخدم ليس مسؤولاً",
|
||||
"enterPassword": "أدخل كلمة المرور",
|
||||
"enterPasswordAgain": "أدخل كلمة المرور مرة أخرى",
|
||||
"passwordsDoNotMatch": "كلمات المرور غير متطابقة"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "مساعدة",
|
||||
@@ -243,7 +292,8 @@
|
||||
"preview": "معاينة",
|
||||
"settings": "الإعدادات",
|
||||
"signup": "Signup",
|
||||
"siteSettings": "إعدادات الموقع"
|
||||
"siteSettings": "إعدادات الموقع",
|
||||
"sources": "المصادر"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "تم نسخ الملف"
|
||||
@@ -254,5 +304,51 @@
|
||||
"minutes": "دقائق",
|
||||
"seconds": "ثواني",
|
||||
"unit": "وحدة الوقت"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "هل أنت متأكدة من أنك تريدين الإجهاض؟"
|
||||
},
|
||||
"share": {
|
||||
"notice": "ملاحظة: يمكن لأي شخص لديه حق الوصول إلى الرابط (وكلمة مرور اختيارية) الوصول إلى الملفات المشتركة. لا يوجد شرط لتسجيل الدخول."
|
||||
},
|
||||
"api": {
|
||||
"title": "مفاتيح واجهة برمجة التطبيقات (API):",
|
||||
"keyName": "اسم مفتاح API:",
|
||||
"createdAt": "تم الإنشاء في:",
|
||||
"expiresAt": "تنتهي في:",
|
||||
"permissions": "الأذونات:",
|
||||
"createTitle": "إنشاء مفتاح API",
|
||||
"keyNamePlaceholder": "أدخل اسم مفتاح API فريد من نوعه:",
|
||||
"tokenDuration": "مدة الرمز المميز:",
|
||||
"durationNumberPlaceholder": "العدد",
|
||||
"days": "الأيام",
|
||||
"months": "الشهور",
|
||||
"permissionNote": "اختر إذنًا واحدًا على الأقل للمفتاح. يجب أن يكون لدى المستخدم أيضًا الإذن.",
|
||||
"createKeyFailed": "فشل في إنشاء مفتاح API.",
|
||||
"createKeySuccess": "تم إنشاء مفتاح API بنجاح.",
|
||||
"description": "تعتمد مفاتيح API على المستخدم الذي أنشأها. انظر",
|
||||
"swaggerLinkText": "صفحة التبختر",
|
||||
"name": "الاسم",
|
||||
"created": "تم إنشاؤها",
|
||||
"expires": "تنتهي صلاحيتها",
|
||||
"actions": "الإجراءات",
|
||||
"enabled": "ممكّنة",
|
||||
"disabled": "معاق"
|
||||
},
|
||||
"index": {
|
||||
"status": "الحالة",
|
||||
"assessment": "التقييم",
|
||||
"files": "الملفات",
|
||||
"folders": "المجلدات",
|
||||
"lastScanned": "آخر مسح ضوئي",
|
||||
"quickScan": "ثواني المسح السريع",
|
||||
"fullScan": "كامل ثواني المسح الضوئي",
|
||||
"settingsHover": "إعدادات المستخدم",
|
||||
"logout": "تسجيل الخروج",
|
||||
"toggleClick": "تبديل نقرة واحدة",
|
||||
"toggleDark": "تبديل الوضع الداكن",
|
||||
"toggleSticky": "تبديل الوضع اللاصق",
|
||||
"of": "من",
|
||||
"used": "مستعمل"
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,8 @@
|
||||
"update": "Aktualisieren",
|
||||
"upload": "Upload",
|
||||
"openFile": "Datei öffnen",
|
||||
"continue": "Fortfahren"
|
||||
"continue": "Fortfahren",
|
||||
"copyDownloadLinkToClipboard": "Download-Link in die Zwischenablage kopieren"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Download Datei",
|
||||
@@ -117,7 +118,8 @@
|
||||
"submit": "Anmelden",
|
||||
"username": "Benutzername",
|
||||
"usernameTaken": "Benutzername ist bereits vergeben",
|
||||
"wrongCredentials": "Falsche Zugangsdaten"
|
||||
"wrongCredentials": "Falsche Zugangsdaten",
|
||||
"or": "OR"
|
||||
},
|
||||
"permanent": "Permanent",
|
||||
"prompts": {
|
||||
@@ -133,7 +135,6 @@
|
||||
"downloadMessage": "Wählen Sie ein Format zum Herunterladen aus.",
|
||||
"error": "Etwas ist schief gelaufen",
|
||||
"fileInfo": "Dateiinformation",
|
||||
"filesSelected": "{count} Dateien ausgewählt.",
|
||||
"lastModified": "Zuletzt geändert",
|
||||
"move": "Verschieben",
|
||||
"moveMessage": "Wählen Sie einen neuen Ort für ihre Datei(en)/Ordner:",
|
||||
@@ -155,7 +156,11 @@
|
||||
"upload": "Upload",
|
||||
"uploadFiles": "Upload von {files} Dateien...",
|
||||
"uploadMessage": "Wählen Sie eine Upload-Methode",
|
||||
"optionalPassword": "Optionales Kennwort"
|
||||
"optionalPassword": "Optionales Kennwort",
|
||||
"deleteUserMessage": "Sind Sie sicher, dass Sie diesen Benutzer löschen möchten?",
|
||||
"filesSelected": "ausgewählte Dateien",
|
||||
"typeName": "Art:",
|
||||
"selected": "ausgewählt"
|
||||
},
|
||||
"search": {
|
||||
"images": "Bilder",
|
||||
@@ -165,7 +170,12 @@
|
||||
"search": "Suche...",
|
||||
"typeToSearch": "Tippen, um zu suchen...",
|
||||
"types": "Typen",
|
||||
"video": "Video"
|
||||
"video": "Video",
|
||||
"path": "Pfad:",
|
||||
"smallerThan": "Kleiner als:",
|
||||
"largerThan": "Größer als:",
|
||||
"helpText1": "Die Suche erfolgt bei jedem Zeichen, das Sie eingeben (mindestens 3 Zeichen für Suchbegriffe).",
|
||||
"helpText2": "Der Index: Die Suche verwendet den Index, der automatisch in dem konfigurierten Intervall aktualisiert wird (Standard: 5 Minuten). Eine Suche, wenn das Programm gerade gestartet wurde, kann zu unvollständigen Ergebnissen führen."
|
||||
},
|
||||
"settings": {
|
||||
"admin": "Admin",
|
||||
@@ -216,7 +226,10 @@
|
||||
"execute": "Befehle ausführen",
|
||||
"modify": "Dateien bearbeiten",
|
||||
"rename": "Umbenennen oder Verschieben von Dateien oder Ordnern",
|
||||
"share": "Datei teilen"
|
||||
"share": "Datei teilen",
|
||||
"admin": "Verwalter",
|
||||
"api": "Erstellen und Verwalten von API-Schlüsseln mit langer Lebensdauer",
|
||||
"realtime": "Verbindungen und Aktualisierungen in Echtzeit ermöglichen"
|
||||
},
|
||||
"permissions-name": "Berechtigungen",
|
||||
"permissionsHelp": "Sie können einem Benutzer Administratorrechte einräumen oder die Berechtigunen individuell festlegen. Wenn Sie \"Administrator\" auswählen, werden alle anderen Rechte automatisch vergeben. Die Nutzerverwaltung kann nur durch einen Administrator erfolgen.\n",
|
||||
@@ -246,7 +259,27 @@
|
||||
"userManagement": "Benutzerverwaltung",
|
||||
"userUpdated": "Benutzer aktualisiert!",
|
||||
"username": "Benutzername",
|
||||
"users": "Benutzer"
|
||||
"users": "Benutzer",
|
||||
"loginMethod": "Login-Methode",
|
||||
"modifyOtherUser": "Benutzer ändern:",
|
||||
"modifyCurrentUser": "Aktuellen Benutzer ändern",
|
||||
"themeColor": "Thema Farbe",
|
||||
"disableOfficePreviewDescription": "Eine durch Leerzeichen getrennte Liste von Dateierweiterungen, für die der OnlyOffice-Viewer deaktiviert werden soll. (z. B. '.txt .html').",
|
||||
"disableOfficePreview": "Onlyoffice-Viewer für bestimmte Dateierweiterungen deaktivieren",
|
||||
"filePreviewOptions": "Optionen für die Dateivorschau",
|
||||
"listingOptions": "Auflistung der Optionen",
|
||||
"emptyGlobal": "Derzeit gibt es keine globalen Konfigurationsoptionen. Sie können die Konfigurations-Yaml bearbeiten, um die Systemeinstellungen anzupassen.",
|
||||
"scopes": "Definition der zulässigen Quellen und des Benutzerbereichs innerhalb dieser Quellen",
|
||||
"UserManagement": "Benutzerverwaltung",
|
||||
"userHomeBasePath": "Basispfad für Benutzer-Home-Verzeichnisse",
|
||||
"userScopeGenerationPlaceholder": "Der Bereich wird automatisch generiert",
|
||||
"createUserHomeDirectory": "Benutzer-Home-Verzeichnis erstellen",
|
||||
"api": "API-Schlüssel",
|
||||
"loginMethodDescription": "erlaubte Anmeldemethode für den Benutzer.",
|
||||
"userNotAdmin": "Benutzer ist kein Administrator",
|
||||
"enterPassword": "Passwort eingeben",
|
||||
"enterPasswordAgain": "Geben Sie das Passwort erneut ein",
|
||||
"passwordsDoNotMatch": "Passwörter stimmen nicht überein"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Hilfe",
|
||||
@@ -259,7 +292,8 @@
|
||||
"preview": "Vorschau",
|
||||
"settings": "Einstellungen",
|
||||
"signup": "Registrieren",
|
||||
"siteSettings": "Seiteneinstellungen"
|
||||
"siteSettings": "Seiteneinstellungen",
|
||||
"sources": "Quellen"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Verweis wurde kopiert!"
|
||||
@@ -270,5 +304,51 @@
|
||||
"minutes": "Minuten",
|
||||
"seconds": "Sekunden",
|
||||
"unit": "Zeiteinheit"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Sind Sie sicher, dass Sie abtreiben wollen?"
|
||||
},
|
||||
"share": {
|
||||
"notice": "Hinweis: Jeder, der Zugang zum Link (und optional zum Passwort) hat, kann auf die gemeinsamen Dateien zugreifen. Es ist nicht erforderlich, dass Sie eingeloggt sind."
|
||||
},
|
||||
"api": {
|
||||
"title": "API-Schlüssel:",
|
||||
"keyName": "API-Schlüssel Name:",
|
||||
"createdAt": "Erstellt am:",
|
||||
"expiresAt": "Läuft ab bei:",
|
||||
"permissions": "Erlaubt:",
|
||||
"createTitle": "API-Schlüssel erstellen",
|
||||
"keyNamePlaceholder": "Geben Sie einen eindeutigen API-Schlüsselnamen ein:",
|
||||
"tokenDuration": "Token Dauer:",
|
||||
"durationNumberPlaceholder": "Nummer",
|
||||
"days": "Tage",
|
||||
"months": "Monate",
|
||||
"permissionNote": "Wählen Sie mindestens eine Berechtigung für den Schlüssel. Ihr Benutzer muss ebenfalls über diese Berechtigung verfügen.",
|
||||
"createKeyFailed": "API-Schlüssel konnte nicht erstellt werden.",
|
||||
"createKeySuccess": "API-Schlüssel erfolgreich erstellt.",
|
||||
"description": "Die API-Schlüssel basieren auf dem Benutzer, der sie erstellt. Siehe",
|
||||
"swaggerLinkText": "Angeberseite",
|
||||
"name": "Name",
|
||||
"created": "Erstellt",
|
||||
"expires": "Abgelaufen",
|
||||
"actions": "Aktionen",
|
||||
"enabled": "Aktiviert",
|
||||
"disabled": "Behinderte"
|
||||
},
|
||||
"index": {
|
||||
"status": "Status",
|
||||
"assessment": "Bewertung",
|
||||
"files": "Dateien",
|
||||
"folders": "Ordner",
|
||||
"lastScanned": "Zuletzt gescannt",
|
||||
"quickScan": "Schnell-Scan-Sekunden",
|
||||
"fullScan": "Vollständiger Scan in Sekunden",
|
||||
"settingsHover": "Einstellungen für Benutzer",
|
||||
"logout": "Abmeldung",
|
||||
"toggleClick": "Einzelklick umschalten",
|
||||
"toggleDark": "Dunkler Modus umschalten",
|
||||
"toggleSticky": "Sticky-Modus umschalten",
|
||||
"of": "von",
|
||||
"used": "gebraucht"
|
||||
}
|
||||
}
|
||||
+350
-275
@@ -1,280 +1,355 @@
|
||||
{
|
||||
"buttons": {
|
||||
"cancel": "Ακύρωση",
|
||||
"close": "Κλείσιμο",
|
||||
"copy": "Αντιγραφή",
|
||||
"copyFile": "Αντιγραφή αρχείου",
|
||||
"copyToClipboard": "Αντιγραφή στο πρόχειρο",
|
||||
"copyDownloadLinkToClipboard": "Αντιγραφή συνδέσμου λήψης στο πρόχειρο",
|
||||
"create": "Δημιουργία",
|
||||
"delete": "Διαγραφή",
|
||||
"download": "Λήψη",
|
||||
"file": "Αρχείο",
|
||||
"folder": "Φάκελος",
|
||||
"info": "Πληροφορίες",
|
||||
"more": "Περισσότερα",
|
||||
"move": "Μετακίνηση",
|
||||
"moveFile": "Μετακίνηση αρχείου",
|
||||
"new": "Νέο",
|
||||
"next": "Επόμενο",
|
||||
"ok": "Εντάξει",
|
||||
"permalink": "Λήψη μόνιμου συνδέσμου",
|
||||
"previous": "Προηγούμενο",
|
||||
"publish": "Δημοσίευση",
|
||||
"rename": "Μετονομασία",
|
||||
"replace": "Αντικατάσταση",
|
||||
"reportIssue": "Αναφορά προβλήματος",
|
||||
"save": "Αποθήκευση",
|
||||
"schedule": "Προγραμματισμός",
|
||||
"search": "Αναζήτηση",
|
||||
"select": "Επιλογή",
|
||||
"selectMultiple": "Επιλογή πολλαπλών",
|
||||
"share": "Κοινοποίηση",
|
||||
"submit": "Υποβολή",
|
||||
"switchView": "Εναλλαγή προβολής",
|
||||
"toggleSidebar": "(Απ-)ενεργοποίησης της πλευρικής μπάρας",
|
||||
"update": "Ενημέρωση",
|
||||
"upload": "Μεταφόρτωση",
|
||||
"openFile": "Άνοιγμα αρχείου",
|
||||
"continue": "Συνέχεια"
|
||||
"buttons": {
|
||||
"cancel": "Ακύρωση",
|
||||
"close": "Κλείσιμο",
|
||||
"copy": "Αντιγραφή",
|
||||
"copyFile": "Αντιγραφή αρχείου",
|
||||
"copyToClipboard": "Αντιγραφή στο πρόχειρο",
|
||||
"copyDownloadLinkToClipboard": "Αντιγραφή συνδέσμου λήψης στο πρόχειρο",
|
||||
"create": "Δημιουργία",
|
||||
"delete": "Διαγραφή",
|
||||
"download": "Λήψη",
|
||||
"file": "Αρχείο",
|
||||
"folder": "Φάκελος",
|
||||
"info": "Πληροφορίες",
|
||||
"more": "Περισσότερα",
|
||||
"move": "Μετακίνηση",
|
||||
"moveFile": "Μετακίνηση αρχείου",
|
||||
"new": "Νέο",
|
||||
"next": "Επόμενο",
|
||||
"ok": "Εντάξει",
|
||||
"permalink": "Λήψη μόνιμου συνδέσμου",
|
||||
"previous": "Προηγούμενο",
|
||||
"publish": "Δημοσίευση",
|
||||
"rename": "Μετονομασία",
|
||||
"replace": "Αντικατάσταση",
|
||||
"reportIssue": "Αναφορά προβλήματος",
|
||||
"save": "Αποθήκευση",
|
||||
"schedule": "Προγραμματισμός",
|
||||
"search": "Αναζήτηση",
|
||||
"select": "Επιλογή",
|
||||
"selectMultiple": "Επιλογή πολλαπλών",
|
||||
"share": "Κοινοποίηση",
|
||||
"submit": "Υποβολή",
|
||||
"switchView": "Εναλλαγή προβολής",
|
||||
"toggleSidebar": "(Απ-)ενεργοποίησης της πλευρικής μπάρας",
|
||||
"update": "Ενημέρωση",
|
||||
"upload": "Μεταφόρτωση",
|
||||
"openFile": "Άνοιγμα αρχείου",
|
||||
"continue": "Συνέχεια",
|
||||
"shell": "Εναλλαγή κελύφους"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Λήψη αρχείου",
|
||||
"downloadFolder": "Λήψη φακέλου",
|
||||
"downloadSelected": "Λήψη επιλεγμένων"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Είστε σίγουροι ότι θέλετε να διακόψετε τη μεταφόρτωση;"
|
||||
},
|
||||
"errors": {
|
||||
"forbidden": "Δεν έχετε άδεια πρόσβασης σε αυτό.",
|
||||
"internal": "Προέκυψε εσωτερικό σφάλμα.",
|
||||
"notFound": "Αυτή η τοποθεσία δεν μπορεί να βρεθεί.",
|
||||
"connection": "Ο διακομιστής δεν είναι διαθέσιμος."
|
||||
},
|
||||
"files": {
|
||||
"body": "Περιεχόμενο",
|
||||
"clear": "Καθαρισμός",
|
||||
"closePreview": "Κλείσιμο προεπισκόπησης",
|
||||
"files": "Αρχεία",
|
||||
"folders": "Φάκελοι",
|
||||
"home": "Αρχική",
|
||||
"lastModified": "Τελευταία τροποποίηση",
|
||||
"loading": "Φορτώνει…",
|
||||
"lonely": "Δεν υπάρχει τίποτα εδώ (ακόμη)…",
|
||||
"metadata": "Μεταδεδομένα",
|
||||
"multipleSelectionEnabled": "Ενεργοποιημένη επιλογή πολλαπλών",
|
||||
"name": "Όνομα",
|
||||
"size": "Μέγεθος",
|
||||
"sortByLastModified": "Ταξινόμηση κατά πρόσφατη τροποποίηση",
|
||||
"sortByName": "Ταξινόμηση κατά όνομα",
|
||||
"sortBySize": "Ταξινόμηση κατά μέγεθος",
|
||||
"noPreview": "Η προεπισκόπηση δεν είναι διαθέσιμη για αυτό το αρχείο."
|
||||
},
|
||||
"help": {
|
||||
"click": "επιλέξτε αρχείο ή φάκελο",
|
||||
"ctrl": {
|
||||
"click": "επιλογή πολλαπλών αρχείων ή φακέλων",
|
||||
"f": "ανοίγει την αναζήτηση",
|
||||
"s": "αποθηκεύει ένα αρχείο ή εκκινεί λήψη του φακέλου στον οποίο βρίσκεστε"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Λήψη αρχείου",
|
||||
"downloadFolder": "Λήψη φακέλου",
|
||||
"downloadSelected": "Λήψη επιλεγμένων"
|
||||
"del": "διαγραφή επιλεγμένων στοιχείων",
|
||||
"doubleClick": "ανοίγει ένα αρχείο ή φάκελο",
|
||||
"esc": "καθαρίζει την επιλογή ή/και κλείνει το παράθυρο",
|
||||
"f1": "αυτή η πληροφορία",
|
||||
"f2": "μετονομασία αρχείου",
|
||||
"help": "Βοήθεια"
|
||||
},
|
||||
"languages": {
|
||||
"he": "עברית",
|
||||
"hu": "Magyar",
|
||||
"ar": "العربية",
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"el": "Ελληνικά",
|
||||
"fr": "Français",
|
||||
"is": "Icelandic",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"ko": "한국어",
|
||||
"nlBE": "Dutch (Belgium)",
|
||||
"pl": "Polski",
|
||||
"pt": "Português",
|
||||
"ptBR": "Português (Brasil)",
|
||||
"ro": "Romanian",
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "Swedish (Sweden)",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
},
|
||||
"login": {
|
||||
"createAnAccount": "Δημιουργία λογαριασμού",
|
||||
"loginInstead": "Έχετε ήδη λογαριασμό",
|
||||
"password": "Κωδικός πρόσβασης",
|
||||
"passwordConfirm": "Επιβεβαίωση κωδικού πρόσβασης",
|
||||
"passwordsDontMatch": "Οι κωδικοί πρόσβασης δεν ταιριάζουν",
|
||||
"signup": "Εγγραφή",
|
||||
"submit": "Είσοδος",
|
||||
"username": "Όνομα χρήστη",
|
||||
"usernameTaken": "Το όνομα χρήστη χρησιμοποιείται ήδη",
|
||||
"wrongCredentials": "Λάθος όνομα ή/και κωδικός πρόσβασης",
|
||||
"or": "Ή"
|
||||
},
|
||||
"permanent": "Μόνιμο",
|
||||
"prompts": {
|
||||
"copy": "Αντιγραφή",
|
||||
"copyMessage": "Επιλέξτε τοποθεσία για αντιγραφή των αρχείων σας:",
|
||||
"deleteMessageMultiple": "Είστε σίγουροι ότι θέλετε να διαγράψετε {count} αρχεία;",
|
||||
"deleteMessageSingle": "Είστε σίγουροι ότι θέλετε να διαγράψετε αυτό το αρχείο/φάκελο;",
|
||||
"deleteMessageShare": "Είστε σίγουροι ότι θέλετε να διαγράψετε αυτή την κοινοποίηση ({path});",
|
||||
"deleteTitle": "Διαγραφή αρχείων",
|
||||
"displayName": "Εμφάνιση ονόματος:",
|
||||
"download": "Λήψη αρχείων",
|
||||
"downloadMessage": "Επιλέξτε τη μορφή που θέλετε να λάβετε.",
|
||||
"error": "Προέκυψε κάποιο σφάλμα",
|
||||
"fileInfo": "Πληροφορίες αρχείου",
|
||||
"lastModified": "Τελευταία τροποποίηση",
|
||||
"move": "Μετακίνηση",
|
||||
"moveMessage": "Επιλέξτε νέα τοποθεσία για τα αρχεία / τους φακέλους σας:",
|
||||
"newArchetype": "Δημιουργία νέας ανάρτησης με βάση έναν αρχέτυπο. Το αρχείο σας θα δημιουργηθεί στο φάκελο περιεχομένου.",
|
||||
"newDir": "Νέος φάκελος",
|
||||
"newDirMessage": "Γράψτε το όνομα του νέου φακέλου.",
|
||||
"newFile": "Νέο αρχείο",
|
||||
"newFileMessage": "Γράψτε το όνομα του νέου αρχείου.",
|
||||
"numberDirs": "Αριθμός φακέλων",
|
||||
"numberFiles": "Αριθμός αρχείων",
|
||||
"rename": "Μετονομασία",
|
||||
"renameMessage": "Εισαγάγετε ένα νέο όνομα για το",
|
||||
"replace": "Αντικατάσταση",
|
||||
"replaceMessage": "Ένα από τα αρχεία που προσπαθείτε να μεταφορτώσετε δημιουργεί σύγκρουση με υπάρχον αρχείο λόγω του ονόματός του. Θέλετε να συνεχίσετε τη μεταφόρτωση ή να αντικαταστήσετε το υπάρχον;\n",
|
||||
"schedule": "Προγραμματισμός",
|
||||
"scheduleMessage": "Επιλέξτε μια ημερομηνία και ώρα για τον προγραμματισμό της δημοσίευσης αυτής της ανάρτησης.",
|
||||
"show": "Εμφάνιση",
|
||||
"size": "Μέγεθος",
|
||||
"upload": "Μεταφόρτωση",
|
||||
"uploadFiles": "Μεταφόρτωση {files} αρχείων…",
|
||||
"uploadMessage": "Επιλέξτε μια επιλογή για τη μεταφόρτωση.",
|
||||
"optionalPassword": "Προαιρετικός κωδικός πρόσβασης",
|
||||
"currentlyNavigating": "Αυτή τη στιγμή πλοηγείστε στο:",
|
||||
"deleteUserMessage": "Είστε σίγουροι ότι θέλετε να διαγράψετε αυτόν τον χρήστη;",
|
||||
"filesSelected": "επιλεγμένα αρχεία",
|
||||
"typeName": "Τύπος:",
|
||||
"selected": "επιλεγμένο"
|
||||
},
|
||||
"search": {
|
||||
"images": "Εικόνες",
|
||||
"music": "Μουσική",
|
||||
"pdf": "PDF",
|
||||
"pressToSearch": "Πατήστε Enter για αναζήτηση…",
|
||||
"search": "Αναζήτηση…",
|
||||
"typeToSearch": "Πληκτρολογήστε για αναζήτηση…",
|
||||
"types": "Τύποι",
|
||||
"video": "Βίντεο",
|
||||
"path": "Μονοπάτι:",
|
||||
"smallerThan": "Μικρότερο από:",
|
||||
"largerThan": "Μεγαλύτερο από:",
|
||||
"helpText1": "Η αναζήτηση πραγματοποιείται σε κάθε χαρακτήρα που πληκτρολογείτε (ελάχιστο όριο 3 χαρακτήρων για τους όρους αναζήτησης).",
|
||||
"helpText2": "Ο δείκτης: Η αναζήτηση χρησιμοποιεί το ευρετήριο το οποίο ενημερώνεται αυτόματα στο ρυθμισμένο διάστημα (προεπιλογή: 5 λεπτά). Η αναζήτηση όταν το πρόγραμμα έχει μόλις ξεκινήσει μπορεί να οδηγήσει σε ελλιπή αποτελέσματα."
|
||||
},
|
||||
"settings": {
|
||||
"admin": "Διαχειριστής",
|
||||
"administrator": "Διαχειριστής",
|
||||
"allowCommands": "Εκτέλεση εντολών",
|
||||
"allowEdit": "Επεξεργασία, μετονομασία και διαγραφή αρχείων ή φακέλων",
|
||||
"allowNew": "Δημιουργία νέων αρχείων και φακέλων",
|
||||
"allowPublish": "Δημοσίευση νέων αναρτήσεων και σελίδων",
|
||||
"allowSignup": "Να επιτρέπεται η εγγραφή νέων χρηστών",
|
||||
"avoidChanges": "(αφήστε το κενό για αποφυγή αλλαγών)",
|
||||
"branding": "Εξατομίκευση",
|
||||
"brandingDirectoryPath": "Διαδρομή φακέλου εξατομίκευσης",
|
||||
"brandingHelp": "Μπορείτε να προσαρμόσετε την εμφάνισης της εφαρμογής File Browser αλλάζοντας το όνομά της, αντικαθιστώντας το λογότυπό της, προσθέτοντας προσαρμοσμένα στυλ και ακόμα και απενεργοποιώντας εξωτερικούς συνδέσμους προς το GitHub.\nΓια περισσότερες πληροφορίες σχετικά με αυτές τις προσαρμογές, ελέγξτε το {0}.",
|
||||
"changePassword": "Αλλαγή κωδικού πρόσβασης",
|
||||
"commandRunner": "Εκτέλεση εντολών",
|
||||
"commandRunnerHelp": "Εδώ μπορείτε να ορίσετε εντολές που εκτελούνται στα ονομασμένα γεγονότα και δραστηριότητες. Πρέπει να γράψετε μία εντολή ανά γραμμή. Οι μεταβλητές περιβάλλοντος {0} και {1} θα είναι διαθέσιμες, και θα είναι {0} σχετικές με το {1}. Για περισσότερες πληροφορίες σχετικά με αυτή τη λειτουργία και τις διαθέσιμες μεταβλητές περιβάλλοντος, παρακαλώ διαβάστε το {2}.",
|
||||
"commandsUpdated": "Οι εντολές ενημερώθηκαν!",
|
||||
"createUserDir": "Αυτόματη δημιουργία φακέλου χρήστη κατά την προσθήκη νέου χρήστη",
|
||||
"tusUploads": "Τμηματικές μεταφορές αρχείων",
|
||||
"tusUploadsHelp": "Η εφαρμογή File Browser υποστηρίζει τμηματικές μεταφορτώσεις αρχείων, επιτρέποντας την αποδοτική, αξιόπιστη και συνεχιζόμενη μεταφόρτωση αρχείων ακόμα και σε ασταθείς συνδέσεις δικτύου.",
|
||||
"tusUploadsChunkSize": "Υποδεικνύει το μέγιστο μέγεθος ενός αιτήματος μεταφόρτωσης (για μικρότερες μεταφορές αρχείων θα χρησιμοποιηθούν απευθείας και όχι τμηματικές μεταφορτώσεις). Μπορείτε να εισάγετε έναν ακέραιο αριθμό που υποδηλώνει το μέγεθος σε bytes, ή κείμενο με αριθμό και μονάδα μέτρησης μεγέθους δεδομένων, όπως 10MB, 1GB κλπ.",
|
||||
"tusUploadsRetryCount": "Αριθμός επαναληπτικών δοκιμών που θα πραγματοποιηθούν αν αποτύχει η μεταφόρτωση ενός τμήματος.",
|
||||
"userHomeBasePath": "Βασική διαδρομή αρχείων για τους φακέλους των χρηστών",
|
||||
"userScopeGenerationPlaceholder": "Η εμβέλεια εφαρμογής θα δημιουργηθεί αυτόματα",
|
||||
"createUserHomeDirectory": "Δημιουργία φακέλου χρήστη",
|
||||
"customStylesheet": "Προσαρμοσμένο στυλ εμφάνισης (stylesheet)",
|
||||
"defaultUserDescription": "Αυτές είναι οι προεπιλεγμένες ρυθμίσεις για νέους χρήστες.",
|
||||
"disableExternalLinks": "Απενεργοποίηση εξωτερικών συνδέσμων (εκτός από συνδέσμους προς τις οδηγίες χρήσης)",
|
||||
"disableUsedDiskPercentage": "Απενεργοποίηση γραφήματος ποσοστού χρήσης χώρου αποθήκευσης",
|
||||
"documentation": "οδηγίες χρήσης",
|
||||
"examples": "Παραδείγματα",
|
||||
"executeOnShell": "Εκτέλεση στο κέλυφος",
|
||||
"executeOnShellDescription": "Από προεπιλογή, η εφαρμογή File Browser εκτελεί τις εντολές καλώντας τα προγράμματα των εντολών απευθείας. Αν θέλετε να τις εκτελέσετε σε ένα κέλυφος (όπως το Bash ή το PowerShell), μπορείτε να το καθορίσετε εδώ με τις απαιτούμενες παραμέτρους. Εάν οριστεί, η εντολή που εκτελείτε θα προστίθεται ως παράμετρος. Αυτό ισχύει τόσο για τις εντολές χρήστη όσο και για τους αγκίστρους συμβάντων (event hooks).",
|
||||
"globalRules": "Πρόκειται για ένα γενικό σύνολο κανόνων που επιτρέπουν και απαγορεύουν διάφορες λειτουργίες και ισχύουν για κάθε χρήστη. Μπορείτε να καθορίσετε συγκεκριμένους κανόνες στις ρυθμίσεις κάθε χρήστη για να παρακάμψετε τους γενικούς κανόνες.",
|
||||
"globalSettings": "Γενικές ρυθμίσεις",
|
||||
"insertPath": "Εισάγετε διαδρομή",
|
||||
"insertRegex": "Εισάγετε έκφραση regex",
|
||||
"instanceName": "Όνομα περιβάλλοντος",
|
||||
"language": "Γλώσσα",
|
||||
"lockPassword": "Αποτρέψτε τον χρήστη από την αλλαγή του κωδικού πρόσβασης",
|
||||
"newPassword": "Νέος κωδικός πρόσβασης",
|
||||
"newPasswordConfirm": "Επιβεβαιώστε τον νέο κωδικό πρόσβασης",
|
||||
"newUser": "Νέος χρήστης",
|
||||
"password": "Κωδικός πρόσβασης",
|
||||
"passwordUpdated": "Ο κωδικός πρόσβασης ενημερώθηκε!",
|
||||
"path": "Διαδρομή",
|
||||
"permissions": {
|
||||
"create": "Δημιουργία αρχείων και φακέλων",
|
||||
"delete": "Διαγραφή αρχείων και φακέλων",
|
||||
"download": "Λήψη",
|
||||
"execute": "Εκτέλεση εντολών",
|
||||
"modify": "Επεξεργασία αρχείων",
|
||||
"rename": "Μετονομασία ή μετακίνηση αρχείων και φακέλων",
|
||||
"share": "Κοινοποίηση αρχείων",
|
||||
"admin": "Διαχειριστής",
|
||||
"api": "Δημιουργία και διαχείριση κλειδιών API μακράς διάρκειας ζωής",
|
||||
"realtime": "Ενεργοποίηση συνδέσεων και ενημερώσεων σε πραγματικό χρόνο"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Είστε σίγουροι ότι θέλετε να διακόψετε τη μεταφόρτωση;"
|
||||
"permissions-name": "Δικαιώματα",
|
||||
"permissionsHelp": "Μπορείτε να ορίσετε τον χρήστη ως διαχειριστή ή να επιλέξετε τα δικαιώματα μεμονωμένα. Αν επιλέξετε \"Διαχειριστής\", όλες οι υπόλοιπες επιλογές θα είναι αυτόματα επιλεγμένες. Η διαχείριση χρηστών παραμένει προνόμιο ενός χρήστη με τον ρόλο του διαχειριστή.\n",
|
||||
"profileSettings": "Ρυθμίσεις προφίλ",
|
||||
"ruleExample1": "αποκλείει την πρόσβαση σε οποιοδήποτε κρυφό αρχείο (όπως .git, .gitignore) σε κάθε φάκελο.\n",
|
||||
"ruleExample2": "αποκλείει την πρόσβαση στο αρχείο με το όνομα Caddyfile στον ριζικό φάκελο της εμβέλειας του κανόνα.",
|
||||
"rules": "Κανόνες",
|
||||
"rulesHelp": "Εδώ μπορείτε να ορίσετε ένα σύνολο κανόνων που επιτρέπουν και απαγορεύουν διάφορες λειτουργίες για τον συγκεκριμένο χρήστη. Τα αποκλεισμένα αρχεία δεν θα εμφανίζονται στα περιεχόμενα των αντίστοιχων φακέλων και δεν θα είναι προσβάσιμα από τον χρήστη. Υποστηρίζονται εκφράσεις regex και διαδρομές σχετικές με την εμβέλεια αρχείων των χρηστών.\n",
|
||||
"scope": "Εμβέλεια",
|
||||
"setDateFormat": "Ορισμός ακριβούς μορφής ημερομηνίας",
|
||||
"settingsUpdated": "Οι ρυθμίσεις ενημερώθηκαν!",
|
||||
"shareDuration": "Διάρκεια κοινοποίησης",
|
||||
"shareManagement": "Διαχείριση κοινοποίησης",
|
||||
"shareDeleted": "Η κοινοποίηση διαγράφηκε!",
|
||||
"singleClick": "Χρήση μονού κλικ για να ανοίξετε αρχεία και φακέλους",
|
||||
"themes": {
|
||||
"dark": "Σκοτεινό",
|
||||
"light": "Φωτεινό",
|
||||
"title": "Μοτίβο"
|
||||
},
|
||||
"errors": {
|
||||
"forbidden": "Δεν έχετε άδεια πρόσβασης σε αυτό.",
|
||||
"internal": "Προέκυψε εσωτερικό σφάλμα.",
|
||||
"notFound": "Αυτή η τοποθεσία δεν μπορεί να βρεθεί.",
|
||||
"connection": "Ο διακομιστής δεν είναι διαθέσιμος."
|
||||
},
|
||||
"files": {
|
||||
"body": "Περιεχόμενο",
|
||||
"clear": "Καθαρισμός",
|
||||
"closePreview": "Κλείσιμο προεπισκόπησης",
|
||||
"files": "Αρχεία",
|
||||
"folders": "Φάκελοι",
|
||||
"home": "Αρχική",
|
||||
"lastModified": "Τελευταία τροποποίηση",
|
||||
"loading": "Φορτώνει…",
|
||||
"lonely": "Δεν υπάρχει τίποτα εδώ (ακόμη)…",
|
||||
"metadata": "Μεταδεδομένα",
|
||||
"multipleSelectionEnabled": "Ενεργοποιημένη επιλογή πολλαπλών",
|
||||
"name": "Όνομα",
|
||||
"size": "Μέγεθος",
|
||||
"sortByLastModified": "Ταξινόμηση κατά πρόσφατη τροποποίηση",
|
||||
"sortByName": "Ταξινόμηση κατά όνομα",
|
||||
"sortBySize": "Ταξινόμηση κατά μέγεθος",
|
||||
"noPreview": "Η προεπισκόπηση δεν είναι διαθέσιμη για αυτό το αρχείο."
|
||||
},
|
||||
"help": {
|
||||
"click": "επιλέξτε αρχείο ή φάκελο",
|
||||
"ctrl": {
|
||||
"click": "επιλογή πολλαπλών αρχείων ή φακέλων",
|
||||
"f": "ανοίγει την αναζήτηση",
|
||||
"s": "αποθηκεύει ένα αρχείο ή εκκινεί λήψη του φακέλου στον οποίο βρίσκεστε"
|
||||
},
|
||||
"del": "διαγραφή επιλεγμένων στοιχείων",
|
||||
"doubleClick": "ανοίγει ένα αρχείο ή φάκελο",
|
||||
"esc": "καθαρίζει την επιλογή ή/και κλείνει το παράθυρο",
|
||||
"f1": "αυτή η πληροφορία",
|
||||
"f2": "μετονομασία αρχείου",
|
||||
"help": "Βοήθεια"
|
||||
},
|
||||
"languages": {
|
||||
"he": "עברית",
|
||||
"hu": "Magyar",
|
||||
"ar": "العربية",
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"el": "Ελληνικά",
|
||||
"fr": "Français",
|
||||
"is": "Icelandic",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"ko": "한국어",
|
||||
"nlBE": "Dutch (Belgium)",
|
||||
"pl": "Polski",
|
||||
"pt": "Português",
|
||||
"ptBR": "Português (Brasil)",
|
||||
"ro": "Romanian",
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "Swedish (Sweden)",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
},
|
||||
"login": {
|
||||
"createAnAccount": "Δημιουργία λογαριασμού",
|
||||
"loginInstead": "Έχετε ήδη λογαριασμό",
|
||||
"password": "Κωδικός πρόσβασης",
|
||||
"passwordConfirm": "Επιβεβαίωση κωδικού πρόσβασης",
|
||||
"passwordsDontMatch": "Οι κωδικοί πρόσβασης δεν ταιριάζουν",
|
||||
"signup": "Εγγραφή",
|
||||
"submit": "Είσοδος",
|
||||
"username": "Όνομα χρήστη",
|
||||
"usernameTaken": "Το όνομα χρήστη χρησιμοποιείται ήδη",
|
||||
"wrongCredentials": "Λάθος όνομα ή/και κωδικός πρόσβασης"
|
||||
},
|
||||
"permanent": "Μόνιμο",
|
||||
"prompts": {
|
||||
"copy": "Αντιγραφή",
|
||||
"copyMessage": "Επιλέξτε τοποθεσία για αντιγραφή των αρχείων σας:",
|
||||
"deleteMessageMultiple": "Είστε σίγουροι ότι θέλετε να διαγράψετε {count} αρχεία;",
|
||||
"deleteMessageSingle": "Είστε σίγουροι ότι θέλετε να διαγράψετε αυτό το αρχείο/φάκελο;",
|
||||
"deleteMessageShare": "Είστε σίγουροι ότι θέλετε να διαγράψετε αυτή την κοινοποίηση ({path});",
|
||||
"deleteTitle": "Διαγραφή αρχείων",
|
||||
"displayName": "Εμφάνιση ονόματος:",
|
||||
"download": "Λήψη αρχείων",
|
||||
"downloadMessage": "Επιλέξτε τη μορφή που θέλετε να λάβετε.",
|
||||
"error": "Προέκυψε κάποιο σφάλμα",
|
||||
"fileInfo": "Πληροφορίες αρχείου",
|
||||
"filesSelected": "Επιλέχθηκαν {count} αρχεία.",
|
||||
"lastModified": "Τελευταία τροποποίηση",
|
||||
"move": "Μετακίνηση",
|
||||
"moveMessage": "Επιλέξτε νέα τοποθεσία για τα αρχεία / τους φακέλους σας:",
|
||||
"newArchetype": "Δημιουργία νέας ανάρτησης με βάση έναν αρχέτυπο. Το αρχείο σας θα δημιουργηθεί στο φάκελο περιεχομένου.",
|
||||
"newDir": "Νέος φάκελος",
|
||||
"newDirMessage": "Γράψτε το όνομα του νέου φακέλου.",
|
||||
"newFile": "Νέο αρχείο",
|
||||
"newFileMessage": "Γράψτε το όνομα του νέου αρχείου.",
|
||||
"numberDirs": "Αριθμός φακέλων",
|
||||
"numberFiles": "Αριθμός αρχείων",
|
||||
"rename": "Μετονομασία",
|
||||
"renameMessage": "Εισαγάγετε ένα νέο όνομα για το",
|
||||
"replace": "Αντικατάσταση",
|
||||
"replaceMessage": "Ένα από τα αρχεία που προσπαθείτε να μεταφορτώσετε δημιουργεί σύγκρουση με υπάρχον αρχείο λόγω του ονόματός του. Θέλετε να συνεχίσετε τη μεταφόρτωση ή να αντικαταστήσετε το υπάρχον;\n",
|
||||
"schedule": "Προγραμματισμός",
|
||||
"scheduleMessage": "Επιλέξτε μια ημερομηνία και ώρα για τον προγραμματισμό της δημοσίευσης αυτής της ανάρτησης.",
|
||||
"show": "Εμφάνιση",
|
||||
"size": "Μέγεθος",
|
||||
"upload": "Μεταφόρτωση",
|
||||
"uploadFiles": "Μεταφόρτωση {files} αρχείων…",
|
||||
"uploadMessage": "Επιλέξτε μια επιλογή για τη μεταφόρτωση.",
|
||||
"optionalPassword": "Προαιρετικός κωδικός πρόσβασης"
|
||||
},
|
||||
"search": {
|
||||
"images": "Εικόνες",
|
||||
"music": "Μουσική",
|
||||
"pdf": "PDF",
|
||||
"pressToSearch": "Πατήστε Enter για αναζήτηση…",
|
||||
"search": "Αναζήτηση…",
|
||||
"typeToSearch": "Πληκτρολογήστε για αναζήτηση…",
|
||||
"types": "Τύποι",
|
||||
"video": "Βίντεο"
|
||||
},
|
||||
"settings": {
|
||||
"admin": "Διαχειριστής",
|
||||
"administrator": "Διαχειριστής",
|
||||
"allowCommands": "Εκτέλεση εντολών",
|
||||
"allowEdit": "Επεξεργασία, μετονομασία και διαγραφή αρχείων ή φακέλων",
|
||||
"allowNew": "Δημιουργία νέων αρχείων και φακέλων",
|
||||
"allowPublish": "Δημοσίευση νέων αναρτήσεων και σελίδων",
|
||||
"allowSignup": "Να επιτρέπεται η εγγραφή νέων χρηστών",
|
||||
"avoidChanges": "(αφήστε το κενό για αποφυγή αλλαγών)",
|
||||
"branding": "Εξατομίκευση",
|
||||
"brandingDirectoryPath": "Διαδρομή φακέλου εξατομίκευσης",
|
||||
"brandingHelp": "Μπορείτε να προσαρμόσετε την εμφάνισης της εφαρμογής File Browser αλλάζοντας το όνομά της, αντικαθιστώντας το λογότυπό της, προσθέτοντας προσαρμοσμένα στυλ και ακόμα και απενεργοποιώντας εξωτερικούς συνδέσμους προς το GitHub.\nΓια περισσότερες πληροφορίες σχετικά με αυτές τις προσαρμογές, ελέγξτε το {0}.",
|
||||
"changePassword": "Αλλαγή κωδικού πρόσβασης",
|
||||
"commandRunner": "Εκτέλεση εντολών",
|
||||
"commandRunnerHelp": "Εδώ μπορείτε να ορίσετε εντολές που εκτελούνται στα ονομασμένα γεγονότα και δραστηριότητες. Πρέπει να γράψετε μία εντολή ανά γραμμή. Οι μεταβλητές περιβάλλοντος {0} και {1} θα είναι διαθέσιμες, και θα είναι {0} σχετικές με το {1}. Για περισσότερες πληροφορίες σχετικά με αυτή τη λειτουργία και τις διαθέσιμες μεταβλητές περιβάλλοντος, παρακαλώ διαβάστε το {2}.",
|
||||
"commandsUpdated": "Οι εντολές ενημερώθηκαν!",
|
||||
"createUserDir": "Αυτόματη δημιουργία φακέλου χρήστη κατά την προσθήκη νέου χρήστη",
|
||||
"tusUploads": "Τμηματικές μεταφορές αρχείων",
|
||||
"tusUploadsHelp": "Η εφαρμογή File Browser υποστηρίζει τμηματικές μεταφορτώσεις αρχείων, επιτρέποντας την αποδοτική, αξιόπιστη και συνεχιζόμενη μεταφόρτωση αρχείων ακόμα και σε ασταθείς συνδέσεις δικτύου.",
|
||||
"tusUploadsChunkSize": "Υποδεικνύει το μέγιστο μέγεθος ενός αιτήματος μεταφόρτωσης (για μικρότερες μεταφορές αρχείων θα χρησιμοποιηθούν απευθείας και όχι τμηματικές μεταφορτώσεις). Μπορείτε να εισάγετε έναν ακέραιο αριθμό που υποδηλώνει το μέγεθος σε bytes, ή κείμενο με αριθμό και μονάδα μέτρησης μεγέθους δεδομένων, όπως 10MB, 1GB κλπ.",
|
||||
"tusUploadsRetryCount": "Αριθμός επαναληπτικών δοκιμών που θα πραγματοποιηθούν αν αποτύχει η μεταφόρτωση ενός τμήματος.",
|
||||
"userHomeBasePath": "Βασική διαδρομή αρχείων για τους φακέλους των χρηστών",
|
||||
"userScopeGenerationPlaceholder": "Η εμβέλεια εφαρμογής θα δημιουργηθεί αυτόματα",
|
||||
"createUserHomeDirectory": "Δημιουργία φακέλου χρήστη",
|
||||
"customStylesheet": "Προσαρμοσμένο στυλ εμφάνισης (stylesheet)",
|
||||
"defaultUserDescription": "Αυτές είναι οι προεπιλεγμένες ρυθμίσεις για νέους χρήστες.",
|
||||
"disableExternalLinks": "Απενεργοποίηση εξωτερικών συνδέσμων (εκτός από συνδέσμους προς τις οδηγίες χρήσης)",
|
||||
"disableUsedDiskPercentage": "Απενεργοποίηση γραφήματος ποσοστού χρήσης χώρου αποθήκευσης",
|
||||
"documentation": "οδηγίες χρήσης",
|
||||
"examples": "Παραδείγματα",
|
||||
"executeOnShell": "Εκτέλεση στο κέλυφος",
|
||||
"executeOnShellDescription": "Από προεπιλογή, η εφαρμογή File Browser εκτελεί τις εντολές καλώντας τα προγράμματα των εντολών απευθείας. Αν θέλετε να τις εκτελέσετε σε ένα κέλυφος (όπως το Bash ή το PowerShell), μπορείτε να το καθορίσετε εδώ με τις απαιτούμενες παραμέτρους. Εάν οριστεί, η εντολή που εκτελείτε θα προστίθεται ως παράμετρος. Αυτό ισχύει τόσο για τις εντολές χρήστη όσο και για τους αγκίστρους συμβάντων (event hooks).",
|
||||
"globalRules": "Πρόκειται για ένα γενικό σύνολο κανόνων που επιτρέπουν και απαγορεύουν διάφορες λειτουργίες και ισχύουν για κάθε χρήστη. Μπορείτε να καθορίσετε συγκεκριμένους κανόνες στις ρυθμίσεις κάθε χρήστη για να παρακάμψετε τους γενικούς κανόνες.",
|
||||
"globalSettings": "Γενικές ρυθμίσεις",
|
||||
"insertPath": "Εισάγετε διαδρομή",
|
||||
"insertRegex": "Εισάγετε έκφραση regex",
|
||||
"instanceName": "Όνομα περιβάλλοντος",
|
||||
"language": "Γλώσσα",
|
||||
"lockPassword": "Αποτρέψτε τον χρήστη από την αλλαγή του κωδικού πρόσβασης",
|
||||
"newPassword": "Νέος κωδικός πρόσβασης",
|
||||
"newPasswordConfirm": "Επιβεβαιώστε τον νέο κωδικό πρόσβασης",
|
||||
"newUser": "Νέος χρήστης",
|
||||
"password": "Κωδικός πρόσβασης",
|
||||
"passwordUpdated": "Ο κωδικός πρόσβασης ενημερώθηκε!",
|
||||
"path": "Διαδρομή",
|
||||
"permissions": {
|
||||
"create": "Δημιουργία αρχείων και φακέλων",
|
||||
"delete": "Διαγραφή αρχείων και φακέλων",
|
||||
"download": "Λήψη",
|
||||
"execute": "Εκτέλεση εντολών",
|
||||
"modify": "Επεξεργασία αρχείων",
|
||||
"rename": "Μετονομασία ή μετακίνηση αρχείων και φακέλων",
|
||||
"share": "Κοινοποίηση αρχείων"
|
||||
},
|
||||
"permissions-name": "Δικαιώματα",
|
||||
"permissionsHelp": "Μπορείτε να ορίσετε τον χρήστη ως διαχειριστή ή να επιλέξετε τα δικαιώματα μεμονωμένα. Αν επιλέξετε \"Διαχειριστής\", όλες οι υπόλοιπες επιλογές θα είναι αυτόματα επιλεγμένες. Η διαχείριση χρηστών παραμένει προνόμιο ενός χρήστη με τον ρόλο του διαχειριστή.\n",
|
||||
"profileSettings": "Ρυθμίσεις προφίλ",
|
||||
"ruleExample1": "αποκλείει την πρόσβαση σε οποιοδήποτε κρυφό αρχείο (όπως .git, .gitignore) σε κάθε φάκελο.\n",
|
||||
"ruleExample2": "αποκλείει την πρόσβαση στο αρχείο με το όνομα Caddyfile στον ριζικό φάκελο της εμβέλειας του κανόνα.",
|
||||
"rules": "Κανόνες",
|
||||
"rulesHelp": "Εδώ μπορείτε να ορίσετε ένα σύνολο κανόνων που επιτρέπουν και απαγορεύουν διάφορες λειτουργίες για τον συγκεκριμένο χρήστη. Τα αποκλεισμένα αρχεία δεν θα εμφανίζονται στα περιεχόμενα των αντίστοιχων φακέλων και δεν θα είναι προσβάσιμα από τον χρήστη. Υποστηρίζονται εκφράσεις regex και διαδρομές σχετικές με την εμβέλεια αρχείων των χρηστών.\n",
|
||||
"scope": "Εμβέλεια",
|
||||
"setDateFormat": "Ορισμός ακριβούς μορφής ημερομηνίας",
|
||||
"settingsUpdated": "Οι ρυθμίσεις ενημερώθηκαν!",
|
||||
"shareDuration": "Διάρκεια κοινοποίησης",
|
||||
"shareManagement": "Διαχείριση κοινοποίησης",
|
||||
"shareDeleted": "Η κοινοποίηση διαγράφηκε!",
|
||||
"singleClick": "Χρήση μονού κλικ για να ανοίξετε αρχεία και φακέλους",
|
||||
"themes": {
|
||||
"dark": "Σκοτεινό",
|
||||
"light": "Φωτεινό",
|
||||
"title": "Μοτίβο"
|
||||
},
|
||||
"user": "Χρήστης",
|
||||
"userCommands": "Εντολές χρήστη",
|
||||
"userCommandsHelp": "Μια λίστα με τις διαθέσιμες εντολές για αυτόν το χρήστη, χωρισμένες μεταξύ τους με κενά. Παράδειγμα:\n",
|
||||
"userCreated": "Ο χρήστης δημιουργήθηκε!",
|
||||
"userDefaults": "Προεπιλεγμένες ρυθμίσεις χρήστη",
|
||||
"userDeleted": "Ο χρήστης διαγράφηκε!",
|
||||
"userManagement": "Διαχείριση χρηστών",
|
||||
"userUpdated": "Ο χρήστης ενημερώθηκε!",
|
||||
"username": "Όνομα χρήστη",
|
||||
"users": "Χρήστες"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Βοήθεια",
|
||||
"hugoNew": "Νέο Hugo",
|
||||
"login": "Σύνδεση",
|
||||
"logout": "Αποσύνδεση",
|
||||
"myFiles": "Τα αρχεία μου",
|
||||
"newFile": "Νέο αρχείο",
|
||||
"newFolder": "Νέος φάκελος",
|
||||
"preview": "Προεπισκόπηση",
|
||||
"settings": "Ρυθμίσεις",
|
||||
"signup": "Εγγραφή",
|
||||
"siteSettings": "Ρυθμίσεις ιστότοπου"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Ο σύνδεσμος αντιγράφηκε!"
|
||||
},
|
||||
"time": {
|
||||
"days": "Ημέρες",
|
||||
"hours": "Ώρες",
|
||||
"minutes": "Λεπτά",
|
||||
"seconds": "Δευτερόλεπτα",
|
||||
"unit": "Μονάδα χρόνου"
|
||||
}
|
||||
"user": "Χρήστης",
|
||||
"userCommands": "Εντολές χρήστη",
|
||||
"userCommandsHelp": "Μια λίστα με τις διαθέσιμες εντολές για αυτόν το χρήστη, χωρισμένες μεταξύ τους με κενά. Παράδειγμα:\n",
|
||||
"userCreated": "Ο χρήστης δημιουργήθηκε!",
|
||||
"userDefaults": "Προεπιλεγμένες ρυθμίσεις χρήστη",
|
||||
"userDeleted": "Ο χρήστης διαγράφηκε!",
|
||||
"userManagement": "Διαχείριση χρηστών",
|
||||
"userUpdated": "Ο χρήστης ενημερώθηκε!",
|
||||
"username": "Όνομα χρήστη",
|
||||
"users": "Χρήστες",
|
||||
"loginMethod": "Μέθοδος σύνδεσης",
|
||||
"modifyOtherUser": "Τροποποίηση χρήστη:",
|
||||
"modifyCurrentUser": "Τροποποίηση τρέχοντος χρήστη",
|
||||
"themeColor": "Χρώμα θέματος",
|
||||
"disableOfficePreviewDescription": "Ένας κατάλογος επεκτάσεων αρχείων με διαχωρισμό διαστήματος για την απενεργοποίηση της προβολής OnlyOffice. (π.χ. '.txt .html').",
|
||||
"disableOfficePreview": "Απενεργοποίηση της προβολής onlyoffice για ορισμένες επεκτάσεις αρχείων",
|
||||
"filePreviewOptions": "Επιλογές προεπισκόπησης αρχείων",
|
||||
"listingOptions": "Επιλογές καταχώρισης",
|
||||
"emptyGlobal": "Προς το παρόν δεν υπάρχουν καθολικές επιλογές ρυθμίσεων, Μπορείτε να επεξεργαστείτε το yaml ρυθμίσεων για να προσαρμόσετε τις ρυθμίσεις του συστήματος.",
|
||||
"scopes": "Καθορισμός των επιτρεπόμενων πηγών και του πεδίου εφαρμογής του χρήστη σε αυτές",
|
||||
"UserManagement": "Διαχείριση χρηστών",
|
||||
"api": "Κλειδιά API",
|
||||
"loginMethodDescription": "επιτρεπόμενη μέθοδος σύνδεσης για τον χρήστη.",
|
||||
"userNotAdmin": "Ο χρήστης δεν είναι διαχειριστής",
|
||||
"enterPassword": "Εισάγετε τον κωδικό πρόσβασης",
|
||||
"enterPasswordAgain": "Πληκτρολογήστε ξανά τον κωδικό πρόσβασης",
|
||||
"passwordsDoNotMatch": "Οι κωδικοί πρόσβασης δεν ταιριάζουν"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Βοήθεια",
|
||||
"hugoNew": "Νέο Hugo",
|
||||
"login": "Σύνδεση",
|
||||
"logout": "Αποσύνδεση",
|
||||
"myFiles": "Τα αρχεία μου",
|
||||
"newFile": "Νέο αρχείο",
|
||||
"newFolder": "Νέος φάκελος",
|
||||
"preview": "Προεπισκόπηση",
|
||||
"settings": "Ρυθμίσεις",
|
||||
"signup": "Εγγραφή",
|
||||
"siteSettings": "Ρυθμίσεις ιστότοπου",
|
||||
"sources": "Πηγές"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Ο σύνδεσμος αντιγράφηκε!"
|
||||
},
|
||||
"time": {
|
||||
"days": "Ημέρες",
|
||||
"hours": "Ώρες",
|
||||
"minutes": "Λεπτά",
|
||||
"seconds": "Δευτερόλεπτα",
|
||||
"unit": "Μονάδα χρόνου"
|
||||
},
|
||||
"share": {
|
||||
"notice": "Σημείωση: οποιοσδήποτε έχει πρόσβαση στο σύνδεσμο (και προαιρετικό κωδικό πρόσβασης) μπορεί να έχει πρόσβαση στα κοινόχρηστα αρχεία. Δεν υπάρχει απαίτηση σύνδεσης."
|
||||
},
|
||||
"api": {
|
||||
"title": "Κλειδιά API:",
|
||||
"keyName": "Όνομα κλειδιού API:",
|
||||
"createdAt": "Δημιουργήθηκε στο:",
|
||||
"expiresAt": "Λήγει στις:",
|
||||
"permissions": "Άδειες:",
|
||||
"createTitle": "Δημιουργία κλειδιού API",
|
||||
"keyNamePlaceholder": "Εισάγετε ένα μοναδικό όνομα κλειδιού API:",
|
||||
"tokenDuration": "Διάρκεια μάρκας:",
|
||||
"durationNumberPlaceholder": "Αριθμός",
|
||||
"days": "Ημέρες",
|
||||
"months": "Μήνες",
|
||||
"permissionNote": "Επιλέξτε τουλάχιστον μία άδεια για το κλειδί. Ο χρήστης σας πρέπει επίσης να έχει το δικαίωμα.",
|
||||
"createKeyFailed": "Απέτυχε η δημιουργία κλειδιού API.",
|
||||
"createKeySuccess": "Το κλειδί API δημιουργήθηκε με επιτυχία.",
|
||||
"description": "Τα κλειδιά API βασίζονται στον χρήστη που τα δημιουργεί. Βλέπε",
|
||||
"swaggerLinkText": "σελίδα swagger",
|
||||
"name": "Όνομα",
|
||||
"created": "Δημιουργήθηκε",
|
||||
"expires": "Λήγει",
|
||||
"actions": "Δράσεις",
|
||||
"enabled": "Ενεργοποιημένο",
|
||||
"disabled": "Άτομα με ειδικές ανάγκες"
|
||||
},
|
||||
"index": {
|
||||
"status": "Κατάσταση",
|
||||
"assessment": "Αξιολόγηση",
|
||||
"files": "Αρχεία",
|
||||
"folders": "Φάκελοι",
|
||||
"lastScanned": "Τελευταία σάρωση",
|
||||
"quickScan": "Δευτερόλεπτα γρήγορης σάρωσης",
|
||||
"fullScan": "Δευτερόλεπτα πλήρους σάρωσης",
|
||||
"settingsHover": "Ρυθμίσεις για τον χρήστη",
|
||||
"logout": "Αποσύνδεση",
|
||||
"toggleClick": "Εναλλαγή με ένα κλικ",
|
||||
"toggleDark": "Εναλλαγή σκοτεινής λειτουργίας",
|
||||
"toggleSticky": "Εναλλαγή της λειτουργίας Sticky",
|
||||
"of": "του",
|
||||
"used": "χρησιμοποιημένο"
|
||||
}
|
||||
}
|
||||
@@ -122,9 +122,13 @@
|
||||
"submit": "Login",
|
||||
"username": "Username",
|
||||
"usernameTaken": "Username already taken",
|
||||
"wrongCredentials": "Wrong credentials"
|
||||
"wrongCredentials": "Wrong credentials",
|
||||
"or": "OR"
|
||||
},
|
||||
"permanent": "Permanent",
|
||||
"share": {
|
||||
"notice": "Note: anyone who has access to the link (and optional password) can access the shared files. There is no requirement to be logged in."
|
||||
},
|
||||
"prompts": {
|
||||
"copy": "Copy",
|
||||
"copyMessage": "Choose the place to copy your files:",
|
||||
@@ -132,13 +136,15 @@
|
||||
"deleteMessageMultiple": "Are you sure you want to delete {count} file(s)?",
|
||||
"deleteMessageSingle": "Are you sure you want to delete this file/folder?",
|
||||
"deleteMessageShare": "Are you sure you want to delete this share: {path} ?",
|
||||
"deleteUserMessage": "Are you sure you want to delete this user?",
|
||||
"deleteTitle": "Delete files",
|
||||
"displayName": "Display Name:",
|
||||
"download": "Download files",
|
||||
"downloadMessage": "Choose the format you want to download.",
|
||||
"error": "Something went wrong",
|
||||
"fileInfo": "File information",
|
||||
"filesSelected": "{count} files selected.",
|
||||
"selected": "selected",
|
||||
"filesSelected": "files selected",
|
||||
"lastModified": "Last Modified",
|
||||
"move": "Move",
|
||||
"moveMessage": "Choose new house for your file(s)/folder(s):",
|
||||
@@ -160,7 +166,8 @@
|
||||
"upload": "Upload",
|
||||
"uploadFiles": "Uploading {files} files...",
|
||||
"uploadMessage": "Select an option to upload.",
|
||||
"optionalPassword": "Optional password"
|
||||
"optionalPassword": "Optional password",
|
||||
"typeName": "Type:"
|
||||
},
|
||||
"search": {
|
||||
"images": "Images",
|
||||
@@ -169,13 +176,32 @@
|
||||
"pressToSearch": "No results found in indexed search.",
|
||||
"search": "Search...",
|
||||
"typeToSearch": "Type to search... (3 character minimum)",
|
||||
"path": "Path:",
|
||||
"types": "Types",
|
||||
"video": "Video"
|
||||
"video": "Video",
|
||||
"smallerThan": "Smaller than:",
|
||||
"largerThan": "Larger than:",
|
||||
"helpText1": "Search occurs on each character you type (3 character minimum for search terms).",
|
||||
"helpText2": "The index: Search utilizes the index which automatically gets updated on the configured interval (default: 5 minutes). Searching when the program has just started may result in incomplete results."
|
||||
},
|
||||
"settings": {
|
||||
"enterPassword": "Enter password",
|
||||
"enterPasswordAgain": "Enter the password again",
|
||||
"passwordsDoNotMatch": "Passwords do not match",
|
||||
"loginMethod": "Login method",
|
||||
"loginMethodDescription": "allowed login method for the user.",
|
||||
"modifyOtherUser": "Modify user:",
|
||||
"modifyCurrentUser": "Modify current user",
|
||||
"themeColor": "Theme Color",
|
||||
"disableOfficePreviewDescription": "A space-separated list of file extensions to disable the OnlyOffice viewer for. (e.g., '.txt .html').",
|
||||
"disableOfficePreview": "Disable onlyoffice viewer for certain file extensions",
|
||||
"filePreviewOptions": "File preview options",
|
||||
"listingOptions": "Listing options",
|
||||
"emptyGlobal": "Currently there are no global config options, You can edit the configuration yaml to adjust system settings.",
|
||||
"scopes": "Define allowed sources and the user scope within them",
|
||||
"UserManagement": "User Management",
|
||||
"admin": "Admin",
|
||||
"userNotAdmin": "User is not an administrator",
|
||||
"administrator": "Administrator",
|
||||
"allowCommands": "Execute commands",
|
||||
"allowEdit": "Edit, rename and delete files or directories",
|
||||
@@ -267,6 +293,7 @@
|
||||
"newFolder": "New folder",
|
||||
"preview": "Preview",
|
||||
"settings": "Settings",
|
||||
"sources": "Sources",
|
||||
"signup": "Signup",
|
||||
"siteSettings": "Site Settings"
|
||||
},
|
||||
@@ -279,5 +306,45 @@
|
||||
"minutes": "Minutes",
|
||||
"seconds": "Seconds",
|
||||
"unit": "Time Unit"
|
||||
},
|
||||
"api": {
|
||||
"title": "API Keys:",
|
||||
"keyName": "API Key Name:",
|
||||
"createdAt": "Created At:",
|
||||
"expiresAt": "Expires At:",
|
||||
"permissions": "Permissions:",
|
||||
"createTitle": "Create API Key",
|
||||
"keyNamePlaceholder": "Enter a unique API key name:",
|
||||
"tokenDuration": "Token Duration:",
|
||||
"durationNumberPlaceholder": "Number",
|
||||
"days": "Days",
|
||||
"months": "Months",
|
||||
"permissionNote": "Choose at least one permission for the key. Your user must also have the permission.",
|
||||
"createKeyFailed": "Failed to create API key.",
|
||||
"createKeySuccess": "API key created successfully.",
|
||||
"description": "API keys are based on the user that creates them. See",
|
||||
"swaggerLinkText": "swagger page",
|
||||
"name": "Name",
|
||||
"created": "Created",
|
||||
"expires": "Expires",
|
||||
"actions": "Actions",
|
||||
"enabled": "Enabled",
|
||||
"disabled": "Disabled"
|
||||
},
|
||||
"index": {
|
||||
"status": "Status",
|
||||
"assessment": "Assessment",
|
||||
"files": "Files",
|
||||
"folders": "Folders",
|
||||
"lastScanned": "Last Scanned",
|
||||
"quickScan": "Quick Scan Seconds",
|
||||
"fullScan": "Full Scan Seconds",
|
||||
"settingsHover": "Settings For User",
|
||||
"logout": "Logout",
|
||||
"toggleClick": "Toggle Single Click",
|
||||
"toggleDark": "Toggle Dark Mode",
|
||||
"toggleSticky": "Toggle Sticky Mode",
|
||||
"of": "of",
|
||||
"used": "used"
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,9 @@
|
||||
"toggleSidebar": "Mostrar/Ocultar menú",
|
||||
"update": "Actualizar",
|
||||
"upload": "Subir",
|
||||
"openFile": "Abrir archivo"
|
||||
"openFile": "Abrir archivo",
|
||||
"copyDownloadLinkToClipboard": "Copiar enlace de descarga al portapapeles",
|
||||
"continue": "Continúe en"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Descargar fichero",
|
||||
@@ -101,7 +103,7 @@
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "Swedish (Sweden)",
|
||||
"tr" : "Türkçe",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
@@ -116,7 +118,8 @@
|
||||
"submit": "Iniciar sesión",
|
||||
"username": "Usuario",
|
||||
"usernameTaken": "Nombre usuario no disponible",
|
||||
"wrongCredentials": "Usuario y/o contraseña incorrectos"
|
||||
"wrongCredentials": "Usuario y/o contraseña incorrectos",
|
||||
"or": "O"
|
||||
},
|
||||
"permanent": "Permanente",
|
||||
"prompts": {
|
||||
@@ -132,7 +135,6 @@
|
||||
"downloadMessage": "Elige el formato de descarga.",
|
||||
"error": "Algo ha fallado",
|
||||
"fileInfo": "Información del archivo",
|
||||
"filesSelected": "{count} archivos seleccionados.",
|
||||
"lastModified": "Última modificación",
|
||||
"move": "Mover",
|
||||
"moveMessage": "Elige una nueva casa para tus archivo(s)/carpeta(s):",
|
||||
@@ -154,7 +156,11 @@
|
||||
"upload": "Subir",
|
||||
"uploadFiles": "Subiendo {files} archivos...",
|
||||
"uploadMessage": "Seleccione una opción para subir.",
|
||||
"optionalPassword": "Contraseña opcional"
|
||||
"optionalPassword": "Contraseña opcional",
|
||||
"deleteUserMessage": "¿Está seguro de que desea eliminar este usuario?",
|
||||
"filesSelected": "archivos seleccionados",
|
||||
"typeName": "Tipo:",
|
||||
"selected": "seleccionado"
|
||||
},
|
||||
"search": {
|
||||
"images": "Imágenes",
|
||||
@@ -164,7 +170,12 @@
|
||||
"search": "Buscar...",
|
||||
"typeToSearch": "Escribe para realizar una busqueda...",
|
||||
"types": "Tipos",
|
||||
"video": "Vídeo"
|
||||
"video": "Vídeo",
|
||||
"path": "Senda:",
|
||||
"smallerThan": "Más pequeño que:",
|
||||
"largerThan": "Más grande que:",
|
||||
"helpText1": "La búsqueda se realiza por cada carácter que escriba (mínimo de 3 caracteres para los términos de búsqueda).",
|
||||
"helpText2": "El índice: La búsqueda utiliza el índice que se actualiza automáticamente en el intervalo configurado (por defecto: 5 minutos). La búsqueda cuando el programa acaba de iniciarse puede dar lugar a resultados incompletos."
|
||||
},
|
||||
"settings": {
|
||||
"scopes": "Definir fuentes permitidas y el alcance del usuario dentro de ellas",
|
||||
@@ -215,7 +226,10 @@
|
||||
"execute": "Executar comandos",
|
||||
"modify": "Editar ficheros",
|
||||
"rename": "Renombrar o mover ficheros y directorios",
|
||||
"share": "Compartir ficheros"
|
||||
"share": "Compartir ficheros",
|
||||
"admin": "Administrador",
|
||||
"api": "Crear y gestionar claves API de larga duración",
|
||||
"realtime": "Permitir conexiones y actualizaciones en tiempo real"
|
||||
},
|
||||
"permissions-name": "Permisos",
|
||||
"permissionsHelp": "Puedes nombrar al usuario como administrador o elegir los permisos individualmente. Si seleccionas \"Administrador\", todas las otras opciones serán activadas automáticamente. La administración de usuarios es un privilegio de administrador.\n",
|
||||
@@ -245,7 +259,27 @@
|
||||
"userManagement": "Administración de usuarios",
|
||||
"userUpdated": "¡Usuario actualizado!",
|
||||
"username": "Usuario",
|
||||
"users": "Usuarios"
|
||||
"users": "Usuarios",
|
||||
"loginMethod": "Método de inicio de sesión",
|
||||
"modifyOtherUser": "Modificar usuario:",
|
||||
"modifyCurrentUser": "Modificar el usuario actual",
|
||||
"themeColor": "Tema Color",
|
||||
"disableOfficePreviewDescription": "Una lista separada por espacios de las extensiones de archivo para las que desea desactivar el visor de OnlyOffice. (por ejemplo, '.txt .html').",
|
||||
"disableOfficePreview": "Desactivar onlyoffice viewer para determinadas extensiones de archivo",
|
||||
"filePreviewOptions": "Opciones de previsualización de archivos",
|
||||
"listingOptions": "Opciones de listado",
|
||||
"emptyGlobal": "Actualmente no hay opciones de configuración global, puede editar el yaml de configuración para ajustar la configuración del sistema.",
|
||||
"UserManagement": "Gestión de usuarios",
|
||||
"tusUploads": "Subidas en trozos",
|
||||
"tusUploadsHelp": "File Browser admite la carga de archivos en trozos, lo que permite crear cargas de archivos eficientes, fiables, reanudables y en trozos, incluso en redes poco fiables.",
|
||||
"tusUploadsChunkSize": "Indica el tamaño máximo de una solicitud (las cargas directas se utilizarán para cargas más pequeñas). Puede introducir un número entero que indique una entrada en bytes o una cadena como 10 MB, 1 GB, etc.",
|
||||
"tusUploadsRetryCount": "Número de reintentos a realizar si falla la subida de un chunk.",
|
||||
"api": "Claves API",
|
||||
"loginMethodDescription": "método de inicio de sesión permitido para el usuario.",
|
||||
"userNotAdmin": "El usuario no es administrador",
|
||||
"enterPassword": "Introduzca la contraseña",
|
||||
"enterPasswordAgain": "Vuelva a introducir la contraseña",
|
||||
"passwordsDoNotMatch": "Las contraseñas no coinciden"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Ayuda",
|
||||
@@ -258,7 +292,8 @@
|
||||
"preview": "Vista previa",
|
||||
"settings": "Ajustes",
|
||||
"signup": "Registrate",
|
||||
"siteSettings": "Ajustes del sitio"
|
||||
"siteSettings": "Ajustes del sitio",
|
||||
"sources": "Fuentes"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "¡Link copiado!"
|
||||
@@ -269,5 +304,51 @@
|
||||
"minutes": "Minutos",
|
||||
"seconds": "Segundos",
|
||||
"unit": "Unidad"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "¿Seguro que quieres abortar?"
|
||||
},
|
||||
"share": {
|
||||
"notice": "Nota: cualquiera que tenga acceso al enlace (y contraseña opcional) puede acceder a los archivos compartidos. No es necesario haber iniciado sesión."
|
||||
},
|
||||
"api": {
|
||||
"title": "Claves API:",
|
||||
"keyName": "Nombre de la clave API:",
|
||||
"createdAt": "Creado en:",
|
||||
"expiresAt": "Expira en:",
|
||||
"permissions": "Permisos:",
|
||||
"createTitle": "Crear clave API",
|
||||
"keyNamePlaceholder": "Introduzca un nombre de clave de API único:",
|
||||
"tokenDuration": "Duración de la ficha:",
|
||||
"durationNumberPlaceholder": "Número",
|
||||
"days": "Días",
|
||||
"months": "Meses",
|
||||
"permissionNote": "Elija al menos un permiso para la clave. Su usuario también debe tener el permiso.",
|
||||
"createKeyFailed": "Error al crear la clave API.",
|
||||
"createKeySuccess": "Clave API creada correctamente.",
|
||||
"description": "Las claves API se basan en el usuario que las crea. Véase",
|
||||
"swaggerLinkText": "página swagger",
|
||||
"name": "Nombre",
|
||||
"created": "Creado",
|
||||
"expires": "Expira en",
|
||||
"actions": "Acciones",
|
||||
"enabled": "Activado",
|
||||
"disabled": "Discapacitados"
|
||||
},
|
||||
"index": {
|
||||
"status": "Estado",
|
||||
"assessment": "Evaluación",
|
||||
"files": "Archivos",
|
||||
"folders": "Carpetas",
|
||||
"lastScanned": "Último escaneado",
|
||||
"quickScan": "Segundos de exploración rápida",
|
||||
"fullScan": "Segundos de exploración completa",
|
||||
"settingsHover": "Ajustes para el usuario",
|
||||
"logout": "Cierre de sesión",
|
||||
"toggleClick": "Conmutar un solo clic",
|
||||
"toggleDark": "Activar el modo oscuro",
|
||||
"toggleSticky": "Conmutar el modo adhesivo",
|
||||
"of": "de",
|
||||
"used": "usado"
|
||||
}
|
||||
}
|
||||
+95
-11
@@ -35,7 +35,9 @@
|
||||
"toggleSidebar": "Afficher/Masquer la barre latérale",
|
||||
"update": "Mettre à jour",
|
||||
"upload": "Importer",
|
||||
"openFile": "Ouvrir le fichier"
|
||||
"openFile": "Ouvrir le fichier",
|
||||
"copyDownloadLinkToClipboard": "Copier le lien de téléchargement dans le presse-papiers",
|
||||
"continue": "Continuer"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Télécharger le fichier",
|
||||
@@ -101,7 +103,7 @@
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "",
|
||||
"tr" : "Türkçe",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
@@ -116,7 +118,8 @@
|
||||
"submit": "Se connecter",
|
||||
"username": "Utilisateur",
|
||||
"usernameTaken": "Le nom d'utilisateur est déjà pris",
|
||||
"wrongCredentials": "Identifiants incorrects !"
|
||||
"wrongCredentials": "Identifiants incorrects !",
|
||||
"or": "OU"
|
||||
},
|
||||
"permanent": "Permanent",
|
||||
"prompts": {
|
||||
@@ -132,7 +135,6 @@
|
||||
"downloadMessage": "Choisissez le format de téléchargement :",
|
||||
"error": "Quelque chose s'est mal passé",
|
||||
"fileInfo": "Informations",
|
||||
"filesSelected": "{count} éléments sélectionnés",
|
||||
"lastModified": "Dernière modification",
|
||||
"move": "Déplacer",
|
||||
"moveMessage": "Choisissez l'emplacement où déplacer la sélection :",
|
||||
@@ -154,7 +156,11 @@
|
||||
"upload": "Importer",
|
||||
"uploadFiles": "Importation de {files} fichiers...",
|
||||
"uploadMessage": "Séléctionnez une option d'import.",
|
||||
"optionalPassword": "Mot de passe optionnel"
|
||||
"optionalPassword": "Mot de passe optionnel",
|
||||
"deleteUserMessage": "Êtes-vous sûr de vouloir supprimer cet utilisateur ?",
|
||||
"filesSelected": "fichiers sélectionnés",
|
||||
"typeName": "Type :",
|
||||
"selected": "sélectionné"
|
||||
},
|
||||
"search": {
|
||||
"images": "Images",
|
||||
@@ -164,7 +170,12 @@
|
||||
"search": "Recherche en cours...",
|
||||
"typeToSearch": "Écrivez pour chercher...",
|
||||
"types": "Types",
|
||||
"video": "Video"
|
||||
"video": "Video",
|
||||
"path": "Trajectoire :",
|
||||
"smallerThan": "Plus petit que :",
|
||||
"largerThan": "Plus grand que :",
|
||||
"helpText1": "La recherche s'effectue sur chaque caractère saisi (3 caractères minimum pour les termes de recherche).",
|
||||
"helpText2": "L'index : La recherche utilise l'index qui est automatiquement mis à jour à l'intervalle configuré (par défaut : 5 minutes). Une recherche effectuée alors que le programme vient de démarrer peut donner des résultats incomplets."
|
||||
},
|
||||
"settings": {
|
||||
"scopes": "Définir les sources autorisées et la portée de l'utilisateur au sein de celles-ci",
|
||||
@@ -181,7 +192,7 @@
|
||||
"brandingHelp": "Vous pouvez personnaliser l'apparence de votre instance de File Browser en changeant son nom, en remplaçant le logo, en ajoutant des styles personnalisés et même en désactivant les liens externes vers GitHub.\nPour plus d'informations sur la personnalisation de l'image de marque, veuillez consulter la {0}.",
|
||||
"changePassword": "Modifier le mot de passe",
|
||||
"commandRunner": "Command runner",
|
||||
"commandRunnerHelp" : "Ici, vous pouvez définir les commandes qui sont exécutées pour les événements nommés précédemments. Vous devez en écrire une par ligne. Les variables d'environnement {0} et {1} seront disponibles, {0} étant relatif à {1}. Pour plus d'informations sur cette fonctionnalité et les variables d'environnement disponibles, veuillez lire la {2}.",
|
||||
"commandRunnerHelp": "Ici, vous pouvez définir les commandes qui sont exécutées pour les événements nommés précédemments. Vous devez en écrire une par ligne. Les variables d'environnement {0} et {1} seront disponibles, {0} étant relatif à {1}. Pour plus d'informations sur cette fonctionnalité et les variables d'environnement disponibles, veuillez lire la {2}.",
|
||||
"commandsUpdated": "Commandes mises à jour !",
|
||||
"createUserDir": "Créer automatiquement un dossier pour l'utilisateur",
|
||||
"customStylesheet": "Feuille de style personnalisée",
|
||||
@@ -204,7 +215,7 @@
|
||||
"newUser": "Nouvel Utilisateur",
|
||||
"password": "Mot de passe",
|
||||
"passwordUpdated": "Mot de passe mis à jour !",
|
||||
"path": "",
|
||||
"path": "Trajectoire",
|
||||
"permissions": {
|
||||
"create": "Créer des fichiers et des dossiers",
|
||||
"delete": "Supprimer des fichiers et des dossiers",
|
||||
@@ -212,7 +223,10 @@
|
||||
"execute": "Exécuter des commandes",
|
||||
"modify": "Modifier des fichiers",
|
||||
"rename": "Renommer ou déplacer des fichiers ou des dossiers",
|
||||
"share": "Partager des fichiers"
|
||||
"share": "Partager des fichiers",
|
||||
"admin": "Administrateur",
|
||||
"api": "Créer et gérer des clés API à longue durée de vie",
|
||||
"realtime": "Permettre des connexions et des mises à jour en temps réel"
|
||||
},
|
||||
"permissions-name": "Permissions",
|
||||
"permissionsHelp": "Vous pouvez définir l'utilisateur comme étant un administrateur ou encore choisir les permissions individuellement. Si vous sélectionnez \"Administrateur\", toutes les autres options seront automatiquement activées. La gestion des utilisateurs est un privilège que seul l'administrateur possède.\n",
|
||||
@@ -242,7 +256,30 @@
|
||||
"userManagement": "Gestion des utilisateurs",
|
||||
"userUpdated": "Utilisateur mis à jour !",
|
||||
"username": "Nom d'utilisateur",
|
||||
"users": "Utilisateurs"
|
||||
"users": "Utilisateurs",
|
||||
"loginMethod": "Méthode de connexion",
|
||||
"modifyOtherUser": "Modifier l'utilisateur :",
|
||||
"modifyCurrentUser": "Modifier l'utilisateur actuel",
|
||||
"themeColor": "Couleur du thème",
|
||||
"disableOfficePreviewDescription": "Une liste d'extensions de fichiers séparées par des espaces pour lesquelles le visualisateur OnlyOffice doit être désactivé. (par exemple, '.txt .html').",
|
||||
"disableOfficePreview": "Désactiver la visionneuse d'Office pour certaines extensions de fichiers",
|
||||
"filePreviewOptions": "Options de prévisualisation des fichiers",
|
||||
"listingOptions": "Options d'inscription",
|
||||
"emptyGlobal": "Actuellement, il n'y a pas d'options de configuration globale. Vous pouvez éditer le fichier de configuration yaml pour ajuster les paramètres du système.",
|
||||
"UserManagement": "Gestion des utilisateurs",
|
||||
"tusUploads": "Chargements groupés",
|
||||
"tusUploadsHelp": "File Browser prend en charge les téléchargements de fichiers par morceaux, ce qui permet de créer des téléchargements de fichiers efficaces, fiables, résumables et par morceaux, même sur des réseaux peu fiables.",
|
||||
"tusUploadsChunkSize": "Indique la taille maximale d'une demande (les téléchargements directs seront utilisés pour les téléchargements plus petits). Vous pouvez saisir un nombre entier simple correspondant à un nombre d'octets ou une chaîne de caractères telle que 10 Mo, 1 Go, etc.",
|
||||
"tusUploadsRetryCount": "Nombre de tentatives à effectuer si un bloc ne parvient pas à être téléchargé.",
|
||||
"userHomeBasePath": "Chemin de base pour les répertoires personnels des utilisateurs",
|
||||
"userScopeGenerationPlaceholder": "Le champ d'application sera généré automatiquement",
|
||||
"createUserHomeDirectory": "Créer le répertoire personnel de l'utilisateur",
|
||||
"api": "Clés API",
|
||||
"loginMethodDescription": "méthode de connexion autorisée pour l'utilisateur.",
|
||||
"userNotAdmin": "L'utilisateur n'est pas un administrateur",
|
||||
"enterPassword": "Saisir le mot de passe",
|
||||
"enterPasswordAgain": "Saisir à nouveau le mot de passe",
|
||||
"passwordsDoNotMatch": "Les mots de passe ne correspondent pas"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Aide",
|
||||
@@ -255,7 +292,8 @@
|
||||
"preview": "Prévisualiser",
|
||||
"settings": "Paramètres",
|
||||
"signup": "S'inscrire",
|
||||
"siteSettings": "Paramètres du site"
|
||||
"siteSettings": "Paramètres du site",
|
||||
"sources": "Sources d'information"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Lien copié!"
|
||||
@@ -266,5 +304,51 @@
|
||||
"minutes": "Minutes",
|
||||
"seconds": "Secondes",
|
||||
"unit": "Unité de temps"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Êtes-vous sûre de vouloir avorter ?"
|
||||
},
|
||||
"share": {
|
||||
"notice": "Remarque : toute personne ayant accès au lien (et au mot de passe facultatif) peut accéder aux fichiers partagés. Il n'est pas nécessaire d'être connecté."
|
||||
},
|
||||
"api": {
|
||||
"title": "Clés API :",
|
||||
"keyName": "Nom de la clé API :",
|
||||
"createdAt": "Créé à :",
|
||||
"expiresAt": "Expire le :",
|
||||
"permissions": "Permissions :",
|
||||
"createTitle": "Créer une clé API",
|
||||
"keyNamePlaceholder": "Saisissez un nom de clé API unique :",
|
||||
"tokenDuration": "Durée du jeton :",
|
||||
"durationNumberPlaceholder": "Nombre",
|
||||
"days": "Jours",
|
||||
"months": "Mois",
|
||||
"permissionNote": "Choisissez au moins une autorisation pour la clé. Votre utilisateur doit également disposer de cette autorisation.",
|
||||
"createKeyFailed": "Échec de la création de la clé API.",
|
||||
"createKeySuccess": "Clé API créée avec succès.",
|
||||
"description": "Les clés d'API sont basées sur l'utilisateur qui les a créées. Voir les",
|
||||
"swaggerLinkText": "page swagger",
|
||||
"name": "Nom",
|
||||
"created": "Créée",
|
||||
"expires": "Expiration",
|
||||
"actions": "Actions",
|
||||
"enabled": "Activé",
|
||||
"disabled": "Handicapés"
|
||||
},
|
||||
"index": {
|
||||
"status": "Statut",
|
||||
"assessment": "L'évaluation",
|
||||
"files": "Dossiers",
|
||||
"folders": "Dossiers",
|
||||
"lastScanned": "Dernière numérisation",
|
||||
"quickScan": "Balayage rapide Secondes",
|
||||
"fullScan": "Balayage complet en secondes",
|
||||
"settingsHover": "Paramètres pour l'utilisateur",
|
||||
"logout": "Déconnexion",
|
||||
"toggleClick": "Toggle Single Click",
|
||||
"toggleDark": "Basculer en mode sombre",
|
||||
"toggleSticky": "Basculer le mode collant",
|
||||
"of": "de",
|
||||
"used": "utilisé"
|
||||
}
|
||||
}
|
||||
@@ -132,7 +132,6 @@
|
||||
"downloadMessage": "בחר את הפורמט שברצונך להוריד",
|
||||
"error": "משהו השתבש",
|
||||
"fileInfo": "מידע על הקובץ",
|
||||
"filesSelected": "{count} קבצים נבחרו.",
|
||||
"lastModified": "שונה לאחרונה",
|
||||
"move": "העבר",
|
||||
"moveMessage": "בחר מיקום חדש לקובץ / תקייה:",
|
||||
@@ -267,5 +266,9 @@
|
||||
"minutes": "דקות",
|
||||
"seconds": "שניות",
|
||||
"unit": "יחידת זמן"
|
||||
}
|
||||
},
|
||||
"upload": {},
|
||||
"share": {},
|
||||
"api": {},
|
||||
"index": {}
|
||||
}
|
||||
@@ -35,7 +35,9 @@
|
||||
"toggleSidebar": "Oldalsáv átváltása",
|
||||
"update": "Frissítés",
|
||||
"upload": "Feltöltés",
|
||||
"openFile": "Fájl megnyitása"
|
||||
"openFile": "Fájl megnyitása",
|
||||
"copyDownloadLinkToClipboard": "Letöltési link másolása a vágólapra",
|
||||
"continue": "Folytatás"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Fájl letöltése",
|
||||
@@ -116,7 +118,8 @@
|
||||
"submit": "Belépés",
|
||||
"username": "Felhasználói név",
|
||||
"usernameTaken": "A felhasználói név már foglalt",
|
||||
"wrongCredentials": "Hibás hitelesítő adatok"
|
||||
"wrongCredentials": "Hibás hitelesítő adatok",
|
||||
"or": "VAGY"
|
||||
},
|
||||
"permanent": "Állandó",
|
||||
"prompts": {
|
||||
@@ -132,7 +135,6 @@
|
||||
"downloadMessage": "Válassza ki a letöltés formátumát.",
|
||||
"error": "Valami rosszul sült el",
|
||||
"fileInfo": "Fájlinformáció",
|
||||
"filesSelected": "{count} fájl van kijelölve.",
|
||||
"lastModified": "Utolsó módosítás",
|
||||
"move": "Mozgatás",
|
||||
"moveMessage": "Válasszon új helyet a fájl(ok)nak/mappá(k)nak:",
|
||||
@@ -154,7 +156,11 @@
|
||||
"upload": "Feltöltés",
|
||||
"uploadFiles": "{files} fájl feltöltése…",
|
||||
"uploadMessage": "Válasszon egy feltöltési módot.",
|
||||
"optionalPassword": "Választható jelszó"
|
||||
"optionalPassword": "Választható jelszó",
|
||||
"deleteUserMessage": "Biztos, hogy törölni szeretné ezt a felhasználót?",
|
||||
"filesSelected": "kiválasztott fájlok",
|
||||
"typeName": "Típus:",
|
||||
"selected": "kiválasztott"
|
||||
},
|
||||
"search": {
|
||||
"images": "Képek",
|
||||
@@ -164,7 +170,12 @@
|
||||
"search": "Keresés…",
|
||||
"typeToSearch": "Keresés indítása beírással…",
|
||||
"types": "Típusok",
|
||||
"video": "Videó"
|
||||
"video": "Videó",
|
||||
"path": "Útvonal:",
|
||||
"smallerThan": "Kisebb, mint:",
|
||||
"largerThan": "Nagyobb, mint:",
|
||||
"helpText1": "A keresés minden egyes beírt karakterre történik (minimum 3 karakteres keresőkifejezés).",
|
||||
"helpText2": "Az index: A keresés az indexet használja, amely automatikusan frissül a beállított időközönként (alapértelmezett: 5 perc). A program indulásakor végzett keresés hiányos eredményeket eredményezhet."
|
||||
},
|
||||
"settings": {
|
||||
"admin": "Admin",
|
||||
@@ -213,7 +224,10 @@
|
||||
"execute": "Parancsok futtatása",
|
||||
"modify": "Fájlok szerkesztése",
|
||||
"rename": "Fájlok és mappák átnevezése vagy mozgatása",
|
||||
"share": "Fájlok megosztása"
|
||||
"share": "Fájlok megosztása",
|
||||
"admin": "Adminisztrátor",
|
||||
"api": "Hosszú élettartamú API-kulcsok létrehozása és kezelése",
|
||||
"realtime": "Valós idejű kapcsolatok és frissítések engedélyezése"
|
||||
},
|
||||
"permissions-name": "Jogosultságok",
|
||||
"permissionsHelp": "A felhasználót beállíthatja rendszergazdának, vagy egyénileg is kiválaszthatja a jogosultságokat. Ha a \"Rendszergazda\" lehetőséget választja, az összes többi opció automatikusan be lesz jelölve. A felhasználók kezelése továbbra is a rendszergazda kiváltsága marad.\n",
|
||||
@@ -243,7 +257,29 @@
|
||||
"userManagement": "Felhasználókezelés",
|
||||
"userUpdated": "Felhasználó frissítve!",
|
||||
"username": "Felhasználói név",
|
||||
"users": "Felhasználók"
|
||||
"users": "Felhasználók",
|
||||
"loginMethod": "Bejelentkezési módszer",
|
||||
"modifyOtherUser": "Felhasználó módosítása:",
|
||||
"modifyCurrentUser": "Jelenlegi felhasználó módosítása",
|
||||
"themeColor": "Téma színe",
|
||||
"disableOfficePreviewDescription": "Azon fájlkiterjesztések szóközzel elválasztott listája, amelyek esetében az OnlyOffice megjelenítőjét le kell tiltani. (pl. '.txt .html').",
|
||||
"disableOfficePreview": "Letiltja a onlyoffice viewer-t bizonyos fájlkiterjesztések esetén",
|
||||
"filePreviewOptions": "Fájl előnézeti beállítások",
|
||||
"listingOptions": "Listázási lehetőségek",
|
||||
"emptyGlobal": "Jelenleg nincsenek globális konfigurációs beállítások, A rendszerbeállítások módosításához szerkesztheti a konfigurációs yaml-t.",
|
||||
"scopes": "Az engedélyezett források és az azokon belüli felhasználói hatókörök meghatározása",
|
||||
"UserManagement": "Felhasználó kezelése",
|
||||
"tusUploads": "Csomagolt feltöltések",
|
||||
"tusUploadsHelp": "A File Browser támogatja a darabolt fájlfeltöltést, lehetővé téve a hatékony, megbízható, folytatható és darabolt fájlfeltöltést még megbízhatatlan hálózatokon is.",
|
||||
"tusUploadsChunkSize": "A kérés maximális méretét jelzi (a kisebb feltöltéseknél a közvetlen feltöltést használják). Beadhat egy egyszerű egész számot, amely a bájtos bemenetet jelöli, vagy egy karakterláncot, például 10MB, 1GB stb.",
|
||||
"tusUploadsRetryCount": "Az újbóli próbálkozások száma, ha egy darabkát nem sikerül feltölteni.",
|
||||
"disableUsedDiskPercentage": "A használt lemez százalékos grafikonjának kikapcsolása",
|
||||
"api": "API kulcsok",
|
||||
"loginMethodDescription": "engedélyezett bejelentkezési módszer a felhasználó számára.",
|
||||
"userNotAdmin": "A felhasználó nem rendszergazda",
|
||||
"enterPassword": "Jelszó megadása",
|
||||
"enterPasswordAgain": "Adja meg újra a jelszót",
|
||||
"passwordsDoNotMatch": "A jelszavak nem egyeznek"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Súgó",
|
||||
@@ -256,7 +292,8 @@
|
||||
"preview": "Előnézet",
|
||||
"settings": "Beállítások",
|
||||
"signup": "Regisztráció",
|
||||
"siteSettings": "Oldalbeállítások"
|
||||
"siteSettings": "Oldalbeállítások",
|
||||
"sources": "Források"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Link másolva!"
|
||||
@@ -267,5 +304,51 @@
|
||||
"minutes": "Perc",
|
||||
"seconds": "Másodperc",
|
||||
"unit": "Időegység"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Biztos, hogy meg akarja szakítani?"
|
||||
},
|
||||
"share": {
|
||||
"notice": "Megjegyzés: bárki, aki hozzáfér a linkhez (és opcionális jelszóval), hozzáférhet a megosztott fájlokhoz. Nem szükséges bejelentkezni."
|
||||
},
|
||||
"api": {
|
||||
"title": "API-kulcsok:",
|
||||
"keyName": "API-kulcs neve:",
|
||||
"createdAt": "Létrehozva:",
|
||||
"expiresAt": "Lejár:",
|
||||
"permissions": "Engedélyek:",
|
||||
"createTitle": "API kulcs létrehozása",
|
||||
"keyNamePlaceholder": "Adjon meg egy egyedi API-kulcs nevet:",
|
||||
"tokenDuration": "Token időtartama:",
|
||||
"durationNumberPlaceholder": "Szám",
|
||||
"days": "Napok",
|
||||
"months": "Hónapok",
|
||||
"permissionNote": "Válasszon legalább egy engedélyt a kulcshoz. A felhasználónak is rendelkeznie kell az adott jogosultsággal.",
|
||||
"createKeyFailed": "Sikertelen API-kulcs létrehozása.",
|
||||
"createKeySuccess": "Sikeresen létrehozott API-kulcs.",
|
||||
"description": "Az API-kulcsok a létrehozó felhasználó alapján készülnek. Lásd",
|
||||
"swaggerLinkText": "swagger oldal",
|
||||
"name": "Név",
|
||||
"created": "Létrehozva",
|
||||
"expires": "Lejárat:",
|
||||
"actions": "Tevékenységek",
|
||||
"enabled": "Engedélyezve",
|
||||
"disabled": "Mozgáskorlátozottak"
|
||||
},
|
||||
"index": {
|
||||
"status": "Állapot",
|
||||
"assessment": "Értékelés",
|
||||
"files": "Fájlok",
|
||||
"folders": "Mappák",
|
||||
"lastScanned": "Utoljára beolvasott",
|
||||
"quickScan": "Gyors beolvasás másodpercek",
|
||||
"fullScan": "Teljes letapogatás másodpercek",
|
||||
"settingsHover": "Felhasználói beállítások",
|
||||
"logout": "Kijelentkezés",
|
||||
"toggleClick": "Egyetlen kattintás kapcsolása",
|
||||
"toggleDark": "Sötét üzemmód átkapcsolása",
|
||||
"toggleSticky": "Ragadós mód átkapcsolása",
|
||||
"of": "a",
|
||||
"used": "használt"
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,7 @@
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "",
|
||||
"tr" : "Türkçe",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
@@ -125,7 +125,6 @@
|
||||
"downloadMessage": "Veldu skrárgerð sem þú vilt sækja.",
|
||||
"error": "Eitthvað fór úrskeiðis",
|
||||
"fileInfo": "Upplýsingar um gögn",
|
||||
"filesSelected": "{count} skjöl valin.",
|
||||
"lastModified": "Seinast breytt",
|
||||
"move": "Færa",
|
||||
"moveMessage": "Velja nýtt hús fyrir skjöl/möppur:",
|
||||
@@ -145,7 +144,8 @@
|
||||
"show": "Sýna",
|
||||
"size": "Stærð",
|
||||
"upload": "",
|
||||
"uploadMessage": ""
|
||||
"uploadMessage": "",
|
||||
"deleteMessageShare": "Are you sure you want to delete this share: {path} ?"
|
||||
},
|
||||
"search": {
|
||||
"images": "Myndir",
|
||||
@@ -254,5 +254,9 @@
|
||||
"minutes": "Mínútur",
|
||||
"seconds": "Sekúndur",
|
||||
"unit": "Tímastilling"
|
||||
}
|
||||
},
|
||||
"upload": {},
|
||||
"share": {},
|
||||
"api": {},
|
||||
"index": {}
|
||||
}
|
||||
+107
-11
@@ -31,7 +31,13 @@
|
||||
"switchView": "Cambia vista",
|
||||
"toggleSidebar": "Mostra/nascondi la barra laterale",
|
||||
"update": "Aggiorna",
|
||||
"upload": "Carica"
|
||||
"upload": "Carica",
|
||||
"copyDownloadLinkToClipboard": "Copiare il link di download negli appunti",
|
||||
"file": "File",
|
||||
"folder": "Cartella",
|
||||
"submit": "Invia",
|
||||
"openFile": "Aprire il file",
|
||||
"continue": "Continua"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Scarica file",
|
||||
@@ -41,7 +47,8 @@
|
||||
"errors": {
|
||||
"forbidden": "Non hai i permessi per accedere a questo file.",
|
||||
"internal": "Qualcosa è andato veramente male.",
|
||||
"notFound": "Questo percorso non può essere raggiunto."
|
||||
"notFound": "Questo percorso non può essere raggiunto.",
|
||||
"connection": "Il server non è raggiungibile."
|
||||
},
|
||||
"files": {
|
||||
"body": "Contenuto",
|
||||
@@ -59,7 +66,8 @@
|
||||
"size": "Dimensione",
|
||||
"sortByLastModified": "Ordina per ultima modifica",
|
||||
"sortByName": "Ordina per nome",
|
||||
"sortBySize": "Ordina per dimensione"
|
||||
"sortBySize": "Ordina per dimensione",
|
||||
"noPreview": "L'anteprima non è disponibile per questo file."
|
||||
},
|
||||
"help": {
|
||||
"click": "seleziona un file o una cartella",
|
||||
@@ -95,7 +103,7 @@
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "",
|
||||
"tr" : "Türkçe",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
@@ -110,7 +118,8 @@
|
||||
"submit": "Entra",
|
||||
"username": "Nome utente",
|
||||
"usernameTaken": "Username già usato",
|
||||
"wrongCredentials": "Credenziali errate"
|
||||
"wrongCredentials": "Credenziali errate",
|
||||
"or": "O"
|
||||
},
|
||||
"permanent": "Permanente",
|
||||
"prompts": {
|
||||
@@ -125,7 +134,6 @@
|
||||
"downloadMessage": "Seleziona il formato che vuoi scaricare.",
|
||||
"error": "Qualcosa è andato per il verso storto",
|
||||
"fileInfo": "Informazioni sul file",
|
||||
"filesSelected": "{count} file selezionati.",
|
||||
"lastModified": "Ultima modifica",
|
||||
"move": "Sposta",
|
||||
"moveMessage": "Seleziona la nuova posizione per i tuoi file e/o cartella/e:",
|
||||
@@ -145,7 +153,14 @@
|
||||
"show": "Mostra",
|
||||
"size": "Dimensione",
|
||||
"upload": "Carica",
|
||||
"uploadMessage": "Seleziona un'opzione per il caricamento."
|
||||
"uploadMessage": "Seleziona un'opzione per il caricamento.",
|
||||
"deleteMessageShare": "Are you sure you want to delete this share: {path} ?",
|
||||
"deleteUserMessage": "Siete sicuri di voler eliminare questo utente?",
|
||||
"filesSelected": "file selezionati",
|
||||
"uploadFiles": "Uploading {files} files...",
|
||||
"optionalPassword": "Password opzionale",
|
||||
"typeName": "Tipo:",
|
||||
"selected": "selezionato"
|
||||
},
|
||||
"search": {
|
||||
"images": "Immagini",
|
||||
@@ -155,7 +170,12 @@
|
||||
"search": "Cerca...",
|
||||
"typeToSearch": "Scrivi per cercare...",
|
||||
"types": "Tipi",
|
||||
"video": "Video"
|
||||
"video": "Video",
|
||||
"path": "Percorso:",
|
||||
"smallerThan": "Più piccolo di:",
|
||||
"largerThan": "Più grande di:",
|
||||
"helpText1": "La ricerca avviene per ogni carattere digitato (minimo 3 caratteri per i termini di ricerca).",
|
||||
"helpText2": "L'indice: La ricerca utilizza l'indice che viene aggiornato automaticamente all'intervallo configurato (default: 5 minuti). La ricerca quando il programma è appena stato avviato può dare risultati incompleti."
|
||||
},
|
||||
"settings": {
|
||||
"admin": "Admin",
|
||||
@@ -202,7 +222,10 @@
|
||||
"execute": "Eseguire comandi",
|
||||
"modify": "Modificare file",
|
||||
"rename": "Rinominare o spostare file e cartelle",
|
||||
"share": "Condividere file"
|
||||
"share": "Condividere file",
|
||||
"admin": "Amministratore",
|
||||
"api": "Creare e gestire chiavi API a lunga durata",
|
||||
"realtime": "Consentire connessioni e aggiornamenti in tempo reale"
|
||||
},
|
||||
"permissions-name": "Permessi",
|
||||
"permissionsHelp": "È possibile impostare l'utente come amministratore o scegliere i permessi singolarmente. Se si seleziona \"Amministratore\", tutte le altre opzioni saranno automaticamente assegnate. La gestione degli utenti rimane un privilegio di un amministratore.\n",
|
||||
@@ -230,7 +253,33 @@
|
||||
"userManagement": "Gestione degli utenti",
|
||||
"userUpdated": "Utente aggiornato!",
|
||||
"username": "Nome utente",
|
||||
"users": "Utenti"
|
||||
"users": "Utenti",
|
||||
"loginMethod": "Metodo di accesso",
|
||||
"modifyOtherUser": "Modificare l'utente:",
|
||||
"modifyCurrentUser": "Modificare l'utente corrente",
|
||||
"themeColor": "Colore del tema",
|
||||
"disableOfficePreviewDescription": "Un elenco separato da spazi di estensioni di file per cui disabilitare il visualizzatore di OnlyOffice. (ad esempio, '.txt .html').",
|
||||
"disableOfficePreview": "Disabilitare il visualizzatore onlyoffice per alcune estensioni di file",
|
||||
"filePreviewOptions": "Opzioni di anteprima dei file",
|
||||
"listingOptions": "Opzioni di quotazione",
|
||||
"emptyGlobal": "Attualmente non ci sono opzioni di configurazione globale, ma è possibile modificare lo yaml di configurazione per regolare le impostazioni del sistema.",
|
||||
"scopes": "Definire le fonti consentite e l'ambito dell'utente all'interno di esse",
|
||||
"UserManagement": "Gestione degli utenti",
|
||||
"tusUploads": "Caricamenti spezzettati",
|
||||
"tusUploadsHelp": "File Browser supporta il caricamento di file a pezzetti, consentendo la creazione di upload di file efficienti, affidabili, riprendibili e a pezzetti anche su reti inaffidabili.",
|
||||
"tusUploadsChunkSize": "Indica la dimensione massima di una richiesta (i caricamenti diretti saranno utilizzati per i caricamenti più piccoli). È possibile immettere un numero intero semplice che indica un input in byte o una stringa come 10MB, 1GB ecc.",
|
||||
"tusUploadsRetryCount": "Numero di tentativi da eseguire se un chunk non riesce a essere caricato.",
|
||||
"userHomeBasePath": "Percorso di base per le directory home degli utenti",
|
||||
"userScopeGenerationPlaceholder": "L'ambito sarà generato automaticamente",
|
||||
"createUserHomeDirectory": "Creare la directory home dell'utente",
|
||||
"api": "Chiavi API",
|
||||
"setDateFormat": "Impostare il formato esatto della data",
|
||||
"shareDeleted": "Condividi cancellato!",
|
||||
"loginMethodDescription": "metodo di accesso consentito per l'utente.",
|
||||
"userNotAdmin": "L'utente non è un amministratore",
|
||||
"enterPassword": "Inserire la password",
|
||||
"enterPasswordAgain": "Immettere nuovamente la password",
|
||||
"passwordsDoNotMatch": "Le password non corrispondono"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Aiuto",
|
||||
@@ -243,7 +292,8 @@
|
||||
"preview": "Anteprima",
|
||||
"settings": "Impostazioni",
|
||||
"signup": "Registrati",
|
||||
"siteSettings": "Impostazioni del sito"
|
||||
"siteSettings": "Impostazioni del sito",
|
||||
"sources": "Fonti"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Link copiato!"
|
||||
@@ -254,5 +304,51 @@
|
||||
"minutes": "Minuti",
|
||||
"seconds": "Secondi",
|
||||
"unit": "Unità di tempo"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Sei sicura di voler abortire?"
|
||||
},
|
||||
"share": {
|
||||
"notice": "Nota: chiunque abbia accesso al link (e alla password opzionale) può accedere ai file condivisi. Non è necessario effettuare il login."
|
||||
},
|
||||
"api": {
|
||||
"title": "Chiavi API:",
|
||||
"keyName": "Nome della chiave API:",
|
||||
"createdAt": "Creato a:",
|
||||
"expiresAt": "Scade a:",
|
||||
"permissions": "Permessi:",
|
||||
"createTitle": "Creare la chiave API",
|
||||
"keyNamePlaceholder": "Inserire un nome univoco per la chiave API:",
|
||||
"tokenDuration": "Durata del gettone:",
|
||||
"durationNumberPlaceholder": "Numero",
|
||||
"days": "Giorni",
|
||||
"months": "Mesi",
|
||||
"permissionNote": "Scegliere almeno un'autorizzazione per la chiave. Anche l'utente deve avere l'autorizzazione.",
|
||||
"createKeyFailed": "Impossibile creare la chiave API.",
|
||||
"createKeySuccess": "Chiave API creata con successo.",
|
||||
"description": "Le chiavi API si basano sull'utente che le crea. Vedere",
|
||||
"swaggerLinkText": "pagina swagger",
|
||||
"name": "Nome",
|
||||
"created": "Creato",
|
||||
"expires": "Scadenza",
|
||||
"actions": "Azioni",
|
||||
"enabled": "Abilitato",
|
||||
"disabled": "Disabili"
|
||||
},
|
||||
"index": {
|
||||
"status": "Stato",
|
||||
"assessment": "Valutazione",
|
||||
"files": "File",
|
||||
"folders": "Cartelle",
|
||||
"lastScanned": "Ultima scansione",
|
||||
"quickScan": "Scansione rapida Secondi",
|
||||
"fullScan": "Secondi di scansione completa",
|
||||
"settingsHover": "Impostazioni per l'utente",
|
||||
"logout": "Disconnessione",
|
||||
"toggleClick": "Alterna il clic singolo",
|
||||
"toggleDark": "Alterna la modalità scura",
|
||||
"toggleSticky": "Alterna la modalità appiccicosa",
|
||||
"of": "di",
|
||||
"used": "usato"
|
||||
}
|
||||
}
|
||||
+116
-20
@@ -31,17 +31,24 @@
|
||||
"switchView": "表示を切り替わる",
|
||||
"toggleSidebar": "サイドバーを表示する",
|
||||
"update": "更新",
|
||||
"upload": "アップロード"
|
||||
"upload": "アップロード",
|
||||
"copyDownloadLinkToClipboard": "ダウンロードリンクをクリップボードにコピーする",
|
||||
"file": "ファイル",
|
||||
"folder": "フォルダ",
|
||||
"submit": "投稿する",
|
||||
"openFile": "ファイルを開く",
|
||||
"continue": "続ける"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Download File",
|
||||
"downloadFolder": "Download Folder",
|
||||
"downloadSelected": ""
|
||||
"downloadSelected": "ダウンロード"
|
||||
},
|
||||
"errors": {
|
||||
"forbidden": "You don't have permissions to access this.",
|
||||
"internal": "内部エラーが発生しました。",
|
||||
"notFound": "リソースが見つからなりませんでした。"
|
||||
"notFound": "リソースが見つからなりませんでした。",
|
||||
"connection": "サーバーにアクセスできません。"
|
||||
},
|
||||
"files": {
|
||||
"body": "本文",
|
||||
@@ -59,7 +66,8 @@
|
||||
"size": "サイズ",
|
||||
"sortByLastModified": "最終変更日付によるソート",
|
||||
"sortByName": "名前によるソート",
|
||||
"sortBySize": "サイズによるソート"
|
||||
"sortBySize": "サイズによるソート",
|
||||
"noPreview": "このファイルではプレビューは利用できません。"
|
||||
},
|
||||
"help": {
|
||||
"click": "ファイルやディレクトリを選択",
|
||||
@@ -95,7 +103,7 @@
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "",
|
||||
"tr" : "Türkçe",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
@@ -110,7 +118,8 @@
|
||||
"submit": "ログイン",
|
||||
"username": "ユーザ名",
|
||||
"usernameTaken": "Username already taken",
|
||||
"wrongCredentials": "ユーザ名またはパスワードが間違っています。"
|
||||
"wrongCredentials": "ユーザ名またはパスワードが間違っています。",
|
||||
"or": "または"
|
||||
},
|
||||
"permanent": "永久",
|
||||
"prompts": {
|
||||
@@ -125,7 +134,6 @@
|
||||
"downloadMessage": "圧縮形式を選択してください。",
|
||||
"error": "あるエラーが発生しました。",
|
||||
"fileInfo": "ファイル情報",
|
||||
"filesSelected": "{count} つのファイルは選択されました。",
|
||||
"lastModified": "最終変更",
|
||||
"move": "移動",
|
||||
"moveMessage": "移動の目標ディレクトリを選択してください:",
|
||||
@@ -144,8 +152,15 @@
|
||||
"scheduleMessage": "このポストの発表日付をスケジュールしてください。",
|
||||
"show": "表示",
|
||||
"size": "サイズ",
|
||||
"upload": "",
|
||||
"uploadMessage": ""
|
||||
"upload": "アップロード",
|
||||
"uploadMessage": "アップロードするオプションを選択します。",
|
||||
"deleteMessageShare": "Are you sure you want to delete this share: {path} ?",
|
||||
"deleteUserMessage": "本当にこのユーザーを削除しますか?",
|
||||
"filesSelected": "選択されたファイル",
|
||||
"uploadFiles": "Uploading {files} files...",
|
||||
"optionalPassword": "任意のパスワード",
|
||||
"typeName": "タイプ",
|
||||
"selected": "選ばれた"
|
||||
},
|
||||
"search": {
|
||||
"images": "画像",
|
||||
@@ -155,7 +170,12 @@
|
||||
"search": "検索...",
|
||||
"typeToSearch": "Type to search...",
|
||||
"types": "種類",
|
||||
"video": "ビデオ"
|
||||
"video": "ビデオ",
|
||||
"path": "パス",
|
||||
"smallerThan": "より小さい:",
|
||||
"largerThan": "より大きい:",
|
||||
"helpText1": "検索は入力した文字ごとに行われます(検索語は最低3文字)。",
|
||||
"helpText2": "インデックス:検索は、設定された間隔(デフォルト:5分)で自動的に更新されるインデックスを利用します。プログラムが開始したばかりの時に検索すると、不完全な結果になることがあります。"
|
||||
},
|
||||
"settings": {
|
||||
"admin": "管理者",
|
||||
@@ -194,7 +214,7 @@
|
||||
"newUser": "新しいユーザー",
|
||||
"password": "パスワード",
|
||||
"passwordUpdated": "パスワードは更新されました!",
|
||||
"path": "",
|
||||
"path": "パス",
|
||||
"permissions": {
|
||||
"create": "Create files and directories",
|
||||
"delete": "Delete files and directories",
|
||||
@@ -202,7 +222,10 @@
|
||||
"execute": "Execute commands",
|
||||
"modify": "Edit files",
|
||||
"rename": "Rename or move files and directories",
|
||||
"share": "Share files"
|
||||
"share": "Share files",
|
||||
"admin": "管理者",
|
||||
"api": "長寿命のAPIキーの作成と管理",
|
||||
"realtime": "リアルタイムの接続と更新を可能にする"
|
||||
},
|
||||
"permissions-name": "権限",
|
||||
"permissionsHelp": "あなたはユーザーを管理者に設定し、または権限を個々に設定しできます。\"管理者\"を選択する場合、その他のすべての選択肢は自動的に設定されます。ユーザーの管理は管理者の権限として保留されました。",
|
||||
@@ -213,13 +236,13 @@
|
||||
"rulesHelp": "ここに、あなたはこのユーザーの許可または拒否規則を設定できます。ブロックされたファイルはリストに表示されません、それではアクセスも制限されます。正規表現(regex)のサポートと範囲に相対のパスが提供されています。",
|
||||
"scope": "範囲",
|
||||
"settingsUpdated": "設定は更新されました!",
|
||||
"shareDuration": "",
|
||||
"shareManagement": "",
|
||||
"singleClick": "",
|
||||
"shareDuration": "シェア期間",
|
||||
"shareManagement": "シェア・マネジメント",
|
||||
"singleClick": "シングルクリックでファイルやディレクトリを開く",
|
||||
"themes": {
|
||||
"dark": "",
|
||||
"light": "",
|
||||
"title": ""
|
||||
"dark": "暗い",
|
||||
"light": "ライト",
|
||||
"title": "テーマ"
|
||||
},
|
||||
"user": "ユーザー",
|
||||
"userCommands": "ユーザーのコマンド",
|
||||
@@ -230,7 +253,33 @@
|
||||
"userManagement": "ユーザー管理",
|
||||
"userUpdated": "ユーザーは更新されました!",
|
||||
"username": "ユーザー名",
|
||||
"users": "ユーザー"
|
||||
"users": "ユーザー",
|
||||
"loginMethod": "ログイン方法",
|
||||
"modifyOtherUser": "ユーザーを変更する:",
|
||||
"modifyCurrentUser": "現在のユーザーを変更する",
|
||||
"themeColor": "テーマカラー",
|
||||
"disableOfficePreviewDescription": "OnlyOffice ビューアを無効にするファイル拡張子をスペース区切りで指定します。(例: '.txt .html')。",
|
||||
"disableOfficePreview": "特定のファイル拡張子でonlyofficeビューアを無効にする",
|
||||
"filePreviewOptions": "ファイルプレビューオプション",
|
||||
"listingOptions": "リストオプション",
|
||||
"emptyGlobal": "現在のところ、グローバルな設定オプションはありませんが、コンフィギュレーションyamlを編集してシステム設定を調整することができます。",
|
||||
"scopes": "許可されるソースとその中のユーザースコープを定義する",
|
||||
"UserManagement": "ユーザー管理",
|
||||
"tusUploads": "チャンクアップロード",
|
||||
"tusUploadsHelp": "File Browserは、チャンクされたファイルアップロードをサポートしており、信頼性の低いネットワーク上でも、効率的で信頼性の高い、再開可能なチャンクされたファイルアップロードを作成することができます。",
|
||||
"tusUploadsChunkSize": "リクエストの最大サイズを示します(直接アップロードはより小さいアップロードに使用されます)。バイト数を示す整数か、10MB、1GBなどの文字列を入力します。",
|
||||
"tusUploadsRetryCount": "チャンクのアップロードに失敗した場合の再試行回数。",
|
||||
"userHomeBasePath": "ユーザーホームディレクトリのベースパス",
|
||||
"userScopeGenerationPlaceholder": "スコープは自動生成されます。",
|
||||
"createUserHomeDirectory": "ユーザーホームディレクトリの作成",
|
||||
"api": "APIキー",
|
||||
"setDateFormat": "正確な日付書式を設定する",
|
||||
"shareDeleted": "削除されたシェア",
|
||||
"loginMethodDescription": "ユーザーに許可されたログイン方法。",
|
||||
"userNotAdmin": "ユーザーが管理者でない",
|
||||
"enterPassword": "パスワードを入力",
|
||||
"enterPasswordAgain": "もう一度パスワードを入力する",
|
||||
"passwordsDoNotMatch": "パスワードが一致しない"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "ヘルプ",
|
||||
@@ -243,7 +292,8 @@
|
||||
"preview": "プレビュー",
|
||||
"settings": "設定",
|
||||
"signup": "Signup",
|
||||
"siteSettings": "サイト設定"
|
||||
"siteSettings": "サイト設定",
|
||||
"sources": "情報源"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "リンクがコピーされました!"
|
||||
@@ -254,5 +304,51 @@
|
||||
"minutes": "分",
|
||||
"seconds": "秒",
|
||||
"unit": "時間単位"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "本当に中絶したいのか?"
|
||||
},
|
||||
"share": {
|
||||
"notice": "注:リンク(およびオプションのパスワード)にアクセスできる人なら、誰でも共有ファイルにアクセスできます。ログインする必要はありません。"
|
||||
},
|
||||
"api": {
|
||||
"title": "APIキー:",
|
||||
"keyName": "APIキー名",
|
||||
"createdAt": "で作成された:",
|
||||
"expiresAt": "有効期限",
|
||||
"permissions": "許可:",
|
||||
"createTitle": "APIキーの作成",
|
||||
"keyNamePlaceholder": "一意のAPIキー名を入力します:",
|
||||
"tokenDuration": "トークンの有効期間:",
|
||||
"durationNumberPlaceholder": "番号",
|
||||
"days": "日数",
|
||||
"months": "ヶ月",
|
||||
"permissionNote": "キーに対して少なくとも1つのパーミッションを選択してください。ユーザーもそのパーミッションを持っている必要があります。",
|
||||
"createKeyFailed": "APIキーの作成に失敗しました。",
|
||||
"createKeySuccess": "APIキーが正常に作成されました。",
|
||||
"description": "APIキーは、それを作成したユーザーに基づいています。参照",
|
||||
"swaggerLinkText": "スワッガーページ",
|
||||
"name": "名称",
|
||||
"created": "作成",
|
||||
"expires": "期限切れ",
|
||||
"actions": "行動",
|
||||
"enabled": "有効",
|
||||
"disabled": "無効"
|
||||
},
|
||||
"index": {
|
||||
"status": "ステータス",
|
||||
"assessment": "評価",
|
||||
"files": "ファイル",
|
||||
"folders": "フォルダ",
|
||||
"lastScanned": "最終スキャン",
|
||||
"quickScan": "クイックスキャン秒数",
|
||||
"fullScan": "フルスキャン秒数",
|
||||
"settingsHover": "ユーザー設定",
|
||||
"logout": "ログアウト",
|
||||
"toggleClick": "トグル・シングルクリック",
|
||||
"toggleDark": "ダークモードの切り替え",
|
||||
"toggleSticky": "スティッキーモードの切り替え",
|
||||
"of": "の",
|
||||
"used": "中古"
|
||||
}
|
||||
}
|
||||
+116
-20
@@ -31,17 +31,24 @@
|
||||
"switchView": "보기 전환",
|
||||
"toggleSidebar": "사이드바 전환",
|
||||
"update": "업데이트",
|
||||
"upload": "업로드"
|
||||
"upload": "업로드",
|
||||
"copyDownloadLinkToClipboard": "다운로드 링크를 클립보드에 복사",
|
||||
"file": "파일",
|
||||
"folder": "폴더",
|
||||
"submit": "제출하기",
|
||||
"openFile": "파일 열기",
|
||||
"continue": "계속하기"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "파일 다운로드",
|
||||
"downloadFolder": "폴더 다운로드",
|
||||
"downloadSelected": ""
|
||||
"downloadSelected": "선택된 다운로드"
|
||||
},
|
||||
"errors": {
|
||||
"forbidden": "접근 권한이 없습니다.",
|
||||
"internal": "오류가 발생하였습니다.",
|
||||
"notFound": "해당 경로를 찾을 수 없습니다."
|
||||
"notFound": "해당 경로를 찾을 수 없습니다.",
|
||||
"connection": "서버에 연결할 수 없습니다."
|
||||
},
|
||||
"files": {
|
||||
"body": "본문",
|
||||
@@ -59,7 +66,8 @@
|
||||
"size": "크기",
|
||||
"sortByLastModified": "수정시간순 정렬",
|
||||
"sortByName": "이름순",
|
||||
"sortBySize": "크기순"
|
||||
"sortBySize": "크기순",
|
||||
"noPreview": "이 파일에는 미리 보기를 사용할 수 없습니다."
|
||||
},
|
||||
"help": {
|
||||
"click": "파일이나 디렉토리를 선택해주세요.",
|
||||
@@ -95,7 +103,7 @@
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "",
|
||||
"tr" : "Türkçe",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
@@ -110,7 +118,8 @@
|
||||
"submit": "로그인",
|
||||
"username": "사용자 이름",
|
||||
"usernameTaken": "사용자 이름이 존재합니다",
|
||||
"wrongCredentials": "사용자 이름 또는 비밀번호를 확인하십시오"
|
||||
"wrongCredentials": "사용자 이름 또는 비밀번호를 확인하십시오",
|
||||
"or": "또는"
|
||||
},
|
||||
"permanent": "영구",
|
||||
"prompts": {
|
||||
@@ -125,7 +134,6 @@
|
||||
"downloadMessage": "다운로드 포맷 설정.",
|
||||
"error": "에러 발생!",
|
||||
"fileInfo": "파일 정보",
|
||||
"filesSelected": "{count} 개의 파일이 선택되었습니다.",
|
||||
"lastModified": "최종 수정",
|
||||
"move": "이동",
|
||||
"moveMessage": "이동할 화일 또는 디렉토리를 선택하세요:",
|
||||
@@ -144,8 +152,15 @@
|
||||
"scheduleMessage": "이 글을 공개할 시간을 알려주세요.",
|
||||
"show": "보기",
|
||||
"size": "크기",
|
||||
"upload": "",
|
||||
"uploadMessage": ""
|
||||
"upload": "업로드",
|
||||
"uploadMessage": "업로드할 옵션을 선택합니다.",
|
||||
"deleteMessageShare": "Are you sure you want to delete this share: {path} ?",
|
||||
"deleteUserMessage": "이 사용자를 삭제하시겠습니까?",
|
||||
"filesSelected": "선택한 파일",
|
||||
"uploadFiles": "Uploading {files} files...",
|
||||
"optionalPassword": "선택적 비밀번호",
|
||||
"typeName": "유형:",
|
||||
"selected": "선택"
|
||||
},
|
||||
"search": {
|
||||
"images": "이미지",
|
||||
@@ -155,7 +170,12 @@
|
||||
"search": "검색...",
|
||||
"typeToSearch": "검색어 입력...",
|
||||
"types": "Types",
|
||||
"video": "비디오"
|
||||
"video": "비디오",
|
||||
"path": "경로:",
|
||||
"smallerThan": "보다 작습니다:",
|
||||
"largerThan": "보다 큽니다:",
|
||||
"helpText1": "검색은 입력하는 각 문자(검색어의 경우 최소 3자)에 대해 이루어집니다.",
|
||||
"helpText2": "색인: 검색은 설정된 간격(기본값: 5분)에 따라 자동으로 업데이트되는 색인을 활용합니다. 프로그램이 막 시작되었을 때 검색하면 불완전한 결과가 나올 수 있습니다."
|
||||
},
|
||||
"settings": {
|
||||
"admin": "관리자",
|
||||
@@ -194,7 +214,7 @@
|
||||
"newUser": "새로운 사용자",
|
||||
"password": "비밀번호",
|
||||
"passwordUpdated": "비밀번호 수정 완료!",
|
||||
"path": "",
|
||||
"path": "경로",
|
||||
"permissions": {
|
||||
"create": "파일이나 디렉토리 생성하기",
|
||||
"delete": "화일이나 디렉토리 삭제하기",
|
||||
@@ -202,7 +222,10 @@
|
||||
"execute": "명령 실행",
|
||||
"modify": "파일 편집",
|
||||
"rename": "파일 이름 변경 또는 디렉토리 이동",
|
||||
"share": "파일 공유하기"
|
||||
"share": "파일 공유하기",
|
||||
"admin": "관리자",
|
||||
"api": "긴 수명의 API 키 생성 및 관리",
|
||||
"realtime": "실시간 연결 및 업데이트 사용"
|
||||
},
|
||||
"permissions-name": "권한",
|
||||
"permissionsHelp": "사용자를 관리자로 만들거나 권한을 부여할 수 있습니다. 관리자를 선택하면, 모든 옵션이 자동으로 선택됩니다. 사용자 관리는 현재 관리자만 할 수 있습니다.\n",
|
||||
@@ -213,13 +236,13 @@
|
||||
"rulesHelp": "사용자별로 규칙을 허용/방지를 지정할 수 있습니다. 방지된 파일은 보이지 않고 사용자들은 접근할 수 없습니다. 사용자의 접근 허용 범위와 관련해 정규표현식(regex)과 경로를 지원합니다.\n",
|
||||
"scope": "범위",
|
||||
"settingsUpdated": "설정 수정됨!",
|
||||
"shareDuration": "",
|
||||
"shareManagement": "",
|
||||
"singleClick": "",
|
||||
"shareDuration": "공유 기간",
|
||||
"shareManagement": "공유 관리",
|
||||
"singleClick": "클릭 한 번으로 파일과 디렉터리 열기",
|
||||
"themes": {
|
||||
"dark": "",
|
||||
"light": "",
|
||||
"title": ""
|
||||
"dark": "Dark",
|
||||
"light": "빛",
|
||||
"title": "테마"
|
||||
},
|
||||
"user": "사용자",
|
||||
"userCommands": "명령어",
|
||||
@@ -230,7 +253,33 @@
|
||||
"userManagement": "사용자 관리",
|
||||
"userUpdated": "사용자 수정됨!",
|
||||
"username": "사용자 이름",
|
||||
"users": "사용자"
|
||||
"users": "사용자",
|
||||
"loginMethod": "로그인 방법",
|
||||
"modifyOtherUser": "사용자를 수정합니다:",
|
||||
"modifyCurrentUser": "현재 사용자 수정",
|
||||
"themeColor": "테마 색상",
|
||||
"disableOfficePreviewDescription": "OnlyOffice 뷰어를 비활성화할 파일 확장명을 공백으로 구분한 목록입니다. (예: '.txt .html').",
|
||||
"disableOfficePreview": "특정 파일 확장자에 대해서만오피스 뷰어 사용 안 함",
|
||||
"filePreviewOptions": "파일 미리 보기 옵션",
|
||||
"listingOptions": "리스팅 옵션",
|
||||
"emptyGlobal": "현재 글로벌 설정 옵션은 없으며, 구성 yaml을 편집하여 시스템 설정을 조정할 수 있습니다.",
|
||||
"scopes": "허용된 소스와 그 안에서 사용자 범위 정의하기",
|
||||
"UserManagement": "사용자 관리",
|
||||
"tusUploads": "청크 업로드",
|
||||
"tusUploadsHelp": "파일 브라우저는 청크 파일 업로드를 지원하므로 불안정한 네트워크에서도 효율적이고 안정적이며 재개 가능한 청크 파일 업로드를 생성할 수 있습니다.",
|
||||
"tusUploadsChunkSize": "요청의 최대 크기를 나타냅니다(더 작은 업로드의 경우 직접 업로드가 사용됩니다). 바이트 입력을 나타내는 일반 정수 또는 10MB, 1GB 등과 같은 문자열을 입력할 수 있습니다.",
|
||||
"tusUploadsRetryCount": "청크 업로드에 실패한 경우 수행할 재시도 횟수입니다.",
|
||||
"userHomeBasePath": "사용자 홈 디렉터리의 기본 경로",
|
||||
"userScopeGenerationPlaceholder": "범위가 자동으로 생성됩니다.",
|
||||
"createUserHomeDirectory": "사용자 홈 디렉터리 만들기",
|
||||
"api": "API 키",
|
||||
"setDateFormat": "정확한 날짜 형식 설정",
|
||||
"shareDeleted": "공유 삭제됨!",
|
||||
"loginMethodDescription": "사용자에게 허용된 로그인 방법을 설정합니다.",
|
||||
"userNotAdmin": "사용자가 관리자가 아닙니다.",
|
||||
"enterPassword": "비밀번호 입력",
|
||||
"enterPasswordAgain": "비밀번호를 다시 입력합니다.",
|
||||
"passwordsDoNotMatch": "비밀번호가 일치하지 않습니다."
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "도움말",
|
||||
@@ -243,7 +292,8 @@
|
||||
"preview": "미리보기",
|
||||
"settings": "설정",
|
||||
"signup": "가입하기",
|
||||
"siteSettings": "사이트 설정"
|
||||
"siteSettings": "사이트 설정",
|
||||
"sources": "출처"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "링크가 복사되었습니다!"
|
||||
@@ -254,5 +304,51 @@
|
||||
"minutes": "분",
|
||||
"seconds": "초",
|
||||
"unit": "Time Unit"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "취소하시겠습니까?"
|
||||
},
|
||||
"share": {
|
||||
"notice": "참고: 링크(및 선택 사항인 비밀번호)에 액세스할 수 있는 사람은 누구나 공유 파일에 액세스할 수 있습니다. 로그인할 필요는 없습니다."
|
||||
},
|
||||
"api": {
|
||||
"title": "API 키:",
|
||||
"keyName": "API 키 이름:",
|
||||
"createdAt": "만든 곳:",
|
||||
"expiresAt": "만료일:",
|
||||
"permissions": "권한:",
|
||||
"createTitle": "API 키 생성",
|
||||
"keyNamePlaceholder": "고유한 API 키 이름을 입력합니다:",
|
||||
"tokenDuration": "토큰 기간:",
|
||||
"durationNumberPlaceholder": "번호",
|
||||
"days": "일수",
|
||||
"months": "개월",
|
||||
"permissionNote": "키에 대한 권한을 하나 이상 선택합니다. 사용자에게도 해당 권한이 있어야 합니다.",
|
||||
"createKeyFailed": "API 키를 생성하지 못했습니다.",
|
||||
"createKeySuccess": "API 키가 성공적으로 생성되었습니다.",
|
||||
"description": "API 키는 키를 생성한 사용자를 기준으로 합니다. 참조",
|
||||
"swaggerLinkText": "스웨거 페이지",
|
||||
"name": "이름",
|
||||
"created": "생성됨",
|
||||
"expires": "만료",
|
||||
"actions": "작업",
|
||||
"enabled": "활성화됨",
|
||||
"disabled": "장애인"
|
||||
},
|
||||
"index": {
|
||||
"status": "상태",
|
||||
"assessment": "평가",
|
||||
"files": "파일",
|
||||
"folders": "폴더",
|
||||
"lastScanned": "마지막 스캔",
|
||||
"quickScan": "빠른 스캔 초",
|
||||
"fullScan": "전체 스캔 시간(초)",
|
||||
"settingsHover": "사용자 설정",
|
||||
"logout": "로그아웃",
|
||||
"toggleClick": "클릭 한 번으로 토글",
|
||||
"toggleDark": "다크 모드 전환",
|
||||
"toggleSticky": "고정 모드 토글",
|
||||
"of": "의",
|
||||
"used": "사용됨"
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,7 @@
|
||||
"ru": "Russisch",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "",
|
||||
"tr" : "Türkçe",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "Chinees (vereenvoudigd)",
|
||||
"zhTW": "Chinees (traditioneel)"
|
||||
@@ -125,7 +125,6 @@
|
||||
"downloadMessage": "Kies het vermat dat u wilt downloaden. ",
|
||||
"error": "Er ging iets fout",
|
||||
"fileInfo": "Bestandinformatie",
|
||||
"filesSelected": "{count} geselecteerde bestanden",
|
||||
"lastModified": "Laatst Bewerkt",
|
||||
"move": "Verplaatsen",
|
||||
"moveMessage": "Kies een nieuwe locatie voor je bestand(en)/map(pen)",
|
||||
@@ -145,7 +144,8 @@
|
||||
"show": "Tonen",
|
||||
"size": "Grootte",
|
||||
"upload": "",
|
||||
"uploadMessage": ""
|
||||
"uploadMessage": "",
|
||||
"deleteMessageShare": "Are you sure you want to delete this share: {path} ?"
|
||||
},
|
||||
"search": {
|
||||
"images": "Afbeeldingen",
|
||||
@@ -254,5 +254,9 @@
|
||||
"minutes": "Minuten",
|
||||
"seconds": "Seconden",
|
||||
"unit": "Tijdseenheid"
|
||||
}
|
||||
},
|
||||
"upload": {},
|
||||
"share": {},
|
||||
"api": {},
|
||||
"index": {}
|
||||
}
|
||||
+107
-12
@@ -31,7 +31,13 @@
|
||||
"switchView": "Zmień widok",
|
||||
"toggleSidebar": "Pokaż/ukryj panel boczny",
|
||||
"update": "Aktualizuj",
|
||||
"upload": "Wgraj"
|
||||
"upload": "Wgraj",
|
||||
"copyDownloadLinkToClipboard": "Skopiuj łącze pobierania do schowka",
|
||||
"file": "Plik",
|
||||
"folder": "Folder",
|
||||
"submit": "Prześlij",
|
||||
"openFile": "Otwórz plik",
|
||||
"continue": "Kontynuuj"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Pobierz plik",
|
||||
@@ -41,7 +47,8 @@
|
||||
"errors": {
|
||||
"forbidden": "Nie posiadasz uprawnień potrzebnych, by uzyskać do tego dostęp.",
|
||||
"internal": "Pojawił się poważny problem.",
|
||||
"notFound": "Ten adres nie jest poprawny."
|
||||
"notFound": "Ten adres nie jest poprawny.",
|
||||
"connection": "Nie można uzyskać dostępu do serwera."
|
||||
},
|
||||
"files": {
|
||||
"body": "Body",
|
||||
@@ -59,7 +66,8 @@
|
||||
"size": "Rozmiar",
|
||||
"sortByLastModified": "Sortuj wg. daty modyfikacji",
|
||||
"sortByName": "Sortuj wg. nazwy",
|
||||
"sortBySize": "Sortuj wg. rozmiaru"
|
||||
"sortBySize": "Sortuj wg. rozmiaru",
|
||||
"noPreview": "Podgląd nie jest dostępny dla tego pliku."
|
||||
},
|
||||
"help": {
|
||||
"click": "wybierz plik lub foler",
|
||||
@@ -95,7 +103,7 @@
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "Svenska (Sverige)",
|
||||
"tr" : "Türkçe",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
@@ -110,7 +118,8 @@
|
||||
"submit": "Logowanie",
|
||||
"username": "Nazwa użytkownika",
|
||||
"usernameTaken": "Nazwa użytkownika już zajęta",
|
||||
"wrongCredentials": "Błędne dane logowania"
|
||||
"wrongCredentials": "Błędne dane logowania",
|
||||
"or": "LUB"
|
||||
},
|
||||
"permanent": "Permanentny",
|
||||
"prompts": {
|
||||
@@ -125,7 +134,6 @@
|
||||
"downloadMessage": "Wybierz format, jaki chesz pobrać.",
|
||||
"error": "Pojawił się nieznany błąd",
|
||||
"fileInfo": "Informacje o pliku",
|
||||
"filesSelected": "{count} plików zostało zaznaczonych.",
|
||||
"lastModified": "Osatnio Zmodyfikowane",
|
||||
"move": "Przenieś",
|
||||
"moveMessage": "Wybierz nową lokalizację dla swoich plik(ów)/folder(ów):",
|
||||
@@ -145,8 +153,14 @@
|
||||
"show": "Pokaż",
|
||||
"size": "Rozmiar",
|
||||
"upload": "Prześlij",
|
||||
"uploadMessage": "Proszę wybrać metodę przesyłania"
|
||||
|
||||
"uploadMessage": "Proszę wybrać metodę przesyłania",
|
||||
"deleteMessageShare": "Are you sure you want to delete this share: {path} ?",
|
||||
"deleteUserMessage": "Czy na pewno chcesz usunąć tego użytkownika?",
|
||||
"filesSelected": "wybrane pliki",
|
||||
"uploadFiles": "Uploading {files} files...",
|
||||
"optionalPassword": "Hasło opcjonalne",
|
||||
"typeName": "Typ:",
|
||||
"selected": "wybrany"
|
||||
},
|
||||
"search": {
|
||||
"images": "Zdjęcia",
|
||||
@@ -156,7 +170,12 @@
|
||||
"search": "Szukaj...",
|
||||
"typeToSearch": "Zacznij pisać, aby wyszukać...",
|
||||
"types": "Typy",
|
||||
"video": "Wideo"
|
||||
"video": "Wideo",
|
||||
"path": "Ścieżka:",
|
||||
"smallerThan": "Mniejszy niż:",
|
||||
"largerThan": "Większy niż:",
|
||||
"helpText1": "Wyszukiwanie odbywa się po każdym wpisanym znaku (minimum 3 znaki dla wyszukiwanych haseł).",
|
||||
"helpText2": "Indeks: Wyszukiwanie wykorzystuje indeks, który jest automatycznie aktualizowany w skonfigurowanych odstępach czasu (domyślnie: 5 minut). Wyszukiwanie po uruchomieniu programu może skutkować niekompletnymi wynikami."
|
||||
},
|
||||
"settings": {
|
||||
"admin": "Admin",
|
||||
@@ -203,7 +222,10 @@
|
||||
"execute": "Wykonywanie poleceń",
|
||||
"modify": "Edycja plików",
|
||||
"rename": "Zmiana nazw lub przenoszenie plików i katalogów",
|
||||
"share": "Udostępnianie plików"
|
||||
"share": "Udostępnianie plików",
|
||||
"admin": "Administrator",
|
||||
"api": "Tworzenie i zarządzanie kluczami API o długiej żywotności",
|
||||
"realtime": "Połączenia i aktualizacje w czasie rzeczywistym"
|
||||
},
|
||||
"permissions-name": "Uprawnienia",
|
||||
"permissionsHelp": "Możesz uczynić użytkownika administratorem, lub wybrać uprawnienia indywidualnie. Jeśli zaznaczysz opcję \"Administrator\", wszystkie pozostałe opcje zostaną automatycznie zaznaczone. Zarządzanie użytkownikami pozostaje przywilejem administratora.\n",
|
||||
@@ -231,7 +253,33 @@
|
||||
"userManagement": "Zarządzanie użytkownikami",
|
||||
"userUpdated": "Użytkownik zapisany!",
|
||||
"username": "Nazwa użytkownika",
|
||||
"users": "Użytkownicy"
|
||||
"users": "Użytkownicy",
|
||||
"loginMethod": "Metoda logowania",
|
||||
"modifyOtherUser": "Modyfikacja użytkownika:",
|
||||
"modifyCurrentUser": "Modyfikacja bieżącego użytkownika",
|
||||
"themeColor": "Kolor motywu",
|
||||
"disableOfficePreviewDescription": "Rozdzielana spacjami lista rozszerzeń plików, dla których przeglądarka OnlyOffice ma zostać wyłączona. (np. \".txt .html\").",
|
||||
"disableOfficePreview": "Wyłącz przeglądarkę onlyoffice dla niektórych rozszerzeń plików",
|
||||
"filePreviewOptions": "Opcje podglądu plików",
|
||||
"listingOptions": "Opcje aukcji",
|
||||
"emptyGlobal": "Obecnie nie ma globalnych opcji konfiguracyjnych, można edytować konfigurację yaml, aby dostosować ustawienia systemu.",
|
||||
"scopes": "Definiowanie dozwolonych źródeł i zakresu użytkowników w ich obrębie",
|
||||
"UserManagement": "Zarządzanie użytkownikami",
|
||||
"tusUploads": "Zbiorcze przesyłanie plików",
|
||||
"tusUploadsHelp": "File Browser obsługuje przesyłanie plików w postaci fragmentów, umożliwiając tworzenie wydajnych, niezawodnych, wznawianych i podzielonych na fragmenty plików nawet w niewiarygodnych sieciach.",
|
||||
"tusUploadsChunkSize": "Wskazuje maksymalny rozmiar żądania (bezpośrednie przesyłanie będzie używane do przesyłania mniejszych plików). Możesz wprowadzić zwykłą liczbę całkowitą oznaczającą bajty wejściowe lub ciąg znaków, taki jak 10 MB, 1 GB itp.",
|
||||
"tusUploadsRetryCount": "Liczba ponawianych prób w przypadku niepowodzenia przesłania fragmentu.",
|
||||
"userHomeBasePath": "Ścieżka podstawowa dla katalogów domowych użytkownika",
|
||||
"userScopeGenerationPlaceholder": "Zakres zostanie wygenerowany automatycznie",
|
||||
"createUserHomeDirectory": "Tworzenie katalogu domowego użytkownika",
|
||||
"api": "Klucze API",
|
||||
"setDateFormat": "Ustaw dokładny format daty",
|
||||
"shareDeleted": "Usunięto udostępnianie!",
|
||||
"loginMethodDescription": "dozwolona metoda logowania dla użytkownika.",
|
||||
"userNotAdmin": "Użytkownik nie jest administratorem",
|
||||
"enterPassword": "Wprowadź hasło",
|
||||
"enterPasswordAgain": "Wprowadź hasło ponownie",
|
||||
"passwordsDoNotMatch": "Hasła nie są zgodne"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Pomoc",
|
||||
@@ -244,7 +292,8 @@
|
||||
"preview": "Podgląd",
|
||||
"settings": "Ustawienia",
|
||||
"signup": "Rejestracja",
|
||||
"siteSettings": "Ustawienia Strony"
|
||||
"siteSettings": "Ustawienia Strony",
|
||||
"sources": "Źródła"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Link Skopiowany!"
|
||||
@@ -255,5 +304,51 @@
|
||||
"minutes": "Minuty",
|
||||
"seconds": "Sekundy",
|
||||
"unit": "Jednostka czasu"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Czy na pewno chcesz przerwać ciążę?"
|
||||
},
|
||||
"share": {
|
||||
"notice": "Uwaga: każdy, kto ma dostęp do linku (i opcjonalnie hasło), może uzyskać dostęp do udostępnionych plików. Nie ma wymogu bycia zalogowanym."
|
||||
},
|
||||
"api": {
|
||||
"title": "Klucze API:",
|
||||
"keyName": "Nazwa klucza API:",
|
||||
"createdAt": "Utworzono w:",
|
||||
"expiresAt": "Wygasa w:",
|
||||
"permissions": "Uprawnienia:",
|
||||
"createTitle": "Tworzenie klucza API",
|
||||
"keyNamePlaceholder": "Wprowadź unikalną nazwę klucza API:",
|
||||
"tokenDuration": "Czas trwania tokena:",
|
||||
"durationNumberPlaceholder": "Liczba",
|
||||
"days": "Dni",
|
||||
"months": "Miesiące",
|
||||
"permissionNote": "Wybierz co najmniej jedno uprawnienie dla klucza. Użytkownik również musi mieć to uprawnienie.",
|
||||
"createKeyFailed": "Nie udało się utworzyć klucza API.",
|
||||
"createKeySuccess": "Klucz API został pomyślnie utworzony.",
|
||||
"description": "Klucze API są oparte na użytkowniku, który je utworzył. Zobacz",
|
||||
"swaggerLinkText": "strona swagger",
|
||||
"name": "Nazwa",
|
||||
"created": "Utworzony",
|
||||
"expires": "Wygasa",
|
||||
"actions": "Działania",
|
||||
"enabled": "Włączone",
|
||||
"disabled": "Wyłączony"
|
||||
},
|
||||
"index": {
|
||||
"status": "Status",
|
||||
"assessment": "Ocena",
|
||||
"files": "Pliki",
|
||||
"folders": "Foldery",
|
||||
"lastScanned": "Ostatnio skanowane",
|
||||
"quickScan": "Sekundy szybkiego skanowania",
|
||||
"fullScan": "Sekundy pełnego skanowania",
|
||||
"settingsHover": "Ustawienia dla użytkownika",
|
||||
"logout": "Wylogowanie",
|
||||
"toggleClick": "Przełączanie jednym kliknięciem",
|
||||
"toggleDark": "Przełączanie trybu ciemnego",
|
||||
"toggleSticky": "Przełączanie trybu samoprzylepnego",
|
||||
"of": "z",
|
||||
"used": "używany"
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,9 @@
|
||||
"toggleSidebar": "Alternar barra lateral",
|
||||
"update": "Atualizar",
|
||||
"upload": "Enviar",
|
||||
"openFile": "Abrir"
|
||||
"openFile": "Abrir",
|
||||
"copyDownloadLinkToClipboard": "Copiar o link de download para a área de transferência",
|
||||
"continue": "Continuar"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Baixar arquivo",
|
||||
@@ -101,7 +103,7 @@
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "",
|
||||
"tr" : "Türkçe",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
@@ -116,7 +118,8 @@
|
||||
"submit": "Login",
|
||||
"username": "Nome do usuário",
|
||||
"usernameTaken": "Nome de usuário já existe",
|
||||
"wrongCredentials": "Ops! Dados incorretos."
|
||||
"wrongCredentials": "Ops! Dados incorretos.",
|
||||
"or": "OU"
|
||||
},
|
||||
"permanent": "Permanente",
|
||||
"prompts": {
|
||||
@@ -132,7 +135,6 @@
|
||||
"downloadMessage": "Escolha o formato do arquivo.",
|
||||
"error": "Algo de errado ocorreu",
|
||||
"fileInfo": "Informação do arquivo",
|
||||
"filesSelected": "{count} arquivos selecionados.",
|
||||
"lastModified": "Última modificação",
|
||||
"move": "Mover",
|
||||
"moveMessage": "Escolha uma nova pasta para os seus arquivos:",
|
||||
@@ -154,7 +156,11 @@
|
||||
"upload": "Enviar",
|
||||
"uploadFiles": "Enviando {files} arquivos...",
|
||||
"uploadMessage": "Selecione uma opção para enviar.",
|
||||
"optionalPassword": "Senha opcional"
|
||||
"optionalPassword": "Senha opcional",
|
||||
"deleteUserMessage": "Tem certeza de que deseja excluir esse usuário?",
|
||||
"filesSelected": "arquivos selecionados",
|
||||
"typeName": "Tipo:",
|
||||
"selected": "selecionado"
|
||||
},
|
||||
"search": {
|
||||
"images": "Imagens",
|
||||
@@ -164,7 +170,12 @@
|
||||
"search": "Pesquise...",
|
||||
"typeToSearch": "Digite para pesquisar...",
|
||||
"types": "Tipos",
|
||||
"video": "Vídeos"
|
||||
"video": "Vídeos",
|
||||
"path": "Caminho:",
|
||||
"smallerThan": "Menor que:",
|
||||
"largerThan": "Maior que:",
|
||||
"helpText1": "A pesquisa ocorre em cada caractere que você digita (mínimo de 3 caracteres para termos de pesquisa).",
|
||||
"helpText2": "O índice: A pesquisa utiliza o índice que é atualizado automaticamente no intervalo configurado (padrão: 5 minutos). A pesquisa quando o programa acaba de ser iniciado pode resultar em resultados incompletos."
|
||||
},
|
||||
"settings": {
|
||||
"admin": "Admin",
|
||||
@@ -206,7 +217,7 @@
|
||||
"newUser": "Novo usuário",
|
||||
"password": "Senha",
|
||||
"passwordUpdated": "Senha atualizada!",
|
||||
"path": "",
|
||||
"path": "Caminho",
|
||||
"permissions": {
|
||||
"create": "Criar arquivos e diretórios",
|
||||
"delete": "Apagar arquivos e diretórios",
|
||||
@@ -214,7 +225,10 @@
|
||||
"execute": "Executar comandos",
|
||||
"modify": "Editar arquivos",
|
||||
"rename": "Renomear ou mover arquivos e diretórios",
|
||||
"share": "Compartilhar arquivos"
|
||||
"share": "Compartilhar arquivos",
|
||||
"admin": "Administrador",
|
||||
"api": "Criar e gerenciar chaves de API de longa duração",
|
||||
"realtime": "Permitir conexões e atualizações em tempo real"
|
||||
},
|
||||
"permissions-name": "Permissões",
|
||||
"permissionsHelp": "Pode definir o usuário como administrador ou escolher as permissões manualmente. Se selecionar a opção \"Administrador\", todas as outras opções serão automaticamente selecionadas. A gestão dos usuários é um privilégio restringido aos administradores.\n",
|
||||
@@ -244,7 +258,28 @@
|
||||
"userManagement": "Gerenciamento de usuários",
|
||||
"userUpdated": "Usuário atualizado!",
|
||||
"username": "Nome do usuário",
|
||||
"users": "Usuários"
|
||||
"users": "Usuários",
|
||||
"loginMethod": "Método de login",
|
||||
"modifyOtherUser": "Modificar usuário:",
|
||||
"modifyCurrentUser": "Modificar o usuário atual",
|
||||
"themeColor": "Cor do tema",
|
||||
"disableOfficePreviewDescription": "Uma lista de extensões de arquivo separada por espaços para desativar o visualizador do OnlyOffice. (por exemplo, '.txt .html').",
|
||||
"disableOfficePreview": "Desativar o visualizador do onlyoffice para determinadas extensões de arquivo",
|
||||
"filePreviewOptions": "Opções de visualização de arquivos",
|
||||
"listingOptions": "Opções de listagem",
|
||||
"emptyGlobal": "Atualmente, não há opções de configuração global. Você pode editar o yaml de configuração para ajustar as configurações do sistema.",
|
||||
"scopes": "Definir fontes permitidas e o escopo do usuário dentro delas",
|
||||
"UserManagement": "Gerenciamento de usuários",
|
||||
"tusUploads": "Uploads em pedaços",
|
||||
"tusUploadsHelp": "O File Browser oferece suporte a uploads de arquivos em pedaços, permitindo a criação de uploads de arquivos eficientes, confiáveis, reestruturáveis e em pedaços, mesmo em redes não confiáveis.",
|
||||
"tusUploadsChunkSize": "Indica o tamanho máximo de uma solicitação (uploads diretos serão usados para uploads menores). Você pode inserir um número inteiro simples que denota uma entrada de bytes ou uma cadeia de caracteres como 10 MB, 1 GB etc.",
|
||||
"tusUploadsRetryCount": "Número de novas tentativas a serem executadas se houver falha no upload de um bloco.",
|
||||
"api": "Chaves de API",
|
||||
"loginMethodDescription": "método de login permitido para o usuário.",
|
||||
"userNotAdmin": "O usuário não é um administrador",
|
||||
"enterPassword": "Digite a senha",
|
||||
"enterPasswordAgain": "Digite a senha novamente",
|
||||
"passwordsDoNotMatch": "As senhas não correspondem"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Ajuda",
|
||||
@@ -257,7 +292,8 @@
|
||||
"preview": "Pré-visualizar",
|
||||
"settings": "Configurações",
|
||||
"signup": "Cadastrar",
|
||||
"siteSettings": "Configurações do site"
|
||||
"siteSettings": "Configurações do site",
|
||||
"sources": "Fontes"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Link copiado!"
|
||||
@@ -268,5 +304,51 @@
|
||||
"minutes": "Minutos",
|
||||
"seconds": "Segundos",
|
||||
"unit": "Unidades de Tempo"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Tem certeza de que quer abortar?"
|
||||
},
|
||||
"share": {
|
||||
"notice": "Observação: qualquer pessoa que tenha acesso ao link (e à senha opcional) pode acessar os arquivos compartilhados. Não é necessário estar conectado."
|
||||
},
|
||||
"api": {
|
||||
"title": "Chaves de API:",
|
||||
"keyName": "Nome da chave da API:",
|
||||
"createdAt": "Criado em:",
|
||||
"expiresAt": "Expira em:",
|
||||
"permissions": "Permissões:",
|
||||
"createTitle": "Criar chave de API",
|
||||
"keyNamePlaceholder": "Digite um nome de chave de API exclusivo:",
|
||||
"tokenDuration": "Duração do token:",
|
||||
"durationNumberPlaceholder": "Número",
|
||||
"days": "Dias",
|
||||
"months": "Meses",
|
||||
"permissionNote": "Escolha pelo menos uma permissão para a chave. Seu usuário também deve ter a permissão.",
|
||||
"createKeyFailed": "Falha ao criar a chave de API.",
|
||||
"createKeySuccess": "Chave de API criada com sucesso.",
|
||||
"description": "As chaves de API são baseadas no usuário que as cria. Veja",
|
||||
"swaggerLinkText": "página do swagger",
|
||||
"name": "Nome",
|
||||
"created": "Criado",
|
||||
"expires": "Expirações",
|
||||
"actions": "Ações",
|
||||
"enabled": "Ativado",
|
||||
"disabled": "Desativado"
|
||||
},
|
||||
"index": {
|
||||
"status": "Status",
|
||||
"assessment": "Avaliação",
|
||||
"files": "Arquivos",
|
||||
"folders": "Pastas",
|
||||
"lastScanned": "Última varredura",
|
||||
"quickScan": "Segundos de varredura rápida",
|
||||
"fullScan": "Segundos de varredura completa",
|
||||
"settingsHover": "Configurações para o usuário",
|
||||
"logout": "Sair",
|
||||
"toggleClick": "Alternar clique único",
|
||||
"toggleDark": "Alternar o modo escuro",
|
||||
"toggleSticky": "Alternar o modo de aderência",
|
||||
"of": "de",
|
||||
"used": "usado"
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,7 @@
|
||||
"ru": "Russo",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "",
|
||||
"tr" : "Türkçe",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "Chinês simplificado",
|
||||
"zhTW": "Chinês tradicional"
|
||||
@@ -125,7 +125,6 @@
|
||||
"downloadMessage": "Escolha o formato do ficheiro que quer descarregar.",
|
||||
"error": "Algo correu mal",
|
||||
"fileInfo": "Informação do ficheiro",
|
||||
"filesSelected": "{count} ficheiros selecionados.",
|
||||
"lastModified": "Última alteração",
|
||||
"move": "Mover",
|
||||
"moveMessage": "Escolha uma nova casa para os seus ficheiros/pastas:",
|
||||
@@ -145,7 +144,8 @@
|
||||
"show": "Mostrar",
|
||||
"size": "Tamanho",
|
||||
"upload": "",
|
||||
"uploadMessage": ""
|
||||
"uploadMessage": "",
|
||||
"deleteMessageShare": "Are you sure you want to delete this share: {path} ?"
|
||||
},
|
||||
"search": {
|
||||
"images": "Imagens",
|
||||
@@ -254,5 +254,9 @@
|
||||
"minutes": "Minutos",
|
||||
"seconds": "Segundos",
|
||||
"unit": "Unidades de tempo"
|
||||
}
|
||||
},
|
||||
"upload": {},
|
||||
"share": {},
|
||||
"api": {},
|
||||
"index": {}
|
||||
}
|
||||
+116
-20
@@ -31,17 +31,24 @@
|
||||
"switchView": "Schimba vizualizarea",
|
||||
"toggleSidebar": "Comută bara laterală",
|
||||
"update": "Actualizează",
|
||||
"upload": "Încarcă"
|
||||
"upload": "Încarcă",
|
||||
"copyDownloadLinkToClipboard": "Copiați link-ul de descărcare în clipboard",
|
||||
"file": "Fișier",
|
||||
"folder": "Dosar",
|
||||
"submit": "Trimite",
|
||||
"openFile": "Deschideți fișierul",
|
||||
"continue": "Continuați"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Descarcă fișier",
|
||||
"downloadFolder": "Descarcă director",
|
||||
"downloadSelected": ""
|
||||
"downloadSelected": "Descărcare selectată"
|
||||
},
|
||||
"errors": {
|
||||
"forbidden": "Nu ai permisiuni sa accesezi asta.",
|
||||
"internal": "Ceva nu a funcționat corect.",
|
||||
"notFound": "Aceasta locație nu poate fi accesată."
|
||||
"notFound": "Aceasta locație nu poate fi accesată.",
|
||||
"connection": "Serverul nu poate fi accesat."
|
||||
},
|
||||
"files": {
|
||||
"body": "Corp",
|
||||
@@ -59,7 +66,8 @@
|
||||
"size": "Dimensiune",
|
||||
"sortByLastModified": "Ordonează dup ultima modificare",
|
||||
"sortByName": "Ordonează după nume",
|
||||
"sortBySize": "Ordonează după dimensiune"
|
||||
"sortBySize": "Ordonează după dimensiune",
|
||||
"noPreview": "Previzualizarea nu este disponibilă pentru acest fișier."
|
||||
},
|
||||
"help": {
|
||||
"click": "alege fișier sau director",
|
||||
@@ -95,7 +103,7 @@
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "",
|
||||
"tr" : "Türkçe",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
@@ -110,7 +118,8 @@
|
||||
"submit": "Autentificare",
|
||||
"username": "Utilizator",
|
||||
"usernameTaken": "Utilizatorul există",
|
||||
"wrongCredentials": "Informații greșite"
|
||||
"wrongCredentials": "Informații greșite",
|
||||
"or": "SAU"
|
||||
},
|
||||
"permanent": "Permanent",
|
||||
"prompts": {
|
||||
@@ -125,7 +134,6 @@
|
||||
"downloadMessage": "Alege formatul în care vrei să descarci.",
|
||||
"error": "Ceva n-a funcționat cum trebuie",
|
||||
"fileInfo": "Informații fișier",
|
||||
"filesSelected": "{count} fișiere selectate.",
|
||||
"lastModified": "Ultima modificare",
|
||||
"move": "Mută",
|
||||
"moveMessage": "Alege destinația:",
|
||||
@@ -144,8 +152,15 @@
|
||||
"scheduleMessage": "Alege data si ora pentru a programa publicarea acestei postări.",
|
||||
"show": "Arată",
|
||||
"size": "Dimensiune",
|
||||
"upload": "",
|
||||
"uploadMessage": ""
|
||||
"upload": "Încărcare",
|
||||
"uploadMessage": "Selectați o opțiune pentru încărcare.",
|
||||
"deleteMessageShare": "Are you sure you want to delete this share: {path} ?",
|
||||
"deleteUserMessage": "Sunteți sigur că doriți să ștergeți acest utilizator?",
|
||||
"filesSelected": "fișiere selectate",
|
||||
"uploadFiles": "Uploading {files} files...",
|
||||
"optionalPassword": "Parolă opțională",
|
||||
"typeName": "Tip:",
|
||||
"selected": "selectat"
|
||||
},
|
||||
"search": {
|
||||
"images": "Imagini",
|
||||
@@ -155,7 +170,12 @@
|
||||
"search": "Caută...",
|
||||
"typeToSearch": "Scrie pentru a căuta...",
|
||||
"types": "Tipuri",
|
||||
"video": "Video"
|
||||
"video": "Video",
|
||||
"path": "Calea:",
|
||||
"smallerThan": "Mai mic decât:",
|
||||
"largerThan": "Mai mare decât:",
|
||||
"helpText1": "Căutarea are loc pe fiecare caracter tastat (minim 3 caractere pentru termenii de căutare).",
|
||||
"helpText2": "Indexul: Căutarea utilizează indexul care se actualizează automat la intervalul configurat (implicit: 5 minute). Căutarea atunci când programul tocmai a început poate duce la rezultate incomplete."
|
||||
},
|
||||
"settings": {
|
||||
"admin": "Admin",
|
||||
@@ -194,7 +214,7 @@
|
||||
"newUser": "Utilizator nou",
|
||||
"password": "Parola",
|
||||
"passwordUpdated": "Parola actualizată!",
|
||||
"path": "",
|
||||
"path": "Calea",
|
||||
"permissions": {
|
||||
"create": "Crează fișiere și directoare",
|
||||
"delete": "Șterge fișiere și directoare",
|
||||
@@ -202,7 +222,10 @@
|
||||
"execute": "Execută comenzi",
|
||||
"modify": "Modifică fișiere",
|
||||
"rename": "Redenumește sau mută fișiere și directoare",
|
||||
"share": "Distribuie fișiere"
|
||||
"share": "Distribuie fișiere",
|
||||
"admin": "Administrator",
|
||||
"api": "Crearea și gestionarea cheilor API cu durată lungă de viață",
|
||||
"realtime": "Permite conexiuni și actualizări în timp real"
|
||||
},
|
||||
"permissions-name": "Permisiuni",
|
||||
"permissionsHelp": "Poți alege ca un utilizator să fie administrator sau să-i alegi permisiunile individual. Dacă alegi \"Administrator\", toate celelalte opțiuni vor fi bifate automat. Gestionarea utilizatorilor rămâne un privilegiu exclusiv al administratorilor.\n",
|
||||
@@ -213,13 +236,13 @@
|
||||
"rulesHelp": "Aici poți defini un set de reguli pentru acest utilizator. Fișierele blocate nu vor apărea in lista și nici nu vor putea fi accesate de utilizator. Expresiile regulate si căile relative la domeniul utilizatorului sunt permise.\n",
|
||||
"scope": "Domeniu",
|
||||
"settingsUpdated": "Setări actualizate!",
|
||||
"shareDuration": "",
|
||||
"shareManagement": "",
|
||||
"singleClick": "",
|
||||
"shareDuration": "Acțiune Durată",
|
||||
"shareManagement": "Gestionarea acțiunilor",
|
||||
"singleClick": "Utilizați un singur clic pentru a deschide fișiere și directoare",
|
||||
"themes": {
|
||||
"dark": "",
|
||||
"light": "",
|
||||
"title": ""
|
||||
"dark": "Întuneric",
|
||||
"light": "Lumină",
|
||||
"title": "Tema"
|
||||
},
|
||||
"user": "Utilizator",
|
||||
"userCommands": "Comenzi",
|
||||
@@ -230,7 +253,33 @@
|
||||
"userManagement": "Gestionare utilizatori",
|
||||
"userUpdated": "Utilizator actualizat!",
|
||||
"username": "Utilizator",
|
||||
"users": "Utilizatori"
|
||||
"users": "Utilizatori",
|
||||
"loginMethod": "Metoda de conectare",
|
||||
"modifyOtherUser": "Modificați utilizatorul:",
|
||||
"modifyCurrentUser": "Modificarea utilizatorului curent",
|
||||
"themeColor": "Culoare temă",
|
||||
"disableOfficePreviewDescription": "O listă de extensii de fișiere separate prin spațiu pentru care se dezactivează vizualizatorul OnlyOffice. (de exemplu, \".txt .html\").",
|
||||
"disableOfficePreview": "Dezactivați vizualizatorul onlyoffice pentru anumite extensii de fișiere",
|
||||
"filePreviewOptions": "Opțiuni de previzualizare a fișierelor",
|
||||
"listingOptions": "Opțiuni de listare",
|
||||
"emptyGlobal": "În prezent nu există opțiuni de configurare globală, Puteți edita yaml-ul de configurare pentru a ajusta setările sistemului.",
|
||||
"scopes": "Definirea surselor permise și a domeniului de aplicare al utilizatorului în cadrul acestora",
|
||||
"UserManagement": "Gestionarea utilizatorilor",
|
||||
"tusUploads": "Chunked încărcări",
|
||||
"tusUploadsHelp": "File Browser suportă încărcări de fișiere fragmentate, permițând crearea de încărcări de fișiere eficiente, fiabile, reluabile și fragmentate, chiar și în rețele nesigure.",
|
||||
"tusUploadsChunkSize": "Indică dimensiunea maximă a unei cereri (încărcările directe vor fi utilizate pentru încărcări mai mici). Puteți introduce un număr întreg simplu care denotă o intrare de octeți sau un șir de caractere precum 10MB, 1GB etc.",
|
||||
"tusUploadsRetryCount": "Numărul de încercări care trebuie efectuate dacă o bucată nu reușește să fie încărcată.",
|
||||
"userHomeBasePath": "Calea de bază pentru directoarele home ale utilizatorilor",
|
||||
"userScopeGenerationPlaceholder": "Domeniul de aplicare va fi generat automat",
|
||||
"createUserHomeDirectory": "Crearea directorului home al utilizatorului",
|
||||
"api": "Chei API",
|
||||
"setDateFormat": "Setați formatul exact al datei",
|
||||
"shareDeleted": "Share șters!",
|
||||
"loginMethodDescription": "metoda de conectare permisă pentru utilizator.",
|
||||
"userNotAdmin": "Utilizatorul nu este administrator",
|
||||
"enterPassword": "Introduceți parola",
|
||||
"enterPasswordAgain": "Introduceți din nou parola",
|
||||
"passwordsDoNotMatch": "Parolele nu se potrivesc"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Ajutor",
|
||||
@@ -243,7 +292,8 @@
|
||||
"preview": "Previzualizare",
|
||||
"settings": "Setări",
|
||||
"signup": "Înregistrare",
|
||||
"siteSettings": "Setări site"
|
||||
"siteSettings": "Setări site",
|
||||
"sources": "Surse"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Legătură copiată!"
|
||||
@@ -254,5 +304,51 @@
|
||||
"minutes": "Minute",
|
||||
"seconds": "Secunde",
|
||||
"unit": "Unitate de timp"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Ești sigură că vrei să avortezi?"
|
||||
},
|
||||
"share": {
|
||||
"notice": "Notă: orice persoană care are acces la link (și parola opțională) poate accesa fișierele partajate. Nu este necesar să fiți autentificat."
|
||||
},
|
||||
"api": {
|
||||
"title": "Chei API:",
|
||||
"keyName": "Nume cheie API:",
|
||||
"createdAt": "Creat la:",
|
||||
"expiresAt": "Expiră la:",
|
||||
"permissions": "Permisiuni:",
|
||||
"createTitle": "Crearea cheii API",
|
||||
"keyNamePlaceholder": "Introduceți un nume unic al cheii API:",
|
||||
"tokenDuration": "Token Durata:",
|
||||
"durationNumberPlaceholder": "Număr",
|
||||
"days": "Zile",
|
||||
"months": "Luni",
|
||||
"permissionNote": "Alegeți cel puțin o permisiune pentru cheie. Utilizatorul dvs. trebuie să aibă și permisiunea respectivă.",
|
||||
"createKeyFailed": "A eșuat crearea cheii API.",
|
||||
"createKeySuccess": "Cheie API creată cu succes.",
|
||||
"description": "Cheile API sunt bazate pe utilizatorul care le creează. A se vedea",
|
||||
"swaggerLinkText": "pagina swagger",
|
||||
"name": "Nume și prenume",
|
||||
"created": "Creat",
|
||||
"expires": "Expiră",
|
||||
"actions": "Acțiuni",
|
||||
"enabled": "Activat",
|
||||
"disabled": "Dezactivat"
|
||||
},
|
||||
"index": {
|
||||
"status": "Statut",
|
||||
"assessment": "Evaluare",
|
||||
"files": "Fișiere",
|
||||
"folders": "Dosare",
|
||||
"lastScanned": "Ultima scanare",
|
||||
"quickScan": "Scanare rapidă secunde",
|
||||
"fullScan": "Scanare completă secunde",
|
||||
"settingsHover": "Setări pentru utilizator",
|
||||
"logout": "Ieșire",
|
||||
"toggleClick": "Comutare clic unic",
|
||||
"toggleDark": "Comutarea modului întunecat",
|
||||
"toggleSticky": "Schimbarea modului lipicios",
|
||||
"of": "de",
|
||||
"used": "utilizate"
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,9 @@
|
||||
"toggleSidebar": "Боковая панель",
|
||||
"update": "Обновить",
|
||||
"upload": "Загрузить",
|
||||
"openFile": "Открыть файл"
|
||||
"openFile": "Открыть файл",
|
||||
"copyDownloadLinkToClipboard": "Скопируйте ссылку на скачивание в буфер обмена",
|
||||
"continue": "Продолжить"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Скачать файл",
|
||||
@@ -101,7 +103,7 @@
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "Swedish (Sweden)",
|
||||
"tr" : "Türkçe",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
@@ -116,7 +118,8 @@
|
||||
"submit": "Войти",
|
||||
"username": "Имя пользователя",
|
||||
"usernameTaken": "Данное имя пользователя уже занято",
|
||||
"wrongCredentials": "Неверные данные"
|
||||
"wrongCredentials": "Неверные данные",
|
||||
"or": "ИЛИ"
|
||||
},
|
||||
"permanent": "Постоянный",
|
||||
"prompts": {
|
||||
@@ -132,7 +135,6 @@
|
||||
"downloadMessage": "Выберите формат в котором хотите скачать.",
|
||||
"error": "Ошибка",
|
||||
"fileInfo": "Информация о файле",
|
||||
"filesSelected": "Файлов выбрано: {count}.",
|
||||
"lastModified": "Последнее изменение",
|
||||
"move": "Переместить",
|
||||
"moveMessage": "Переместить в:",
|
||||
@@ -153,7 +155,12 @@
|
||||
"size": "Размер",
|
||||
"upload": "Загрузить",
|
||||
"uploadMessage": "Выберите вариант для загрузки.",
|
||||
"optionalPassword": "Необязательный пароль"
|
||||
"optionalPassword": "Необязательный пароль",
|
||||
"deleteUserMessage": "Вы уверены, что хотите удалить этого пользователя?",
|
||||
"filesSelected": "выбранные файлы",
|
||||
"uploadFiles": "Uploading {files} files...",
|
||||
"typeName": "Тип:",
|
||||
"selected": "выбранные"
|
||||
},
|
||||
"search": {
|
||||
"images": "Изображения",
|
||||
@@ -163,7 +170,12 @@
|
||||
"search": "Поиск...",
|
||||
"typeToSearch": "Введите имя файла ...",
|
||||
"types": "Типы",
|
||||
"video": "Видео"
|
||||
"video": "Видео",
|
||||
"path": "Путь:",
|
||||
"smallerThan": "Меньше, чем:",
|
||||
"largerThan": "Больше, чем:",
|
||||
"helpText1": "Поиск осуществляется по каждому введенному символу (минимум 3 символа для поисковых запросов).",
|
||||
"helpText2": "Индекс: Для поиска используется индекс, который автоматически обновляется с заданным интервалом (по умолчанию: 5 минут). Поиск, когда программа только что запущена, может привести к неполным результатам."
|
||||
},
|
||||
"settings": {
|
||||
"admin": "Админ",
|
||||
@@ -210,7 +222,10 @@
|
||||
"execute": "Выполнять команды",
|
||||
"modify": "Редактировать файлы",
|
||||
"rename": "Переименовывать или перемещать файлы и каталоги",
|
||||
"share": "Делиться файлами"
|
||||
"share": "Делиться файлами",
|
||||
"admin": "Администратор",
|
||||
"api": "Создание и управление долгоживущими ключами API",
|
||||
"realtime": "Обеспечьте подключение и обновление в режиме реального времени"
|
||||
},
|
||||
"permissions-name": "Права доступа",
|
||||
"permissionsHelp": "Можно настроить пользователя как администратора или выбрать разрешения индивидуально. При выборе \"Администратор\", все остальные параметры будут автоматически выбраны. Управление пользователями - привилегия администратора.\n",
|
||||
@@ -240,7 +255,31 @@
|
||||
"userManagement": "Управление пользователями",
|
||||
"userUpdated": "Пользователь изменен!",
|
||||
"username": "Имя пользователя",
|
||||
"users": "Пользователи"
|
||||
"users": "Пользователи",
|
||||
"loginMethod": "Метод входа в систему",
|
||||
"modifyOtherUser": "Измените пользователя:",
|
||||
"modifyCurrentUser": "Изменить текущего пользователя",
|
||||
"themeColor": "Цвет темы",
|
||||
"disableOfficePreviewDescription": "Список расширений файлов, для которых необходимо отключить программу просмотра OnlyOffice, разделенный пробелами. (например, '.txt .html').",
|
||||
"disableOfficePreview": "Отключите просмотрщик Onlyoffice для определенных расширений файлов",
|
||||
"filePreviewOptions": "Параметры предварительного просмотра файлов",
|
||||
"listingOptions": "Варианты листинга",
|
||||
"emptyGlobal": "В настоящее время нет глобальных опций конфигурации, вы можете редактировать конфигурационный yaml для настройки параметров системы.",
|
||||
"scopes": "Определите разрешенные источники и область действия пользователей в них",
|
||||
"UserManagement": "Управление пользователями",
|
||||
"tusUploads": "Загружаемые файлы",
|
||||
"tusUploadsHelp": "File Browser поддерживает загрузку файлов в виде фрагментов, что позволяет создавать эффективные, надежные, возобновляемые и фрагментированные загрузки файлов даже в ненадежных сетях.",
|
||||
"tusUploadsChunkSize": "Указывает максимальный размер запроса (для меньшего размера будет использоваться прямая загрузка). Вы можете ввести целое число, обозначающее байт, или строку, например 10 МБ, 1 ГБ и т. д.",
|
||||
"tusUploadsRetryCount": "Количество повторных попыток, которые необходимо выполнить, если чанк не удалось загрузить.",
|
||||
"userHomeBasePath": "Базовый путь к домашним каталогам пользователей",
|
||||
"userScopeGenerationPlaceholder": "Область действия будет сгенерирована автоматически",
|
||||
"createUserHomeDirectory": "Создайте домашний каталог пользователя",
|
||||
"api": "Ключи API",
|
||||
"loginMethodDescription": "разрешенный метод входа для пользователя.",
|
||||
"userNotAdmin": "Пользователь не является администратором",
|
||||
"enterPassword": "Введите пароль",
|
||||
"enterPasswordAgain": "Введите пароль еще раз",
|
||||
"passwordsDoNotMatch": "Пароли не совпадают"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Помощь",
|
||||
@@ -253,7 +292,8 @@
|
||||
"preview": "Предпросмотр",
|
||||
"settings": "Настройки",
|
||||
"signup": "Зарегистрироваться",
|
||||
"siteSettings": "Настройки сайта"
|
||||
"siteSettings": "Настройки сайта",
|
||||
"sources": "Источники"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Ссылка скопирована!"
|
||||
@@ -264,5 +304,51 @@
|
||||
"minutes": "Минуты",
|
||||
"seconds": "Секунды",
|
||||
"unit": "Единица времени"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Вы уверены, что хотите сделать аборт?"
|
||||
},
|
||||
"share": {
|
||||
"notice": "Примечание: любой, кто имеет доступ к ссылке (и дополнительный пароль), может получить доступ к общим файлам. Вход в систему не требуется."
|
||||
},
|
||||
"api": {
|
||||
"title": "Ключи API:",
|
||||
"keyName": "Имя ключа API:",
|
||||
"createdAt": "Создан в:",
|
||||
"expiresAt": "Истекает в:",
|
||||
"permissions": "Разрешения:",
|
||||
"createTitle": "Создайте ключ API",
|
||||
"keyNamePlaceholder": "Введите уникальное имя ключа API:",
|
||||
"tokenDuration": "Длительность жетона:",
|
||||
"durationNumberPlaceholder": "Номер",
|
||||
"days": "Дни",
|
||||
"months": "Месяцы",
|
||||
"permissionNote": "Выберите хотя бы одно разрешение для ключа. Ваш пользователь также должен иметь это разрешение.",
|
||||
"createKeyFailed": "Не удалось создать ключ API.",
|
||||
"createKeySuccess": "Ключ API успешно создан.",
|
||||
"description": "Ключи API зависят от пользователя, который их создает. См.",
|
||||
"swaggerLinkText": "страница swagger",
|
||||
"name": "Имя",
|
||||
"created": "Создано",
|
||||
"expires": "Срок действия:",
|
||||
"actions": "Действия",
|
||||
"enabled": "Включено",
|
||||
"disabled": "Инвалид"
|
||||
},
|
||||
"index": {
|
||||
"status": "Статус",
|
||||
"assessment": "Оценка",
|
||||
"files": "Файлы",
|
||||
"folders": "Папки",
|
||||
"lastScanned": "Последнее сканирование",
|
||||
"quickScan": "Секунды быстрого сканирования",
|
||||
"fullScan": "Секунды полного сканирования",
|
||||
"settingsHover": "Настройки для пользователя",
|
||||
"logout": "Выход из системы",
|
||||
"toggleClick": "Переключение одним щелчком",
|
||||
"toggleDark": "Переключение темного режима",
|
||||
"toggleSticky": "Переключение режима липкости",
|
||||
"of": "из",
|
||||
"used": "используется"
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,9 @@
|
||||
"toggleSidebar": "Prepnúť sidebar",
|
||||
"update": "Aktualizovať",
|
||||
"upload": "Nahrať",
|
||||
"openFile": "Otvoriť súbor"
|
||||
"openFile": "Otvoriť súbor",
|
||||
"copyDownloadLinkToClipboard": "Skopírujte odkaz na stiahnutie do schránky",
|
||||
"continue": "Pokračovať"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Stiahnuť súbor",
|
||||
@@ -101,7 +103,7 @@
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "Swedish (Sweden)",
|
||||
"tr" : "Türkçe",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
@@ -116,7 +118,8 @@
|
||||
"submit": "Prihlásiť",
|
||||
"username": "Používateľské meno",
|
||||
"usernameTaken": "Meno je už obsadené",
|
||||
"wrongCredentials": "Nesprávne prihlasovacie údaje"
|
||||
"wrongCredentials": "Nesprávne prihlasovacie údaje",
|
||||
"or": "ALEBO"
|
||||
},
|
||||
"permanent": "Trvalé",
|
||||
"prompts": {
|
||||
@@ -132,7 +135,6 @@
|
||||
"downloadMessage": "Vyberte formát, ktorý chcete stiahnuť.",
|
||||
"error": "Niečo sa pokazilo",
|
||||
"fileInfo": "Informácie o súbore",
|
||||
"filesSelected": "{count} súborov vybratých.",
|
||||
"lastModified": "Dátum zmeny",
|
||||
"move": "Presunúť",
|
||||
"moveMessage": "Zvoľte nový domov pre vaše súbory/priečinky:",
|
||||
@@ -153,7 +155,12 @@
|
||||
"size": "Veľkosť",
|
||||
"upload": "Nahrať",
|
||||
"uploadMessage": "Zvoľte možnosť nahrávania.",
|
||||
"optionalPassword": "Voliteľné heslo"
|
||||
"optionalPassword": "Voliteľné heslo",
|
||||
"deleteUserMessage": "Ste si istí, že chcete odstrániť tohto používateľa?",
|
||||
"filesSelected": "vybrané súbory",
|
||||
"uploadFiles": "Uploading {files} files...",
|
||||
"typeName": "Typ:",
|
||||
"selected": "vybrané"
|
||||
},
|
||||
"search": {
|
||||
"images": "Obrázky",
|
||||
@@ -163,7 +170,12 @@
|
||||
"search": "Hľadať...",
|
||||
"typeToSearch": "Vyhľadáte písaním...",
|
||||
"types": "Typy",
|
||||
"video": "Video"
|
||||
"video": "Video",
|
||||
"path": "Cesta:",
|
||||
"smallerThan": "Menšie ako:",
|
||||
"largerThan": "Väčšie ako:",
|
||||
"helpText1": "Vyhľadávanie prebieha na základe každého zadaného znaku (minimálne 3 znaky pre hľadané výrazy).",
|
||||
"helpText2": "Index: Vyhľadávanie využíva index, ktorý sa automaticky aktualizuje v nastavenom intervale (predvolené: 5 minút). Vyhľadávanie, keď sa program práve spustil, môže viesť k neúplným výsledkom."
|
||||
},
|
||||
"settings": {
|
||||
"admin": "Admin",
|
||||
@@ -210,7 +222,10 @@
|
||||
"execute": "Vykonávať príkazy",
|
||||
"modify": "Upravovať súbory",
|
||||
"rename": "Premenovať a presúvať súbory a priečinky",
|
||||
"share": "Zdieľať súbory"
|
||||
"share": "Zdieľať súbory",
|
||||
"admin": "Správca",
|
||||
"api": "Vytváranie a správa kľúčov API s dlhou životnosťou",
|
||||
"realtime": "Povolenie pripojení a aktualizácií v reálnom čase"
|
||||
},
|
||||
"permissions-name": "Práva",
|
||||
"permissionsHelp": "Môžete nastaviť používateľa, aby bol administrátorom alebo vybrať práva jednotlivo. Ak zvolíte \"Administrator\", všetky ďalšie budú automaticky zaškrtnuté. Manažment používateľov ostáva v správe administrátora.\n",
|
||||
@@ -239,7 +254,32 @@
|
||||
"userManagement": "Správa používateľov",
|
||||
"userUpdated": "Používateľ upravený!",
|
||||
"username": "Meno používateľa",
|
||||
"users": "Používatelia"
|
||||
"users": "Používatelia",
|
||||
"loginMethod": "Spôsob prihlásenia",
|
||||
"modifyOtherUser": "Upravte používateľa:",
|
||||
"modifyCurrentUser": "Úprava aktuálneho používateľa",
|
||||
"themeColor": "Farba témy",
|
||||
"disableOfficePreviewDescription": "Medzerou oddelený zoznam prípon súborov, pre ktoré sa má prehliadač OnlyOffice vypnúť. (napr. \".txt .html\").",
|
||||
"disableOfficePreview": "Zakázať prehliadač OnlyOffice pre určité prípony súborov",
|
||||
"filePreviewOptions": "Možnosti náhľadu súborov",
|
||||
"listingOptions": "Možnosti uvedenia v zozname",
|
||||
"emptyGlobal": "V súčasnosti neexistujú žiadne globálne konfiguračné možnosti, Môžete upraviť konfiguračný yaml upraviť nastavenia systému.",
|
||||
"scopes": "Definovanie povolených zdrojov a používateľského rozsahu v rámci nich",
|
||||
"UserManagement": "Správa používateľov",
|
||||
"tusUploads": "Nahrávanie v častiach",
|
||||
"tusUploadsHelp": "Prehliadač súborov podporuje sekané odosielanie súborov, čo umožňuje vytvárať efektívne, spoľahlivé, obnoviteľné a sekané odosielanie súborov aj v nespoľahlivých sieťach.",
|
||||
"tusUploadsChunkSize": "Udáva maximálnu veľkosť požiadavky (pre menšie odoslania sa použije priame odoslanie). Môžete zadať obyčajné celé číslo označujúce vstup v bajtoch alebo reťazec, napríklad 10 MB, 1 GB atď.",
|
||||
"tusUploadsRetryCount": "Počet opakovaných pokusov, ktoré sa vykonajú, ak sa nepodarí nahrať časť.",
|
||||
"userHomeBasePath": "Základná cesta pre domovské adresáre používateľov",
|
||||
"userScopeGenerationPlaceholder": "Rozsah sa vygeneruje automaticky",
|
||||
"createUserHomeDirectory": "Vytvorenie domovského adresára používateľa",
|
||||
"api": "Kľúče API",
|
||||
"setDateFormat": "Nastavenie presného formátu dátumu",
|
||||
"loginMethodDescription": "povolená metóda prihlásenia pre používateľa.",
|
||||
"userNotAdmin": "Používateľ nie je správca",
|
||||
"enterPassword": "Zadajte heslo",
|
||||
"enterPasswordAgain": "Znovu zadajte heslo",
|
||||
"passwordsDoNotMatch": "Heslá sa nezhodujú"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Pomoc",
|
||||
@@ -252,7 +292,8 @@
|
||||
"preview": "Náhľad",
|
||||
"settings": "Nastavenia",
|
||||
"signup": "Registrovať",
|
||||
"siteSettings": "Nastavenia stránky"
|
||||
"siteSettings": "Nastavenia stránky",
|
||||
"sources": "Zdroje"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Odkaz skopírovaný!"
|
||||
@@ -263,5 +304,51 @@
|
||||
"minutes": "Minúty",
|
||||
"seconds": "Sekundy",
|
||||
"unit": "Jednotka času"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Ste si istí, že chcete prerušiť tehotenstvo?"
|
||||
},
|
||||
"share": {
|
||||
"notice": "Poznámka: prístup k zdieľaným súborom má každý, kto má prístup k odkazu (a voliteľnému heslu). Nie je potrebné byť prihlásený."
|
||||
},
|
||||
"api": {
|
||||
"title": "Kľúče API:",
|
||||
"keyName": "Názov kľúča API:",
|
||||
"createdAt": "Vytvorené v:",
|
||||
"expiresAt": "Platnosť končí na:",
|
||||
"permissions": "Oprávnenia:",
|
||||
"createTitle": "Vytvorenie kľúča API",
|
||||
"keyNamePlaceholder": "Zadajte jedinečný názov kľúča API:",
|
||||
"tokenDuration": "Trvanie žetónu:",
|
||||
"durationNumberPlaceholder": "Číslo",
|
||||
"days": "Dni",
|
||||
"months": "Mesiace",
|
||||
"permissionNote": "Vyberte aspoň jedno povolenie pre kľúč. Oprávnenie musí mať aj váš používateľ.",
|
||||
"createKeyFailed": "Nepodarilo sa vytvoriť kľúč API.",
|
||||
"createKeySuccess": "Kľúč API bol úspešne vytvorený.",
|
||||
"description": "Kľúče API sú založené na používateľovi, ktorý ich vytvoril. Pozri .",
|
||||
"swaggerLinkText": "swagger stránka",
|
||||
"name": "Názov",
|
||||
"created": "Vytvorené",
|
||||
"expires": "Platnosť končí na",
|
||||
"actions": "Činnosti",
|
||||
"enabled": "Povolené",
|
||||
"disabled": "Bezbariérový"
|
||||
},
|
||||
"index": {
|
||||
"status": "Stav",
|
||||
"assessment": "Hodnotenie",
|
||||
"files": "Súbory",
|
||||
"folders": "Priečinky",
|
||||
"lastScanned": "Posledné skenovanie",
|
||||
"quickScan": "Sekundy rýchleho skenovania",
|
||||
"fullScan": "Sekundy úplného skenovania",
|
||||
"settingsHover": "Nastavenia pre používateľa",
|
||||
"logout": "Odhlásenie",
|
||||
"toggleClick": "Prepínanie jedným kliknutím",
|
||||
"toggleDark": "Prepínanie tmavého režimu",
|
||||
"toggleSticky": "Prepnutie režimu Sticky",
|
||||
"of": "z",
|
||||
"used": "použité"
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,7 @@
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "",
|
||||
"tr" : "Türkçe",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
@@ -125,7 +125,6 @@
|
||||
"downloadMessage": "Välj format på det du vill lada ner.",
|
||||
"error": "Något gick fel",
|
||||
"fileInfo": "Fil information",
|
||||
"filesSelected": "{count} filer valda.",
|
||||
"lastModified": "Senast ändrad",
|
||||
"move": "Flytta",
|
||||
"moveMessage": "Välj ny plats för din fil (er)/mapp (ar):",
|
||||
@@ -145,7 +144,8 @@
|
||||
"show": "Visa",
|
||||
"size": "Storlek",
|
||||
"upload": "",
|
||||
"uploadMessage": ""
|
||||
"uploadMessage": "",
|
||||
"deleteMessageShare": "Are you sure you want to delete this share: {path} ?"
|
||||
},
|
||||
"search": {
|
||||
"images": "Bilder",
|
||||
@@ -254,5 +254,9 @@
|
||||
"minutes": "Minuter",
|
||||
"seconds": "Sekunder",
|
||||
"unit": "Tidsenhet"
|
||||
}
|
||||
},
|
||||
"upload": {},
|
||||
"share": {},
|
||||
"api": {},
|
||||
"index": {}
|
||||
}
|
||||
@@ -33,7 +33,11 @@
|
||||
"toggleSidebar": "Menüyü aç/kapat",
|
||||
"update": "Güncelle",
|
||||
"upload": "Yükle",
|
||||
"openFile": "Dosyayı aç"
|
||||
"openFile": "Dosyayı aç",
|
||||
"copyDownloadLinkToClipboard": "İndirme bağlantısını panoya kopyala",
|
||||
"file": "Dosya",
|
||||
"folder": "Klasör",
|
||||
"continue": "Devam et"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Dosyayı indir",
|
||||
@@ -99,7 +103,7 @@
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "Swedish (Sweden)",
|
||||
"tr" : "Türkçe",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
@@ -114,7 +118,8 @@
|
||||
"submit": "Giriş",
|
||||
"username": "Kullanıcı adı",
|
||||
"usernameTaken": "Kullanıcı adı mevcut",
|
||||
"wrongCredentials": "Yanlış hesap bilgileri"
|
||||
"wrongCredentials": "Yanlış hesap bilgileri",
|
||||
"or": "VEYA"
|
||||
},
|
||||
"permanent": "Kalıcı",
|
||||
"prompts": {
|
||||
@@ -130,7 +135,6 @@
|
||||
"downloadMessage": "İndirmek istediğiniz formatı seçin.",
|
||||
"error": "Bir şeyler yanlış gitti",
|
||||
"fileInfo": "Dosya bilgisi",
|
||||
"filesSelected": "{count} dosya seçildi.",
|
||||
"lastModified": "Son güncellenme",
|
||||
"move": "Taşı",
|
||||
"moveMessage": "Dosya(lar)ınız/klasör(ler)iniz için yeni ana dizin seçin:",
|
||||
@@ -151,7 +155,12 @@
|
||||
"size": "Boyut",
|
||||
"upload": "Gönder",
|
||||
"uploadMessage": "Yüklemek için bir seçenek belirleyin.",
|
||||
"optionalPassword": "İsteğe bağlı şifre"
|
||||
"optionalPassword": "İsteğe bağlı şifre",
|
||||
"deleteUserMessage": "Bu kullanıcıyı silmek istediğinizden emin misiniz?",
|
||||
"filesSelected": "seçilen dosyalar",
|
||||
"uploadFiles": "Uploading {files} files...",
|
||||
"typeName": "Tip:",
|
||||
"selected": "seçilmiş"
|
||||
},
|
||||
"search": {
|
||||
"images": "Görseller",
|
||||
@@ -161,7 +170,12 @@
|
||||
"search": "Ara...",
|
||||
"typeToSearch": "Aramak için yazın...",
|
||||
"types": "Türler",
|
||||
"video": "Video"
|
||||
"video": "Video",
|
||||
"path": "Yol:",
|
||||
"smallerThan": "Daha küçük:",
|
||||
"largerThan": "Daha büyük:",
|
||||
"helpText1": "Arama, yazdığınız her karakterde gerçekleşir (arama terimleri için minimum 3 karakter).",
|
||||
"helpText2": "Dizin: Arama, yapılandırılan aralıkta (varsayılan: 5 dakika) otomatik olarak güncellenen dizini kullanır. Program yeni başladığında arama yapmak eksik sonuçlara neden olabilir."
|
||||
},
|
||||
"settings": {
|
||||
"admin": "Yönetim",
|
||||
@@ -208,7 +222,10 @@
|
||||
"execute": "Komutları çalıştır",
|
||||
"modify": "Dosyaları değiştir",
|
||||
"rename": "Dosyaları ve dizinleri yeniden adlandırın veya taşıyın",
|
||||
"share": "Dosyaları paylaş"
|
||||
"share": "Dosyaları paylaş",
|
||||
"admin": "Yönetici",
|
||||
"api": "Uzun ömürlü API anahtarları oluşturma ve yönetme",
|
||||
"realtime": "Gerçek zamanlı bağlantıları ve güncellemeleri etkinleştirin"
|
||||
},
|
||||
"permissions-name": "İzinler",
|
||||
"permissionsHelp": "Kullanıcıyı yönetici olarak ayarlayabilir veya izinleri ayrı ayrı seçebilirsiniz. \"Yönetici\"yi seçerseniz, diğer tüm seçenekler otomatik olarak kontrol edilecektir. Kullanıcıların yönetimi, bir yöneticinin yetkisi olarak kalır.\n",
|
||||
@@ -237,7 +254,32 @@
|
||||
"userManagement": "Kullanıcı yönetimi",
|
||||
"userUpdated": "Kullanıcı güncellendi!",
|
||||
"username": "Kullanıcı adı",
|
||||
"users": "Kullanıcılar"
|
||||
"users": "Kullanıcılar",
|
||||
"loginMethod": "Giriş yöntemi",
|
||||
"modifyOtherUser": "Kullanıcıyı değiştir:",
|
||||
"modifyCurrentUser": "Geçerli kullanıcıyı değiştir",
|
||||
"themeColor": "Tema Rengi",
|
||||
"disableOfficePreviewDescription": "OnlyOffice görüntüleyicisinin devre dışı bırakılacağı dosya uzantılarının boşluk bırakılarak ayrılmış bir listesi. (örneğin, '.txt .html').",
|
||||
"disableOfficePreview": "Belirli dosya uzantıları için onlyoffice görüntüleyiciyi devre dışı bırakma",
|
||||
"filePreviewOptions": "Dosya önizleme seçenekleri",
|
||||
"listingOptions": "Listeleme seçenekleri",
|
||||
"emptyGlobal": "Şu anda global yapılandırma seçenekleri yoktur, sistem ayarlarını yapmak için yapılandırma yaml'ını düzenleyebilirsiniz.",
|
||||
"scopes": "İzin verilen kaynakları ve bunlar içindeki kullanıcı kapsamını tanımlama",
|
||||
"UserManagement": "Kullanıcı Yönetimi",
|
||||
"tusUploads": "Yığınlanmış Yüklemeler",
|
||||
"tusUploadsHelp": "File Browser, parçalı dosya yüklemelerini destekleyerek güvenilir olmayan ağlarda bile verimli, güvenilir, yeniden başlatılabilir ve parçalı dosya yüklemelerinin oluşturulmasına olanak tanır.",
|
||||
"tusUploadsChunkSize": "Bir isteğin maksimum boyutunu belirtir (daha küçük yüklemeler için doğrudan yüklemeler kullanılacaktır). Bayt girişini belirten düz bir tamsayı veya 10MB, 1GB vb. gibi bir dize girebilirsiniz.",
|
||||
"tusUploadsRetryCount": "Bir yığının yüklenememesi durumunda gerçekleştirilecek yeniden deneme sayısı.",
|
||||
"userHomeBasePath": "Kullanıcı ev dizinleri için temel yol",
|
||||
"userScopeGenerationPlaceholder": "Kapsam otomatik olarak oluşturulacaktır",
|
||||
"createUserHomeDirectory": "Kullanıcı ev dizini oluşturma",
|
||||
"api": "API Anahtarları",
|
||||
"setDateFormat": "Tam tarih biçimini ayarlama",
|
||||
"loginMethodDescription": "kullanıcı için izin verilen oturum açma yöntemi.",
|
||||
"userNotAdmin": "Kullanıcı yönetici değil",
|
||||
"enterPassword": "Şifre girin",
|
||||
"enterPasswordAgain": "Şifreyi tekrar girin",
|
||||
"passwordsDoNotMatch": "Parolalar eşleşmiyor"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Yardım",
|
||||
@@ -250,7 +292,8 @@
|
||||
"preview": "Önizleme",
|
||||
"settings": "Ayarlar",
|
||||
"signup": "Kayıt",
|
||||
"siteSettings": "Site ayarları!"
|
||||
"siteSettings": "Site ayarları!",
|
||||
"sources": "Kaynaklar"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Link kopyalandı!"
|
||||
@@ -261,5 +304,51 @@
|
||||
"minutes": "Dakika",
|
||||
"seconds": "Saniye",
|
||||
"unit": "Zaman birimi"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Aldırmak istediğine emin misin?"
|
||||
},
|
||||
"share": {
|
||||
"notice": "Not: Bağlantıya (ve isteğe bağlı şifreye) erişimi olan herkes paylaşılan dosyalara erişebilir. Oturum açma zorunluluğu yoktur."
|
||||
},
|
||||
"api": {
|
||||
"title": "API Anahtarları:",
|
||||
"keyName": "API Anahtar Adı:",
|
||||
"createdAt": "Oluşturuldu:",
|
||||
"expiresAt": "Son kullanma tarihi:",
|
||||
"permissions": "İzinler:",
|
||||
"createTitle": "API Anahtarı Oluşturma",
|
||||
"keyNamePlaceholder": "Benzersiz bir API anahtar adı girin:",
|
||||
"tokenDuration": "Token Süresi:",
|
||||
"durationNumberPlaceholder": "Sayı",
|
||||
"days": "Günler",
|
||||
"months": "Aylar",
|
||||
"permissionNote": "Anahtar için en az bir izin seçin. Kullanıcınız da bu izne sahip olmalıdır.",
|
||||
"createKeyFailed": "API anahtarı oluşturulamadı.",
|
||||
"createKeySuccess": "API anahtarı başarıyla oluşturuldu.",
|
||||
"description": "API anahtarları, onları oluşturan kullanıcıyı temel alır. Bkz.",
|
||||
"swaggerLinkText": "swagger sayfası",
|
||||
"name": "İsim",
|
||||
"created": "Oluşturuldu",
|
||||
"expires": "Sona erdi",
|
||||
"actions": "Eylemler",
|
||||
"enabled": "Etkin",
|
||||
"disabled": "Engelli"
|
||||
},
|
||||
"index": {
|
||||
"status": "Durum",
|
||||
"assessment": "Değerlendirme",
|
||||
"files": "Dosyalar",
|
||||
"folders": "Klasörler",
|
||||
"lastScanned": "Son Taranan",
|
||||
"quickScan": "Hızlı Tarama Saniyeleri",
|
||||
"fullScan": "Tam Tarama Saniyeleri",
|
||||
"settingsHover": "Kullanıcı Ayarları",
|
||||
"logout": "Oturum Kapatma",
|
||||
"toggleClick": "Tek Tıklamayı Değiştir",
|
||||
"toggleDark": "Karanlık Modu Aç / Kapat",
|
||||
"toggleSticky": "Yapışkan Modunu Değiştir",
|
||||
"of": ".",
|
||||
"used": "kullanılmış"
|
||||
}
|
||||
}
|
||||
+266
-263
@@ -1,268 +1,271 @@
|
||||
{
|
||||
"buttons": {
|
||||
"cancel": "Відмінити",
|
||||
"close": "Закрити",
|
||||
"copy": "Копіювати",
|
||||
"copyFile": "Копіювати файл",
|
||||
"copyToClipboard": "Копіювати в буфер обміну",
|
||||
"create": "Створити",
|
||||
"delete": "Видалити",
|
||||
"download": "Завантажити",
|
||||
"file": "Файл",
|
||||
"folder": "Папка",
|
||||
"info": "Інфо",
|
||||
"more": "Більше",
|
||||
"move": "Перемістити",
|
||||
"moveFile": "Перемістити файл",
|
||||
"new": "Новий",
|
||||
"next": "Далі",
|
||||
"ok": "ОК",
|
||||
"permalink": "Отримати постійне посилання",
|
||||
"previous": "Назад",
|
||||
"publish": "Опублікувати",
|
||||
"rename": "Перейменувати",
|
||||
"replace": "Замінити",
|
||||
"reportIssue": "Повідомити про помилку",
|
||||
"save": "Зберегти",
|
||||
"schedule": "Планування",
|
||||
"search": "Пошук",
|
||||
"select": "Вибрати",
|
||||
"selectMultiple": "Мультивибір",
|
||||
"share": "Поділитися",
|
||||
"shell": "Командний рядок",
|
||||
"submit": "Відправити",
|
||||
"switchView": "Вид",
|
||||
"toggleSidebar": "Бічна панель",
|
||||
"update": "Оновити",
|
||||
"upload": "Завантажити",
|
||||
"openFile": "Відкрити файл"
|
||||
"buttons": {
|
||||
"cancel": "Відмінити",
|
||||
"close": "Закрити",
|
||||
"copy": "Копіювати",
|
||||
"copyFile": "Копіювати файл",
|
||||
"copyToClipboard": "Копіювати в буфер обміну",
|
||||
"create": "Створити",
|
||||
"delete": "Видалити",
|
||||
"download": "Завантажити",
|
||||
"file": "Файл",
|
||||
"folder": "Папка",
|
||||
"info": "Інфо",
|
||||
"more": "Більше",
|
||||
"move": "Перемістити",
|
||||
"moveFile": "Перемістити файл",
|
||||
"new": "Новий",
|
||||
"next": "Далі",
|
||||
"ok": "ОК",
|
||||
"permalink": "Отримати постійне посилання",
|
||||
"previous": "Назад",
|
||||
"publish": "Опублікувати",
|
||||
"rename": "Перейменувати",
|
||||
"replace": "Замінити",
|
||||
"reportIssue": "Повідомити про помилку",
|
||||
"save": "Зберегти",
|
||||
"schedule": "Планування",
|
||||
"search": "Пошук",
|
||||
"select": "Вибрати",
|
||||
"selectMultiple": "Мультивибір",
|
||||
"share": "Поділитися",
|
||||
"shell": "Командний рядок",
|
||||
"submit": "Відправити",
|
||||
"switchView": "Вид",
|
||||
"toggleSidebar": "Бічна панель",
|
||||
"update": "Оновити",
|
||||
"upload": "Завантажити",
|
||||
"openFile": "Відкрити файл"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Завантажити файл",
|
||||
"downloadFolder": "Завантажити папку",
|
||||
"downloadSelected": "Завантажити вибране"
|
||||
},
|
||||
"errors": {
|
||||
"forbidden": "У вас немає прав доступу до цього.",
|
||||
"internal": "Щось пішло не так.",
|
||||
"notFound": "Неправильне посилання.",
|
||||
"connection": "Немає підключення до сервера."
|
||||
},
|
||||
"files": {
|
||||
"body": "Тіло",
|
||||
"clear": "Очистити",
|
||||
"closePreview": "Закрити",
|
||||
"files": "Файли",
|
||||
"folders": "Папки",
|
||||
"home": "Домівка",
|
||||
"lastModified": "Останній раз змінено",
|
||||
"loading": "Завантаження...",
|
||||
"lonely": "Тут пусто...",
|
||||
"metadata": "Метадані",
|
||||
"multipleSelectionEnabled": "Мультивибір включений",
|
||||
"name": "Ім'я",
|
||||
"size": "Розмір",
|
||||
"sortByLastModified": "Сортувати за останнім зміненням",
|
||||
"sortByName": "Сортувати за іменем",
|
||||
"sortBySize": "Сортувати за розміром",
|
||||
"noPreview": "Попередній перегляд для цього файлу недоступний."
|
||||
},
|
||||
"help": {
|
||||
"click": "вибрати файл чи каталог",
|
||||
"ctrl": {
|
||||
"click": "вибрати кілька файлів чи каталогів",
|
||||
"f": "відкрити пошук",
|
||||
"s": "скачати файл або поточний каталог"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Завантажити файл",
|
||||
"downloadFolder": "Завантажити папку",
|
||||
"downloadSelected": "Завантажити вибране"
|
||||
"del": "видалити вибрані елементи",
|
||||
"doubleClick": "відкрити файл чи каталог",
|
||||
"esc": "очистити виділення та/або закрити вікно",
|
||||
"f1": "допомога",
|
||||
"f2": "перейменувати файл",
|
||||
"help": "Допомога"
|
||||
},
|
||||
"languages": {
|
||||
"he": "עברית",
|
||||
"hu": "Magyar",
|
||||
"ar": "العربية",
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"is": "Icelandic",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"ko": "한국어",
|
||||
"nlBE": "Dutch (Belgium)",
|
||||
"pl": "Polski",
|
||||
"pt": "Português",
|
||||
"ptBR": "Português (Brasil)",
|
||||
"ro": "Romanian",
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "Swedish (Sweden)",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
},
|
||||
"login": {
|
||||
"createAnAccount": "Створити обліковий запис",
|
||||
"loginInstead": "Вже є обліковий запис",
|
||||
"password": "Пароль",
|
||||
"passwordConfirm": "Підтвердження паролю",
|
||||
"passwordsDontMatch": "Паролі не співпадають",
|
||||
"signup": "Зареєструватися",
|
||||
"submit": "Увійти",
|
||||
"username": "Ім'я користувача",
|
||||
"usernameTaken": "Ім'я користувача вже використовується",
|
||||
"wrongCredentials": "Невірне ім'я користувача або пароль"
|
||||
},
|
||||
"permanent": "Постійний",
|
||||
"prompts": {
|
||||
"copy": "Копіювати",
|
||||
"copyMessage": "Копіювати в:",
|
||||
"currentlyNavigating": "Поточний каталог:",
|
||||
"deleteMessageMultiple": "Видалити ці файли ({count})?",
|
||||
"deleteMessageSingle": "Видалити цей файл/каталог?",
|
||||
"deleteMessageShare": "Видалити цей спільний файл/каталог ({path})?",
|
||||
"deleteTitle": "Видалити файлы",
|
||||
"displayName": "Відображене ім'я:",
|
||||
"download": "Завантажити файлы",
|
||||
"downloadMessage": "Виберіть формат, в якому хочете завантажити.",
|
||||
"error": "Помилка",
|
||||
"fileInfo": "Інформація про файл",
|
||||
"lastModified": "Останній раз змінено",
|
||||
"move": "Перемістити",
|
||||
"moveMessage": "Перемістити в:",
|
||||
"newArchetype": "Створіть новий запис на основі архетипу. Файл буде створено у каталозі.",
|
||||
"newDir": "Новий каталог",
|
||||
"newDirMessage": "Ім'я нового каталогу.",
|
||||
"newFile": "Новий файл",
|
||||
"newFileMessage": "Ім'я нового файлу.",
|
||||
"numberDirs": "Кількість каталогів",
|
||||
"numberFiles": "Кількість файлів",
|
||||
"rename": "Перейменувати",
|
||||
"renameMessage": "Нове ім'я",
|
||||
"replace": "Замінити",
|
||||
"replaceMessage": "Ім'я одного з файлів, що завантажуються, збігається з вже існуючим файлом. Ви бажаєте замінити існуючий?\n",
|
||||
"schedule": "Планування",
|
||||
"scheduleMessage": "Запланувати дату та час публікації.",
|
||||
"show": "Показати",
|
||||
"size": "Розмір",
|
||||
"upload": "Завантажити",
|
||||
"uploadMessage": "Виберіть варіант для завантаження.",
|
||||
"optionalPassword": "Необов'язковий пароль"
|
||||
},
|
||||
"search": {
|
||||
"images": "Зображення",
|
||||
"music": "Музика",
|
||||
"pdf": "PDF",
|
||||
"pressToSearch": "Натисніть ENTER для пошуку",
|
||||
"search": "Пошук...",
|
||||
"typeToSearch": "Введіть ім'я файлу...",
|
||||
"types": "Типи",
|
||||
"video": "Відео"
|
||||
},
|
||||
"settings": {
|
||||
"admin": "Адмін",
|
||||
"administrator": "Адміністратор",
|
||||
"allowCommands": "Запуск команд",
|
||||
"allowEdit": "Редагування, перейменування та видалення файлів чи каталогів",
|
||||
"allowNew": "Створення нових файлів або каталогів",
|
||||
"allowPublish": "Публікація нових записів та сторінок",
|
||||
"allowSignup": "Дозволити користувачам реєструватися",
|
||||
"avoidChanges": "(залишіть поле порожнім, щоб уникнути змін)",
|
||||
"branding": "Брендинг",
|
||||
"brandingDirectoryPath": "Шлях до каталогу брендів",
|
||||
"brandingHelp": "Ви можете налаштувати зовнішній вигляд файлового браузера, змінивши його ім'я, замінивши логотип, додавши власні стилі та навіть відключивши зовнішні посилання на GitHub.\nДодаткову інформацію про персоналізований брендинг можна знайти на сторінці {0}.",
|
||||
"changePassword": "Зміна пароля",
|
||||
"commandRunner": "Запуск команд",
|
||||
"commandRunnerHelp": "Тут ви можете встановити команди, які будуть виконуватися у зазначених подіях. Ви повинні вказати по одній команді в кожному рядку. Змінні середовища {0} та {1} будуть доступні, будучи {0} щодо {1}. Додаткові відомості про цю функцію та доступні змінні середовища див. у {2}.",
|
||||
"commandsUpdated": "Команди оновлені!",
|
||||
"createUserDir": "Автоматичне створення домашнього каталогу користувача при додаванні нового користувача",
|
||||
"customStylesheet": "Свій стиль",
|
||||
"defaultUserDescription": "Це налаштування за замовчуванням для нових користувачів.",
|
||||
"disableExternalLinks": "Вимкнути зовнішні посилання (крім документації)",
|
||||
"disableUsedDiskPercentage": "Disable used disk percentage graph",
|
||||
"documentation": "документація",
|
||||
"examples": "Приклади",
|
||||
"executeOnShell": "Виконати в командному рядку",
|
||||
"executeOnShellDescription": "За замовчуванням File Browser виконує команди, безпосередньо викликаючи їх бінарні файли. Якщо ви хочете замість цього запускати їх в оболонці (наприклад, Bash або PowerShell), ви можете визначити їх тут з необхідними аргументами та прапорами. Якщо встановлено, виконуєма вами команда буде додана як аргумент. Це стосується як користувацьких команд, так і обробників подій.",
|
||||
"globalRules": "Це глобальний набір дозволяючих та забороняючих правил. Вони застосовні до кожного користувача. Ви можете визначити певні правила для налаштувань кожного користувача, щоб перевизначити їх.",
|
||||
"globalSettings": "Глобальні налаштування",
|
||||
"insertPath": "Вставте шлях",
|
||||
"insertRegex": "Вставити регулярний вираз",
|
||||
"instanceName": "Поточна назва програми",
|
||||
"language": "Мова",
|
||||
"lockPassword": "Заборонити користувачеві змінювати пароль",
|
||||
"newPassword": "Новий пароль",
|
||||
"newPasswordConfirm": "Підтвердження нового пароля",
|
||||
"newUser": "Новий користувач",
|
||||
"password": "Пароль",
|
||||
"passwordUpdated": "Пароль оновлено!",
|
||||
"path": "Шлях",
|
||||
"permissions": {
|
||||
"create": "Створювати файли та каталоги",
|
||||
"delete": "Видаляти файли та каталоги",
|
||||
"download": "Завантажувати",
|
||||
"execute": "Виконувати команди",
|
||||
"modify": "Редагувати файли",
|
||||
"rename": "Перейменовувати або переміщувати файли та каталоги",
|
||||
"share": "Ділітися файлами"
|
||||
},
|
||||
"errors": {
|
||||
"forbidden": "У вас немає прав доступу до цього.",
|
||||
"internal": "Щось пішло не так.",
|
||||
"notFound": "Неправильне посилання.",
|
||||
"connection": "Немає підключення до сервера."
|
||||
"permissions-name": "Дозволи",
|
||||
"permissionsHelp": "Можна настроїти користувача як адміністратора або вибрати індивідуальні дозволи. При виборі \"Адміністратор\" всі інші параметри будуть автоматично вибрані. Керування користувачами - привілей адміністратора.\n",
|
||||
"profileSettings": "Налаштування профілю",
|
||||
"ruleExample1": "запобігти доступу до будь-якого прихованого файлу (наприклад: .git, .gitignore) у кожній папці.\n",
|
||||
"ruleExample2": "блокує доступ до файлу з ім'ям Caddyfile у кореневій області.",
|
||||
"rules": "Права",
|
||||
"rulesHelp": "Тут ви можете визначити набір дозволяючих та забороняючих правил для цього конкретного користувача. Блоковані файли не відображатимуться у списках, і не будуть доступні для користувача. Є підтримка регулярних виразів та відносних шляхів.\n",
|
||||
"scope": "Корінь",
|
||||
"setDateFormat": "Встановити точний формат дати",
|
||||
"settingsUpdated": "Налаштування застосовані!",
|
||||
"shareDuration": "Тривалість спільного посилання",
|
||||
"shareManagement": "Управління спільними посиланнями",
|
||||
"shareDeleted": "Спільне посилання видалено!",
|
||||
"singleClick": "Відкриття файлів та каталогів одним кліком",
|
||||
"themes": {
|
||||
"dark": "Темна",
|
||||
"light": "Світла",
|
||||
"title": "Тема"
|
||||
},
|
||||
"files": {
|
||||
"body": "Тіло",
|
||||
"clear": "Очистити",
|
||||
"closePreview": "Закрити",
|
||||
"files": "Файли",
|
||||
"folders": "Папки",
|
||||
"home": "Домівка",
|
||||
"lastModified": "Останній раз змінено",
|
||||
"loading": "Завантаження...",
|
||||
"lonely": "Тут пусто...",
|
||||
"metadata": "Метадані",
|
||||
"multipleSelectionEnabled": "Мультивибір включений",
|
||||
"name": "Ім'я",
|
||||
"size": "Розмір",
|
||||
"sortByLastModified": "Сортувати за останнім зміненням",
|
||||
"sortByName": "Сортувати за іменем",
|
||||
"sortBySize": "Сортувати за розміром",
|
||||
"noPreview": "Попередній перегляд для цього файлу недоступний."
|
||||
},
|
||||
"help": {
|
||||
"click": "вибрати файл чи каталог",
|
||||
"ctrl": {
|
||||
"click": "вибрати кілька файлів чи каталогів",
|
||||
"f": "відкрити пошук",
|
||||
"s": "скачати файл або поточний каталог"
|
||||
},
|
||||
"del": "видалити вибрані елементи",
|
||||
"doubleClick": "відкрити файл чи каталог",
|
||||
"esc": "очистити виділення та/або закрити вікно",
|
||||
"f1": "допомога",
|
||||
"f2": "перейменувати файл",
|
||||
"help": "Допомога"
|
||||
},
|
||||
"languages": {
|
||||
"he": "עברית",
|
||||
"hu": "Magyar",
|
||||
"ar": "العربية",
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"is": "Icelandic",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"ko": "한국어",
|
||||
"nlBE": "Dutch (Belgium)",
|
||||
"pl": "Polski",
|
||||
"pt": "Português",
|
||||
"ptBR": "Português (Brasil)",
|
||||
"ro": "Romanian",
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "Swedish (Sweden)",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
},
|
||||
"login": {
|
||||
"createAnAccount": "Створити обліковий запис",
|
||||
"loginInstead": "Вже є обліковий запис",
|
||||
"password": "Пароль",
|
||||
"passwordConfirm": "Підтвердження паролю",
|
||||
"passwordsDontMatch": "Паролі не співпадають",
|
||||
"signup": "Зареєструватися",
|
||||
"submit": "Увійти",
|
||||
"username": "Ім'я користувача",
|
||||
"usernameTaken": "Ім'я користувача вже використовується",
|
||||
"wrongCredentials": "Невірне ім'я користувача або пароль"
|
||||
},
|
||||
"permanent": "Постійний",
|
||||
"prompts": {
|
||||
"copy": "Копіювати",
|
||||
"copyMessage": "Копіювати в:",
|
||||
"currentlyNavigating": "Поточний каталог:",
|
||||
"deleteMessageMultiple": "Видалити ці файли ({count})?",
|
||||
"deleteMessageSingle": "Видалити цей файл/каталог?",
|
||||
"deleteMessageShare": "Видалити цей спільний файл/каталог ({path})?",
|
||||
"deleteTitle": "Видалити файлы",
|
||||
"displayName": "Відображене ім'я:",
|
||||
"download": "Завантажити файлы",
|
||||
"downloadMessage": "Виберіть формат, в якому хочете завантажити.",
|
||||
"error": "Помилка",
|
||||
"fileInfo": "Інформація про файл",
|
||||
"filesSelected": "Файлів вибрано: {count}.",
|
||||
"lastModified": "Останній раз змінено",
|
||||
"move": "Перемістити",
|
||||
"moveMessage": "Перемістити в:",
|
||||
"newArchetype": "Створіть новий запис на основі архетипу. Файл буде створено у каталозі.",
|
||||
"newDir": "Новий каталог",
|
||||
"newDirMessage": "Ім'я нового каталогу.",
|
||||
"newFile": "Новий файл",
|
||||
"newFileMessage": "Ім'я нового файлу.",
|
||||
"numberDirs": "Кількість каталогів",
|
||||
"numberFiles": "Кількість файлів",
|
||||
"rename": "Перейменувати",
|
||||
"renameMessage": "Нове ім'я",
|
||||
"replace": "Замінити",
|
||||
"replaceMessage": "Ім'я одного з файлів, що завантажуються, збігається з вже існуючим файлом. Ви бажаєте замінити існуючий?\n",
|
||||
"schedule": "Планування",
|
||||
"scheduleMessage": "Запланувати дату та час публікації.",
|
||||
"show": "Показати",
|
||||
"size": "Розмір",
|
||||
"upload": "Завантажити",
|
||||
"uploadMessage": "Виберіть варіант для завантаження.",
|
||||
"optionalPassword": "Необов'язковий пароль"
|
||||
},
|
||||
"search": {
|
||||
"images": "Зображення",
|
||||
"music": "Музика",
|
||||
"pdf": "PDF",
|
||||
"pressToSearch": "Натисніть ENTER для пошуку",
|
||||
"search": "Пошук...",
|
||||
"typeToSearch": "Введіть ім'я файлу...",
|
||||
"types": "Типи",
|
||||
"video": "Відео"
|
||||
},
|
||||
"settings": {
|
||||
"admin": "Адмін",
|
||||
"administrator": "Адміністратор",
|
||||
"allowCommands": "Запуск команд",
|
||||
"allowEdit": "Редагування, перейменування та видалення файлів чи каталогів",
|
||||
"allowNew": "Створення нових файлів або каталогів",
|
||||
"allowPublish": "Публікація нових записів та сторінок",
|
||||
"allowSignup": "Дозволити користувачам реєструватися",
|
||||
"avoidChanges": "(залишіть поле порожнім, щоб уникнути змін)",
|
||||
"branding": "Брендинг",
|
||||
"brandingDirectoryPath": "Шлях до каталогу брендів",
|
||||
"brandingHelp": "Ви можете налаштувати зовнішній вигляд файлового браузера, змінивши його ім'я, замінивши логотип, додавши власні стилі та навіть відключивши зовнішні посилання на GitHub.\nДодаткову інформацію про персоналізований брендинг можна знайти на сторінці {0}.",
|
||||
"changePassword": "Зміна пароля",
|
||||
"commandRunner": "Запуск команд",
|
||||
"commandRunnerHelp": "Тут ви можете встановити команди, які будуть виконуватися у зазначених подіях. Ви повинні вказати по одній команді в кожному рядку. Змінні середовища {0} та {1} будуть доступні, будучи {0} щодо {1}. Додаткові відомості про цю функцію та доступні змінні середовища див. у {2}.",
|
||||
"commandsUpdated": "Команди оновлені!",
|
||||
"createUserDir": "Автоматичне створення домашнього каталогу користувача при додаванні нового користувача",
|
||||
"customStylesheet": "Свій стиль",
|
||||
"defaultUserDescription": "Це налаштування за замовчуванням для нових користувачів.",
|
||||
"disableExternalLinks": "Вимкнути зовнішні посилання (крім документації)",
|
||||
"disableUsedDiskPercentage": "Disable used disk percentage graph",
|
||||
"documentation": "документація",
|
||||
"examples": "Приклади",
|
||||
"executeOnShell": "Виконати в командному рядку",
|
||||
"executeOnShellDescription": "За замовчуванням File Browser виконує команди, безпосередньо викликаючи їх бінарні файли. Якщо ви хочете замість цього запускати їх в оболонці (наприклад, Bash або PowerShell), ви можете визначити їх тут з необхідними аргументами та прапорами. Якщо встановлено, виконуєма вами команда буде додана як аргумент. Це стосується як користувацьких команд, так і обробників подій.",
|
||||
"globalRules": "Це глобальний набір дозволяючих та забороняючих правил. Вони застосовні до кожного користувача. Ви можете визначити певні правила для налаштувань кожного користувача, щоб перевизначити їх.",
|
||||
"globalSettings": "Глобальні налаштування",
|
||||
"insertPath": "Вставте шлях",
|
||||
"insertRegex": "Вставити регулярний вираз",
|
||||
"instanceName": "Поточна назва програми",
|
||||
"language": "Мова",
|
||||
"lockPassword": "Заборонити користувачеві змінювати пароль",
|
||||
"newPassword": "Новий пароль",
|
||||
"newPasswordConfirm": "Підтвердження нового пароля",
|
||||
"newUser": "Новий користувач",
|
||||
"password": "Пароль",
|
||||
"passwordUpdated": "Пароль оновлено!",
|
||||
"path": "Шлях",
|
||||
"permissions": {
|
||||
"create": "Створювати файли та каталоги",
|
||||
"delete": "Видаляти файли та каталоги",
|
||||
"download": "Завантажувати",
|
||||
"execute": "Виконувати команди",
|
||||
"modify": "Редагувати файли",
|
||||
"rename": "Перейменовувати або переміщувати файли та каталоги",
|
||||
"share": "Ділітися файлами"
|
||||
},
|
||||
"permissions-name": "Дозволи",
|
||||
"permissionsHelp": "Можна настроїти користувача як адміністратора або вибрати індивідуальні дозволи. При виборі \"Адміністратор\" всі інші параметри будуть автоматично вибрані. Керування користувачами - привілей адміністратора.\n",
|
||||
"profileSettings": "Налаштування профілю",
|
||||
"ruleExample1": "запобігти доступу до будь-якого прихованого файлу (наприклад: .git, .gitignore) у кожній папці.\n",
|
||||
"ruleExample2": "блокує доступ до файлу з ім'ям Caddyfile у кореневій області.",
|
||||
"rules": "Права",
|
||||
"rulesHelp": "Тут ви можете визначити набір дозволяючих та забороняючих правил для цього конкретного користувача. Блоковані файли не відображатимуться у списках, і не будуть доступні для користувача. Є підтримка регулярних виразів та відносних шляхів.\n",
|
||||
"scope": "Корінь",
|
||||
"setDateFormat": "Встановити точний формат дати",
|
||||
"settingsUpdated": "Налаштування застосовані!",
|
||||
"shareDuration": "Тривалість спільного посилання",
|
||||
"shareManagement": "Управління спільними посиланнями",
|
||||
"shareDeleted": "Спільне посилання видалено!",
|
||||
"singleClick": "Відкриття файлів та каталогів одним кліком",
|
||||
"themes": {
|
||||
"dark": "Темна",
|
||||
"light": "Світла",
|
||||
"title": "Тема"
|
||||
},
|
||||
"user": "Користувач",
|
||||
"userCommands": "Команди",
|
||||
"userCommandsHelp": "Список команд, доступних користувачу, розділений пробілами. Приклад:\n",
|
||||
"userCreated": "Користувач створений!",
|
||||
"userDefaults": "Налаштування користувача за замовчуванням",
|
||||
"userDeleted": "Користувач видалений!",
|
||||
"userManagement": "Керування користувачами",
|
||||
"userUpdated": "Користувач змінений!",
|
||||
"username": "Ім'я користувача",
|
||||
"users": "Користувачі"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Допомога",
|
||||
"hugoNew": "Hugo New",
|
||||
"login": "Увійти",
|
||||
"logout": "Вийти",
|
||||
"myFiles": "Файли",
|
||||
"newFile": "Новий файл",
|
||||
"newFolder": "Новий каталог",
|
||||
"preview": "Перегляд",
|
||||
"settings": "Налаштування",
|
||||
"signup": "Зареєструватися",
|
||||
"siteSettings": "Налаштування сайту"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Посилання скопійоване!"
|
||||
},
|
||||
"time": {
|
||||
"days": "Дні",
|
||||
"hours": "Години",
|
||||
"minutes": "Хвилини",
|
||||
"seconds": "Секунди",
|
||||
"unit": "Одиниця часу"
|
||||
}
|
||||
"user": "Користувач",
|
||||
"userCommands": "Команди",
|
||||
"userCommandsHelp": "Список команд, доступних користувачу, розділений пробілами. Приклад:\n",
|
||||
"userCreated": "Користувач створений!",
|
||||
"userDefaults": "Налаштування користувача за замовчуванням",
|
||||
"userDeleted": "Користувач видалений!",
|
||||
"userManagement": "Керування користувачами",
|
||||
"userUpdated": "Користувач змінений!",
|
||||
"username": "Ім'я користувача",
|
||||
"users": "Користувачі"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Допомога",
|
||||
"hugoNew": "Hugo New",
|
||||
"login": "Увійти",
|
||||
"logout": "Вийти",
|
||||
"myFiles": "Файли",
|
||||
"newFile": "Новий файл",
|
||||
"newFolder": "Новий каталог",
|
||||
"preview": "Перегляд",
|
||||
"settings": "Налаштування",
|
||||
"signup": "Зареєструватися",
|
||||
"siteSettings": "Налаштування сайту"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Посилання скопійоване!"
|
||||
},
|
||||
"time": {
|
||||
"days": "Дні",
|
||||
"hours": "Години",
|
||||
"minutes": "Хвилини",
|
||||
"seconds": "Секунди",
|
||||
"unit": "Одиниця часу"
|
||||
},
|
||||
"upload": {},
|
||||
"share": {},
|
||||
"api": {},
|
||||
"index": {}
|
||||
}
|
||||
@@ -101,7 +101,7 @@
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "Swedish(Sweden)",
|
||||
"tr" : "Türkçe",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文(简体)",
|
||||
"zhTW": "中文(繁體)"
|
||||
@@ -132,7 +132,6 @@
|
||||
"downloadMessage": "请选择要下载的压缩格式。",
|
||||
"error": "出了一点问题...",
|
||||
"fileInfo": "文件信息",
|
||||
"filesSelected": "已选择 {count} 个文件。",
|
||||
"lastModified": "最后修改",
|
||||
"move": "移动",
|
||||
"moveMessage": "请选择欲移动至的目录:",
|
||||
@@ -265,5 +264,9 @@
|
||||
"minutes": "分钟",
|
||||
"seconds": "秒",
|
||||
"unit": "时间单位"
|
||||
}
|
||||
},
|
||||
"upload": {},
|
||||
"share": {},
|
||||
"api": {},
|
||||
"index": {}
|
||||
}
|
||||
@@ -95,7 +95,7 @@
|
||||
"ru": "Русский",
|
||||
"sk": "Slovenčina",
|
||||
"svSE": "Swedish(Sweden)",
|
||||
"tr" : "Türkçe",
|
||||
"tr": "Türkçe",
|
||||
"ua": "Українська",
|
||||
"zhCN": "中文 (简体)",
|
||||
"zhTW": "中文 (繁體)"
|
||||
@@ -125,7 +125,6 @@
|
||||
"downloadMessage": "請選擇要下載的壓縮格式。",
|
||||
"error": "發出了一點錯誤...",
|
||||
"fileInfo": "檔案資訊",
|
||||
"filesSelected": "已選擇 {count} 個檔案。",
|
||||
"lastModified": "最後修改",
|
||||
"move": "移動",
|
||||
"moveMessage": "請選擇欲移動至的目錄:",
|
||||
@@ -145,7 +144,8 @@
|
||||
"show": "顯示",
|
||||
"size": "大小",
|
||||
"upload": "上傳",
|
||||
"uploadMessage": "選擇上傳項。"
|
||||
"uploadMessage": "選擇上傳項。",
|
||||
"deleteMessageShare": "Are you sure you want to delete this share: {path} ?"
|
||||
},
|
||||
"search": {
|
||||
"images": "影像",
|
||||
@@ -254,5 +254,9 @@
|
||||
"minutes": "分鐘",
|
||||
"seconds": "秒",
|
||||
"unit": "時間單位"
|
||||
}
|
||||
},
|
||||
"upload": {},
|
||||
"share": {},
|
||||
"api": {},
|
||||
"index": {}
|
||||
}
|
||||
@@ -186,10 +186,6 @@ export const mutations = {
|
||||
}
|
||||
emitStateChanged();
|
||||
},
|
||||
showError: () => {
|
||||
state.prompts.push("error");
|
||||
emitStateChanged();
|
||||
},
|
||||
setLoading: (loadType, status) => {
|
||||
if (status === false) {
|
||||
delete state.loading[loadType];
|
||||
@@ -235,8 +231,6 @@ export const mutations = {
|
||||
state.multiple = value;
|
||||
if (value == true) {
|
||||
notify.showMultipleSelection()
|
||||
} else {
|
||||
notify.closePopUp()
|
||||
}
|
||||
emitStateChanged();
|
||||
},
|
||||
|
||||
@@ -96,6 +96,13 @@ export async function signupLogin(username, password) {
|
||||
}
|
||||
|
||||
export function logout() {
|
||||
if (state.user.loginMethod == "oidc") {
|
||||
document.cookie = "auth=; expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/";
|
||||
mutations.setCurrentUser(null);
|
||||
let apiPath = getApiPath("api/auth/logout")
|
||||
window.location.href = apiPath;
|
||||
return
|
||||
}
|
||||
document.cookie = "auth=; expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/";
|
||||
mutations.setCurrentUser(null);
|
||||
router.push({ path: "/login" });
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
:class="{
|
||||
'dark-mode': isDarkMode,
|
||||
moveWithSidebar: moveWithSidebar,
|
||||
'remove-padding-top': isOnlyOffice,
|
||||
'main-padding': showPadding,
|
||||
scrollable: scrollable,
|
||||
}"
|
||||
@@ -70,6 +71,9 @@ export default {
|
||||
this.updateSourceInfo();
|
||||
},
|
||||
computed: {
|
||||
isOnlyOffice() {
|
||||
return getters.currentView() === "onlyOfficeEditor";
|
||||
},
|
||||
scrollable() {
|
||||
return getters.isScrollable();
|
||||
},
|
||||
@@ -158,6 +162,10 @@ export default {
|
||||
/* Enable momentum scrolling in iOS */
|
||||
}
|
||||
|
||||
.remove-padding-top {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
|
||||
#main {
|
||||
overflow: unset;
|
||||
-ms-overflow-style: none;
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
</p>
|
||||
</div>
|
||||
<div v-if="oidcAvailable" class="password-entry">
|
||||
<div v-if="passwordAvailable" class="or">OR</div>
|
||||
<a href="/api/auth/oidc/login" class="button button--block direct-login">
|
||||
<div v-if="passwordAvailable" class="or">{{ $t('login.or') }}</div>
|
||||
<a href="/api/auth/oidc/login" class="button button--block direct-login"> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
OpenID Connect
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -95,17 +95,45 @@ export default {
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.form-button {
|
||||
border-top-left-radius: 0 !important;
|
||||
border-bottom-left-radius: 0 !important;
|
||||
height: auto !important
|
||||
}
|
||||
|
||||
.invalid-form {
|
||||
border-color: red !important;
|
||||
}
|
||||
|
||||
.flat-right {
|
||||
border-top-right-radius: 0 !important;
|
||||
border-bottom-right-radius: 0 !important;
|
||||
}
|
||||
.flat-left {
|
||||
border-top-left-radius: 0 !important;
|
||||
border-bottom-left-radius: 0 !important;
|
||||
}
|
||||
|
||||
.dashboard {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.settings-views {
|
||||
max-width: 1000px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.settings-views .card {
|
||||
border-style: solid;
|
||||
opacity: 1;
|
||||
|
||||
@@ -76,10 +76,10 @@
|
||||
<strong>{{ $t("prompts.displayName") }}</strong> {{ req.name }}
|
||||
</div>
|
||||
<div class="share__box__element" :title="modTime">
|
||||
<strong>{{ $t("prompts.lastModified") }}:</strong> {{ humanTime }}
|
||||
<strong>{{ $t("prompts.lastModified") }}:</strong> {{ humanTime }} <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
</div>
|
||||
<div class="share__box__element">
|
||||
<strong>{{ $t("prompts.size") }}:</strong> {{ humanSize }}
|
||||
<strong>{{ $t("prompts.size") }}:</strong> {{ humanSize }} <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
</div>
|
||||
<div class="share__box__element share__box__center">
|
||||
<a target="_blank" :href="getLink(false)" class="button button--flat">
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
<template>
|
||||
<header :class="['flexbar', { 'dark-mode-header': isDarkMode }]">
|
||||
<header v-if="!isOnlyOffice" :class="['flexbar', { 'dark-mode-header': isDarkMode }]">
|
||||
<action
|
||||
v-if="!isShare"
|
||||
icon="close_back"
|
||||
:label="$t('buttons.close')"
|
||||
:disabled="isSearchActive"
|
||||
@action="multiAction"
|
||||
/>
|
||||
<search v-if="showSearch" />
|
||||
<title v-else-if="isSettings" class="topTitle">Settings</title>
|
||||
<title v-else-if="isSettings" class="topTitle">{{ $t('sidebar.settings') }}</title>
|
||||
<title v-else class="topTitle">{{ req.name }}</title>
|
||||
<action
|
||||
v-if="isListingView"
|
||||
@@ -45,6 +46,9 @@ export default {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isOnlyOffice() {
|
||||
return getters.currentView() === "onlyOfficeEditor";
|
||||
},
|
||||
isListingView() {
|
||||
return getters.currentView() == "listingView";
|
||||
},
|
||||
@@ -123,13 +127,6 @@ export default {
|
||||
router.push({path: "/files" });
|
||||
return;
|
||||
}
|
||||
if (listingView === "onlyOfficeEditor") {
|
||||
const current = window.location.pathname;
|
||||
const newpath = removeLastDir(current);
|
||||
window.location = newpath + "#" + state.req.name;
|
||||
return;
|
||||
}
|
||||
|
||||
mutations.replaceRequest({});
|
||||
router.go(-1);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
import { eventBus } from "@/store/eventBus";
|
||||
import { state, getters } from "@/store";
|
||||
import { filesApi } from "@/api";
|
||||
import ace from "ace-builds/src-min-noconflict/ace.js";
|
||||
import ace, { version as ace_version } from "ace-builds";
|
||||
import modelist from "ace-builds/src-noconflict/ext-modelist";
|
||||
import "ace-builds/src-min-noconflict/theme-chrome";
|
||||
import "ace-builds/src-min-noconflict/theme-twilight";
|
||||
|
||||
@@ -30,10 +31,15 @@ export default {
|
||||
this.editor.destroy();
|
||||
},
|
||||
mounted: function () {
|
||||
ace.config.set(
|
||||
"basePath",
|
||||
`https://cdn.jsdelivr.net/npm/ace-builds@${ace_version}/src-min-noconflict/`
|
||||
);
|
||||
// this is empty content string "empty-file-x6OlSil" which is used to represent empty text file
|
||||
const fileContent =
|
||||
state.req.content == "empty-file-x6OlSil" ? "" : state.req.content || "";
|
||||
this.editor = ace.edit("editor", {
|
||||
this.editor = ace.edit("editor", {
|
||||
mode: modelist.getModeForPath(state.req.name).mode,
|
||||
value: fileContent,
|
||||
showPrintMargin: false,
|
||||
theme: "ace/theme/chrome",
|
||||
@@ -41,7 +47,6 @@ export default {
|
||||
wrap: false,
|
||||
});
|
||||
// Set the basePath for Ace Editor
|
||||
ace.config.set("basePath", "/node_modules/ace-builds/src-min-noconflict");
|
||||
if (this.isDarkMode) {
|
||||
this.editor.setTheme("ace/theme/twilight");
|
||||
}
|
||||
@@ -51,9 +56,6 @@ export default {
|
||||
handleEditorValueRequest() {
|
||||
filesApi.put(state.req.path, state.req.source, this.editor.getValue());
|
||||
},
|
||||
back() {
|
||||
this.$router.push(-1);
|
||||
},
|
||||
keyEvent(event) {
|
||||
const { key, ctrlKey, metaKey } = event;
|
||||
if (getters.currentPromptName() != null) {
|
||||
@@ -65,7 +67,7 @@ export default {
|
||||
switch (key.toLowerCase()) {
|
||||
case "s":
|
||||
event.preventDefault();
|
||||
this.save();
|
||||
this.handleEditorValueRequest();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -8,7 +8,11 @@
|
||||
:onLoadComponentError="onLoadComponentError"
|
||||
/>
|
||||
<div v-else>
|
||||
<p>Loading editor...</p>
|
||||
<p>{{ $t("files.loading") }}</p>
|
||||
</div>
|
||||
<div @click="close" class="floating-close button" :class="{ 'float-in': floatIn }"
|
||||
>
|
||||
<i class="material-icons">close</i>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -19,6 +23,7 @@ import { state } from "@/store";
|
||||
import { fetchJSON } from "@/api/utils";
|
||||
import { filesApi } from "@/api";
|
||||
import { baseURL } from "@/utils/constants";
|
||||
import { removeLastDir } from "@/utils/url";
|
||||
|
||||
export default {
|
||||
name: "onlyOfficeEditor",
|
||||
@@ -29,6 +34,7 @@ export default {
|
||||
return {
|
||||
ready: false, // Flag to indicate whether the setup is complete
|
||||
clientConfig: {},
|
||||
floatIn: false, // Flag for the float-in animation
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -53,10 +59,43 @@ export default {
|
||||
this.clientConfig = configData;
|
||||
console.log("Client config:", this.clientConfig);
|
||||
this.ready = true;
|
||||
// Trigger float-in animation
|
||||
setTimeout(() => {
|
||||
this.floatIn = true;
|
||||
}, 100); // slight delay to allow rendering
|
||||
} catch (error) {
|
||||
console.error("Error during setup:", error);
|
||||
// Handle setup failure if needed
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
const current = window.location.pathname;
|
||||
const newpath = removeLastDir(current);
|
||||
window.location = newpath + "#" + state.req.name;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.floating-close {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -5em); /* Start offscreen */
|
||||
transition: transform 0.4s ease;
|
||||
background: var(--surfaceSecondary);
|
||||
font-size: .5em;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.float-in {
|
||||
transform: translate(-50%, 2.75em); /* Animate to final position */
|
||||
}
|
||||
|
||||
.floating-close i {
|
||||
font-size: 2em;
|
||||
padding-right: 1em;
|
||||
padding-left: 1em;
|
||||
}
|
||||
</style>
|
||||
@@ -2,28 +2,28 @@
|
||||
<errors v-if="error" :errorCode="error.status" />
|
||||
<div class="card" :class="{ active: active }">
|
||||
<div class="card-title">
|
||||
<h2>{{ $t("settings.api") }}</h2>
|
||||
<h2>{{ $t("api.title") }}</h2>
|
||||
<div>
|
||||
<button @click.prevent="createPrompt" class="button">
|
||||
{{ $t("buttons.new") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-content full" v-if="Object.keys(links).length > 0">
|
||||
<p>
|
||||
API keys are based on the user that creates them. See
|
||||
<a class="link" href="swagger/index.html">swagger page</a> for how to use them.
|
||||
Keys are associated with your user and the user must have access to the permission
|
||||
level you want to use the key with.
|
||||
{{ $t("api.description") }}
|
||||
<a class="link" href="swagger/index.html">{{ $t("api.swaggerLinkText") }}</a>
|
||||
</p>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Created</th>
|
||||
<th>Expires</th>
|
||||
<th>{{ $t("api.name") }}</th>
|
||||
<th>{{ $t("api.created") }}</th>
|
||||
<th>{{ $t("api.expires") }}</th>
|
||||
<th>{{ $t("settings.permissions-name") }}</th>
|
||||
<th>Actions</th>
|
||||
<th>{{ $t("api.actions") }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -35,7 +35,7 @@
|
||||
<span
|
||||
v-for="(value, permission) in link.Permissions"
|
||||
:key="permission"
|
||||
:title="`${permission}: ${value ? 'Enabled' : 'Disabled'}`"
|
||||
:title="`${permission}: ${value ? $t('api.enabled') : $t('api.disabled')}`"
|
||||
class="clickable"
|
||||
@click.prevent="infoPrompt(name, link)"
|
||||
>
|
||||
@@ -61,6 +61,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h2 class="message" v-else>
|
||||
<i class="material-icons">sentiment_dissatisfied</i>
|
||||
<span>{{ $t("files.lonely") }}</span>
|
||||
|
||||
@@ -5,10 +5,7 @@
|
||||
<h2>{{ $t("settings.globalSettings") }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
Currently there are no global config options, You can edit the configuration yaml to
|
||||
adjust system settings.
|
||||
</div>
|
||||
<div class="card-content"> {{ $t('settings.emptyGlobal') }} </div>
|
||||
|
||||
<div class="card-action">
|
||||
<input class="button button--flat" type="submit" :value="$t('buttons.update')" />
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="card-content">
|
||||
<form>
|
||||
<div class="card-content">
|
||||
<h3>Listing options</h3>
|
||||
<h3>{{ $t('settings.listingOptions') }}</h3>
|
||||
<div class="settings-items">
|
||||
<ToggleSwitch
|
||||
class="item"
|
||||
@@ -24,7 +24,7 @@
|
||||
:name="`Always show download icon for quick access`"
|
||||
/>
|
||||
</div>
|
||||
<h3>File preview options</h3>
|
||||
<h3> {{ $t('settings.filePreviewOptions') }}</h3>
|
||||
<div class="settings-items">
|
||||
<ToggleSwitch
|
||||
class="item"
|
||||
@@ -37,6 +37,12 @@
|
||||
v-model="localuser.preview.video"
|
||||
name="Preview videos"
|
||||
/>
|
||||
<ToggleSwitch
|
||||
v-if="mediaEnabled"
|
||||
class="item"
|
||||
v-model="localuser.preview.motionVideoPreview"
|
||||
name="Motion previews for videos"
|
||||
/>
|
||||
<ToggleSwitch
|
||||
class="item"
|
||||
v-model="localuser.preview.highQuality"
|
||||
@@ -55,27 +61,24 @@
|
||||
/>
|
||||
</div>
|
||||
<div v-if="hasOnlyOfficeEnabled">
|
||||
<h3>Disable onlyoffice viewer for certain file extensions</h3>
|
||||
<h3> {{ $t('settings.disableOfficePreview')}} </h3>
|
||||
<p>
|
||||
A space-separated list of file extensions to disable the OnlyOffice viewer
|
||||
for. (e.g., <code>.txt .html</code>)
|
||||
{{ $t('settings.disableOfficePreviewDescription') }}
|
||||
</p>
|
||||
<div class="onlyoffice-group">
|
||||
<div class="form-group">
|
||||
<input
|
||||
class="input input--block onlyoffice-form"
|
||||
class="input input--block form-form flat-right"
|
||||
:class="{ 'invalid-form': !formValidation() }"
|
||||
type="text"
|
||||
placeholder="enter file extensions"
|
||||
id="onlyofficeExt"
|
||||
v-model="formOnlyOfficeExt"
|
||||
/>
|
||||
<button type="button" class="button onlyoffice-button" @click="submitOnlyOfficeChange">
|
||||
save
|
||||
</button>
|
||||
<button type="button" class="button form-button" @click="submitOnlyOfficeChange"> {{ $t('buttons.save') }} </button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Theme Color</h3>
|
||||
<h3> {{ $t('settings.themeColor') }} </h3>
|
||||
<ButtonGroup
|
||||
:buttons="colorChoices"
|
||||
@button-clicked="setColor"
|
||||
@@ -210,18 +213,5 @@ export default {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.onlyoffice-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.onlyoffice-button {
|
||||
margin-left: 1em;
|
||||
}
|
||||
.onlyoffice-form {
|
||||
height: 3em;
|
||||
}
|
||||
.invalid-form {
|
||||
border-color: red !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -3,21 +3,20 @@
|
||||
<form @submit="save" class="card active" v-if="loaded">
|
||||
<div class="card-title">
|
||||
<h2 v-if="isNew">{{ $t("settings.newUser") }}</h2>
|
||||
<h2 v-else-if="actor.id == user.id">modify current user ({{ user.username }})</h2>
|
||||
<h2 v-else>modify user: {{ user.username }}</h2>
|
||||
<h2 v-else-if="actor.id == user.id"> {{ $t('settings.modifyCurrentUser') }} ({{ user.username }})</h2> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<h2 v-else> {{ $t('settings.modifyOtherUser') }} {{ user.username }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="card-content minimal-card">
|
||||
<user-form
|
||||
v-model:user="user"
|
||||
v-model:updatePassword="updatePassword"
|
||||
:createUserDir="createUserDir"
|
||||
:isNew="isNew"
|
||||
@update:createUserDir="(updatedDir) => (createUserDir = updatedDir)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="card-action">
|
||||
<div v-if="actor.permissions.admin" class="card-action">
|
||||
<button
|
||||
v-if="!isNew && actor.permissions.admin"
|
||||
@click.prevent="deletePrompt"
|
||||
@@ -53,12 +52,12 @@ export default {
|
||||
user: {
|
||||
scopes: [],
|
||||
username: "",
|
||||
password: "",
|
||||
permissions: { admin: false },
|
||||
},
|
||||
showDelete: false,
|
||||
createUserDir: false,
|
||||
loaded: false,
|
||||
updatePassword: false,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
@@ -83,6 +82,7 @@ export default {
|
||||
if (this.isNew) {
|
||||
let defaults = await settingsApi.get("userDefaults");
|
||||
this.user = defaults;
|
||||
this.user.password = "";
|
||||
} else {
|
||||
const id = Array.isArray(state.route.params.id)
|
||||
? state.route.params.id.join("")
|
||||
@@ -91,6 +91,7 @@ export default {
|
||||
return;
|
||||
}
|
||||
this.user = { ...(await usersApi.get(id)) };
|
||||
this.user.password = "";
|
||||
}
|
||||
} catch (e) {
|
||||
notify.showError(e);
|
||||
@@ -108,16 +109,14 @@ export default {
|
||||
try {
|
||||
let fields = ["all"]
|
||||
if (!state.user.permissions.admin) {
|
||||
fields = ["password"];
|
||||
notify.showError(this.$t("settings.userNotAdmin"));
|
||||
return;
|
||||
}
|
||||
if (this.isNew) {
|
||||
await usersApi.create(this.user); // Use the computed property
|
||||
this.$router.push({ path: "/settings", hash: "#users-main" });
|
||||
} else {
|
||||
await usersApi.update(this.user, fields);
|
||||
if (this.updatePassword) {
|
||||
await usersApi.update(this.user, ["password"]);
|
||||
}
|
||||
notify.showSuccess(this.$t("settings.userUpdated"));
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ $t("settings.username") }}</th>
|
||||
<th>Login Method</th>
|
||||
<th> {{ $t("settings.loginMethod") }} </th>
|
||||
<th>{{ $t("settings.admin") }}</th>
|
||||
<th>Scopes</th>
|
||||
<th>Scopes</th> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@@ -43,10 +43,10 @@ test("open nested file in /files dir from search", async({ page, checkForErrors,
|
||||
await page.goto("/files/");
|
||||
await expect(page).toHaveTitle("Graham's Filebrowser - Files - playwright-files");
|
||||
await page.locator('#search').click()
|
||||
await page.locator('#main-input').fill('graham');
|
||||
await page.locator('#main-input').fill('binary');
|
||||
await expect(page.locator('#result-list')).toHaveCount(1);
|
||||
await page.locator('li[aria-label="graham.xlsx"]').click();
|
||||
await expect(page).toHaveTitle("Graham's Filebrowser - Files - graham.xlsx");
|
||||
await page.locator('li[aria-label="binary.dat"]').click();
|
||||
await expect(page).toHaveTitle("Graham's Filebrowser - Files - binary.dat");
|
||||
await expect(page.locator('#previewer')).toContainText('Preview is not available for this file.');
|
||||
checkForErrors();
|
||||
})
|
||||
|
||||
Binary file not shown.
@@ -28,13 +28,13 @@ run: build-frontend
|
||||
else \
|
||||
sed -i '/func init/,+3d' ./swagger/docs/docs.go; \
|
||||
fi && \
|
||||
go run ./tools/yaml.go -input ./common/settings/settings.go -output=http/embed/config.generated.yaml && \
|
||||
cp http/embed/config.generated.yaml http/dist/config.generated.yaml && \
|
||||
FILEBROWSER_NO_EMBEDED=true go run \
|
||||
--ldflags="-w -s -X 'github.com/gtsteffaniak/filebrowser/backend/version.CommitSHA=testingCommit' -X 'github.com/gtsteffaniak/filebrowser/backend/version.Version=testing'" . -c test_config.yaml
|
||||
|
||||
build-frontend:
|
||||
cd backend/http && rm -rf dist embed/* && ln -s ../../frontend/dist
|
||||
cd backend && rm -rf http/dist http/embed/* && \
|
||||
go run ./tools/yaml.go -input ./common/settings/settings.go -output=../frontend/public/config.generated.yaml
|
||||
cd backend/http/ && ln -s ../../frontend/dist
|
||||
if [ "$(OS)" = "Windows_NT" ]; then \
|
||||
cd frontend && npm run build-windows; \
|
||||
else \
|
||||
|
||||
Reference in new issue
Block a user