mirror of
https://github.com/syncthing/syncthing.git
synced 2026-01-03 11:29:10 -05:00
Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2145b3701d | ||
|
|
4031568cdf | ||
|
|
fff9bf98eb | ||
|
|
6a7fc49c6b | ||
|
|
89f5d0d400 | ||
|
|
1eda82b95f | ||
|
|
623ec03dad | ||
|
|
c0de42e3df | ||
|
|
4893513800 | ||
|
|
100142067d | ||
|
|
3907cb0693 | ||
|
|
61dffabf97 | ||
|
|
bc27aa12cd | ||
|
|
0537b9546f | ||
|
|
0525c755f4 | ||
|
|
bcd91f536e | ||
|
|
f9c6c69fa8 | ||
|
|
0c46e0a9cc | ||
|
|
bca6d31b95 | ||
|
|
db72579f0e | ||
|
|
9b09bcc5f1 | ||
|
|
22e12904c9 | ||
|
|
b947056e62 | ||
|
|
e30898ddb3 | ||
|
|
072fa46bfd | ||
|
|
edc3a77b98 | ||
|
|
2b80848341 | ||
|
|
30fa462e33 | ||
|
|
11ac945b87 | ||
|
|
55c513b827 | ||
|
|
0eca0ac45a | ||
|
|
4be867c560 | ||
|
|
44b11ec257 | ||
|
|
53926a1ae6 | ||
|
|
5f383923df | ||
|
|
26eaedc491 | ||
|
|
7b63254a35 | ||
|
|
d0fd6c6c82 | ||
|
|
6862dd04ab | ||
|
|
e1b1631c65 | ||
|
|
1d74b547dd | ||
|
|
a3a4da6e3e | ||
|
|
e974c13c7a | ||
|
|
1999383443 | ||
|
|
bd0acd04b1 | ||
|
|
f25947e5eb | ||
|
|
f890fe6fd3 | ||
|
|
10f9d95cd2 |
@@ -10,11 +10,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
name: Update translations and documentation
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@629c2de402a417ea7690ca6ce3f33229e27606a5 # v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.ACTIONS_GITHUB_TOKEN }}
|
||||
- uses: actions/setup-go@v2
|
||||
- uses: actions/setup-go@bfdd3570ce990073878bf10f6b2d79082de49492 # v2
|
||||
with:
|
||||
go-version: ^1.17.6
|
||||
- run: |
|
||||
|
||||
14
AUTHORS
14
AUTHORS
@@ -27,6 +27,7 @@ Aman Gupta <aman@tmm1.net>
|
||||
Anderson Mesquita (andersonvom) <andersonvom@gmail.com>
|
||||
andresvia <andres.via@gmail.com>
|
||||
Andrew Dunham (andrew-d) <andrew@du.nham.ca>
|
||||
Andrew Meyer <andrewm.bpi@gmail.com>
|
||||
Andrew Rabert (nvllsvm) <ar@nullsum.net> <6550543+nvllsvm@users.noreply.github.com>
|
||||
Andrey D (scienmind) <scintertech@cryptolab.net> <scienmind@users.noreply.github.com>
|
||||
André Colomb (acolomb) <src@andre.colomb.de> <github.com@andre.colomb.de>
|
||||
@@ -76,6 +77,7 @@ Cromefire_ <tim.l@nghorst.net> <26320625+cromefire@users.noreply.github.com>
|
||||
Cyprien Devillez <cypx@users.noreply.github.com>
|
||||
Dale Visser <dale.visser@live.com>
|
||||
Dan <benda.daniel@gmail.com>
|
||||
Daniel Barczyk <46358936+DanielBarczyk@users.noreply.github.com>
|
||||
Daniel Bergmann (brgmnn) <dan.arne.bergmann@gmail.com> <brgmnn@users.noreply.github.com>
|
||||
Daniel Harte (norgeous) <daniel@harte.me> <daniel@danielharte.co.uk> <norgeous@users.noreply.github.com>
|
||||
Daniel Martí (mvdan) <mvdan@mvdan.cc>
|
||||
@@ -94,6 +96,7 @@ Dominik Heidler (asdil12) <dominik@heidler.eu>
|
||||
Elias Jarlebring (jarlebring) <jarlebring@gmail.com>
|
||||
Elliot Huffman <thelich2@gmail.com>
|
||||
Emil Hessman (ceh) <emil@hessman.se>
|
||||
Eng Zer Jun <engzerjun@gmail.com>
|
||||
Eric Lesiuta <elesiuta@gmail.com>
|
||||
Erik Meitner (WSGCSysadmin) <e.meitner@willystreet.coop>
|
||||
Evgeny Kuznetsov <evgeny@kuznetsov.md>
|
||||
@@ -103,13 +106,14 @@ Felix Lampe <mail@flampe.de>
|
||||
Felix Unterpaintner (bigbear2nd) <bigbear2nd@gmail.com>
|
||||
Francois-Xavier Gsell (zukoo) <fxgsell@gmail.com>
|
||||
Frank Isemann (fti7) <frank@isemann.name>
|
||||
Gahl Saraf <saraf.gahl@gmail.com>
|
||||
Gahl Saraf <saraf.gahl@gmail.com> <gahl@raftt.io>
|
||||
georgespatton <georgespatton@users.noreply.github.com>
|
||||
ghjklw <malo@jaffre.info>
|
||||
Gilli Sigurdsson (gillisig) <gilli@vx.is>
|
||||
Gleb Sinyavskiy <zhulik.gleb@gmail.com>
|
||||
Graham Miln (grahammiln) <graham.miln@dssw.co.uk> <graham.miln@miln.eu>
|
||||
greatroar <61184462+greatroar@users.noreply.github.com>
|
||||
Greg <gco@jazzhaiku.com>
|
||||
Han Boetes <han@boetes.org>
|
||||
HansK-p <42314815+HansK-p@users.noreply.github.com>
|
||||
Harrison Jones (harrisonhjones) <harrisonhjones@users.noreply.github.com>
|
||||
@@ -117,6 +121,7 @@ Heiko Zuerker (Smiley73) <heiko@zuerker.org>
|
||||
Hugo Locurcio <hugo.locurcio@hugo.pro>
|
||||
Iain Barnett <iainspeed@gmail.com>
|
||||
Ian Johnson (anonymouse64) <ian.johnson@canonical.com> <person.uwsome@gmail.com>
|
||||
ignacy123 <ignacy.buczek@onet.pl>
|
||||
Ikko Ashimine <eltociear@gmail.com>
|
||||
Ilya Brin <464157+ilyabrin@users.noreply.github.com>
|
||||
Iskander Sharipov (Alex) <quasilyte@gmail.com>
|
||||
@@ -132,6 +137,7 @@ Jaroslav Lichtblau <svetlemodry@users.noreply.github.com>
|
||||
Jaroslav Malec (dzarda) <dzardacz@gmail.com>
|
||||
jaseg <githubaccount@jaseg.net>
|
||||
Jaya Chithra (jayachithra) <s.k.jayachithra@gmail.com>
|
||||
Jeffery To <jeffery.to@gmail.com>
|
||||
jelle van der Waa <jelle@vdwaa.nl>
|
||||
Jens Diemer (jedie) <github.com@jensdiemer.de> <git@jensdiemer.de>
|
||||
Jerry Jacobs (xor-gate) <jerry.jacobs@xor-gate.org> <xor-gate@users.noreply.github.com>
|
||||
@@ -150,6 +156,7 @@ Jörg Thalheim <Mic92@users.noreply.github.com>
|
||||
Jędrzej Kula <kula.jedrek@gmail.com>
|
||||
Kalle Laine <pahakalle@protonmail.com>
|
||||
Karol Różycki (krozycki) <rozycki.karol@gmail.com>
|
||||
Kebin Liu <lkebin@gmail.com>
|
||||
Keith Turner <kturner@apache.org>
|
||||
Kelong Cong (kc1212) <kc04bc@gmx.com> <kc1212@users.noreply.github.com>
|
||||
Ken'ichi Kamada (kamadak) <kamada@nanohz.org>
|
||||
@@ -198,6 +205,7 @@ MikolajTwarog <43782609+MikolajTwarog@users.noreply.github.com>
|
||||
Mingxuan Lin <gdlmx@users.noreply.github.com>
|
||||
mv1005 <49659413+mv1005@users.noreply.github.com>
|
||||
Nate Morrison (nrm21) <natemorrison@gmail.com>
|
||||
Naveen <172697+naveensrinivasan@users.noreply.github.com>
|
||||
Nicholas Rishel (PrototypeNM1) <rishel.nick@gmail.com> <PrototypeNM1@users.noreply.github.com>
|
||||
Nico Stapelbroek <3368018+nstapelbroek@users.noreply.github.com>
|
||||
Nicolas Braud-Santoni <nicolas@braud-santoni.eu>
|
||||
@@ -231,6 +239,7 @@ Piotr Bejda (piobpl) <piotrb10@gmail.com>
|
||||
Pramodh KP (pramodhkp) <pramodh.p@directi.com> <1507241+pramodhkp@users.noreply.github.com>
|
||||
Quentin Hibon <qh.public@yahoo.com>
|
||||
Rahmi Pruitt <rjpruitt16@gmail.com>
|
||||
red_led <red-led@users.noreply.github.com>
|
||||
Richard Hartmann <RichiH@users.noreply.github.com>
|
||||
Robert Carosi (nov1n) <robert@carosi.nl>
|
||||
Roberto Santalla <roobre@users.noreply.github.com>
|
||||
@@ -239,6 +248,7 @@ Roman Zaynetdinov (zaynetro) <romanznet@gmail.com>
|
||||
Ross Smith II (rasa) <ross@smithii.com>
|
||||
rubenbe <github-com-00ff86@vandamme.email>
|
||||
Ruslan Yevdokymov <38809160+ruslanye@users.noreply.github.com>
|
||||
Ryan Qian <i@bitbili.net>
|
||||
Ryan Sullivan (KayoticSully) <kayoticsully@gmail.com>
|
||||
Sacheendra Talluri (sacheendra) <sacheendra.t@gmail.com>
|
||||
Scott Klupfel (kluppy) <kluppy@going2blue.com>
|
||||
@@ -251,6 +261,7 @@ Stefan Kuntz (Stefan-Code) <stefan.github@gmail.com> <Stefan.github@gmail.com>
|
||||
Stefan Tatschner (rumpelsepp) <stefan@sevenbyte.org> <rumpelsepp@sevenbyte.org> <stefan@rumpelsepp.org>
|
||||
Steven Eckhoff <steven.eckhoff.opensource@gmail.com>
|
||||
Suhas Gundimeda (snugghash) <suhas.gundimeda@gmail.com> <snugghash@gmail.com>
|
||||
Syncthing Automation <automation@syncthing.net>
|
||||
Syncthing Release Automation <release@syncthing.net>
|
||||
Taylor Khan (nelsonkhan) <nelsonkhan@gmail.com>
|
||||
Thomas Hipp <thomashipp@gmail.com>
|
||||
@@ -269,6 +280,7 @@ Unrud (Unrud) <unrud@openaliasbox.org> <Unrud@users.noreply.github.com>
|
||||
Veeti Paananen (veeti) <veeti.paananen@rojekti.fi>
|
||||
Victor Buinsky (buinsky) <vix_booja@tut.by>
|
||||
Vil Brekin (Vilbrekin) <vilbrekin@gmail.com>
|
||||
villekalliomaki <53118179+villekalliomaki@users.noreply.github.com>
|
||||
Vladimir Rusinov <vrusinov@google.com> <vladimir.rusinov@gmail.com>
|
||||
wangguoliang <liangcszzu@163.com>
|
||||
William A. Kennington III (wkennington) <william@wkennington.com>
|
||||
|
||||
@@ -16,7 +16,7 @@ the name of the Syncthing instance can be optionally defined by using
|
||||
**Docker cli**
|
||||
```
|
||||
$ docker pull syncthing/syncthing
|
||||
$ docker run -p 8384:8384 -p 22000:22000/tcp -p 22000:22000/udp \
|
||||
$ docker run -p 8384:8384 -p 22000:22000/tcp -p 22000:22000/udp -p 21027:21027/udp \
|
||||
-v /wherever/st-sync:/var/syncthing \
|
||||
--hostname=my-syncthing \
|
||||
syncthing/syncthing:latest
|
||||
@@ -37,9 +37,10 @@ services:
|
||||
volumes:
|
||||
- /wherever/st-sync:/var/syncthing
|
||||
ports:
|
||||
- 8384:8384
|
||||
- 22000:22000/tcp
|
||||
- 22000:22000/udp
|
||||
- 8384:8384 # Web UI
|
||||
- 22000:22000/tcp # TCP file transfers
|
||||
- 22000:22000/udp # QUIC file transfers
|
||||
- 21027:21027/udp # Receive local discovery broadcasts
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
|
||||
4
build.go
4
build.go
@@ -883,7 +883,7 @@ func shouldRebuildAssets(target, srcdir string) bool {
|
||||
|
||||
func updateDependencies() {
|
||||
runPrint(goCmd, "get", "-u", "./cmd/...")
|
||||
runPrint(goCmd, "mod", "tidy", "-go=1.16", "-compat=1.16")
|
||||
runPrint(goCmd, "mod", "tidy", "-go=1.17", "-compat=1.17")
|
||||
|
||||
// We might have updated the protobuf package and should regenerate to match.
|
||||
proto()
|
||||
@@ -985,7 +985,7 @@ func getGitVersion() (string, error) {
|
||||
v0 := string(bs)
|
||||
|
||||
// To be more semantic-versionish and ensure proper ordering in our
|
||||
// upgrade process, we make sure there's only one hypen in the version.
|
||||
// upgrade process, we make sure there's only one hyphen in the version.
|
||||
|
||||
versionRe := regexp.MustCompile(`-([0-9]{1,3}-g[0-9a-f]{5,10}(-dirty)?)`)
|
||||
if m := versionRe.FindStringSubmatch(vcur); len(m) > 0 {
|
||||
|
||||
@@ -84,7 +84,7 @@ func checkServers(deviceID protocol.DeviceID, servers ...string) {
|
||||
}
|
||||
|
||||
func checkServer(deviceID protocol.DeviceID, server string) checkResult {
|
||||
disco, err := discover.NewGlobal(server, tls.Certificate{}, nil, events.NoopLogger)
|
||||
disco, err := discover.NewGlobal(server, tls.Certificate{}, nil, events.NoopLogger, nil)
|
||||
if err != nil {
|
||||
return checkResult{error: err}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ var errorsCommand = cli.Command{
|
||||
{
|
||||
Name: "push",
|
||||
Usage: "Push an error to active clients",
|
||||
ArgsUsage: "[error message]",
|
||||
ArgsUsage: "ERROR-MESSAGE",
|
||||
Action: expects(1, errorsPush),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -39,13 +39,13 @@ var operationCommand = cli.Command{
|
||||
{
|
||||
Name: "folder-override",
|
||||
Usage: "Override changes on folder (remote for sendonly, local for receiveonly). WARNING: Destructive - deletes/changes your data.",
|
||||
ArgsUsage: "[folder id]",
|
||||
ArgsUsage: "FOLDER-ID",
|
||||
Action: expects(1, foldersOverride),
|
||||
},
|
||||
{
|
||||
Name: "default-ignores",
|
||||
Usage: "Set the default ignores (config) from a file",
|
||||
ArgsUsage: "path",
|
||||
ArgsUsage: "PATH",
|
||||
Action: expects(1, setDefaultIgnores),
|
||||
},
|
||||
},
|
||||
|
||||
@@ -68,9 +68,9 @@ The --logflags value is a sum of the following:
|
||||
8 Long filename
|
||||
16 Short filename
|
||||
|
||||
I.e. to prefix each log line with date and time, set --logflags=3 (1 + 2 from
|
||||
above). The value 0 is used to disable all of the above. The default is to
|
||||
show time only (2).
|
||||
I.e. to prefix each log line with time and filename, set --logflags=18 (2 + 16
|
||||
from above). The value 0 is used to disable all of the above. The default is
|
||||
to show date and time (3).
|
||||
|
||||
Logging always happens to the command line (stdout) and optionally to the
|
||||
file at the path specified by --logfile=path. In addition to an path, the special
|
||||
@@ -173,7 +173,7 @@ type serveOptions struct {
|
||||
DebugGUIAssetsDir string `placeholder:"PATH" help:"Directory to load GUI assets from" env:"STGUIASSETS"`
|
||||
DebugPerfStats bool `env:"STPERFSTATS" help:"Write running performance statistics to perf-$pid.csv (Unix only)"`
|
||||
DebugProfileBlock bool `env:"STBLOCKPROFILE" help:"Write block profiles to block-$pid-$timestamp.pprof every 20 seconds"`
|
||||
DebugProfileCPU bool `help:"Write a CPU profile to cpu-$pid.pprof on exit" env:"CPUPROFILE"`
|
||||
DebugProfileCPU bool `help:"Write a CPU profile to cpu-$pid.pprof on exit" env:"STCPUPROFILE"`
|
||||
DebugProfileHeap bool `env:"STHEAPPROFILE" help:"Write heap profiles to heap-$pid-$timestamp.pprof each time heap usage increases"`
|
||||
DebugProfilerListen string `placeholder:"ADDR" env:"STPROFILER" help:"Network profiler listen address"`
|
||||
DebugResetDatabase bool `name:"reset-database" help:"Reset the database, forcing a full rescan and resync"`
|
||||
@@ -187,7 +187,7 @@ type serveOptions struct {
|
||||
func defaultVars() kong.Vars {
|
||||
vars := kong.Vars{}
|
||||
|
||||
vars["logFlags"] = strconv.Itoa(log.Ltime)
|
||||
vars["logFlags"] = strconv.Itoa(logger.DefaultFlags)
|
||||
vars["logMaxSize"] = strconv.Itoa(10 << 20) // 10 MiB
|
||||
vars["logMaxFiles"] = "3" // plus the current one
|
||||
|
||||
|
||||
@@ -17,14 +17,17 @@ import (
|
||||
func TestRotatedFile(t *testing.T) {
|
||||
// Verify that log rotation happens.
|
||||
|
||||
dir, err := os.MkdirTemp("", "syncthing")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
dir := t.TempDir()
|
||||
|
||||
open := func(name string) (io.WriteCloser, error) {
|
||||
return os.Create(name)
|
||||
f, err := os.Create(name)
|
||||
t.Cleanup(func() {
|
||||
if f != nil {
|
||||
_ = f.Close()
|
||||
}
|
||||
})
|
||||
|
||||
return f, err
|
||||
}
|
||||
|
||||
logName := filepath.Join(dir, "log.txt")
|
||||
|
||||
31
go.mod
31
go.mod
@@ -28,7 +28,7 @@ require (
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||
github.com/lib/pq v1.10.3
|
||||
github.com/lucas-clemente/quic-go v0.25.0
|
||||
github.com/lucas-clemente/quic-go v0.27.0
|
||||
github.com/maruel/panicparse v1.6.1
|
||||
github.com/maxbrunsfeld/counterfeiter/v6 v6.3.0
|
||||
github.com/minio/sha256-simd v1.0.0
|
||||
@@ -44,7 +44,7 @@ require (
|
||||
github.com/shirou/gopsutil/v3 v3.21.12
|
||||
github.com/syncthing/notify v0.0.0-20210616190510-c6b7342338d2
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20200815071216-d9e9293bd0f7
|
||||
github.com/thejerf/suture/v4 v4.0.1
|
||||
github.com/thejerf/suture/v4 v4.0.2
|
||||
github.com/urfave/cli v1.22.5
|
||||
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
|
||||
@@ -53,8 +53,31 @@ require (
|
||||
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c
|
||||
golang.org/x/text v0.3.7
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
|
||||
golang.org/x/tools v0.1.6
|
||||
golang.org/x/tools v0.1.7
|
||||
google.golang.org/protobuf v1.27.1
|
||||
)
|
||||
|
||||
go 1.16
|
||||
require (
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cheekybits/genny v1.0.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.1 // indirect
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.1 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/onsi/ginkgo v1.16.4 // indirect
|
||||
github.com/oschwald/maxminddb-golang v1.8.0 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
)
|
||||
|
||||
go 1.17
|
||||
|
||||
29
go.sum
29
go.sum
@@ -240,21 +240,24 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.10.3 h1:v9QZf2Sn6AmjXtQeFpdoq/eaNtYP6IN+7lcrygsIAtg=
|
||||
github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lucas-clemente/quic-go v0.22.0/go.mod h1:vF5M1XqhBAHgbjKcJOXY3JZz3GP0T3FQhz/uyOUS38Q=
|
||||
github.com/lucas-clemente/quic-go v0.25.0 h1:K+X9Gvd7JXsOHtU0N2icZ2Nw3rx82uBej3mP4CLgibc=
|
||||
github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg=
|
||||
github.com/lucas-clemente/quic-go v0.26.0 h1:ALBQXr9UJ8A1LyzvceX4jd9QFsHvlI0RR6BkV16o00A=
|
||||
github.com/lucas-clemente/quic-go v0.26.0/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI=
|
||||
github.com/lucas-clemente/quic-go v0.27.0 h1:v6WY87q9zD4dKASbG8hy/LpzAVNzEQzw8sEIeloJsc4=
|
||||
github.com/lucas-clemente/quic-go v0.27.0/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
||||
github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
|
||||
github.com/marten-seemann/qtls-go1-15 v0.1.5/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.4 h1:xbHbOGGhrenVtII6Co8akhLEdrawwB2iHl5yhJRpnco=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.0-rc.1/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.0 h1:P9ggrs5xtwiqXv/FHNwntmuLMNq3KaSIG93AtAZ48xk=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 h1:EnzzN9fPUkUck/1CuY1FlzBaIYMoiBsdwTNmNGkwUUM=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.1 h1:DQjHPq+aOzUeh9/lixAGunn6rIOQyWChPSI4+hgW7jc=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.1/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.1 h1:qp7p7XXUFL7fpBvSS1sWD+uSqPvzNQK43DH+/qEkj0Y=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.1/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
||||
github.com/maruel/panicparse v1.6.1 h1:803MjBzGcUgE1vYgg3UMNq3G1oyYeKkMu3t6hBS97x0=
|
||||
github.com/maruel/panicparse v1.6.1/go.mod h1:uoxI4w9gJL6XahaYPMq/z9uadrdr1SyHuQwV2q80Mm0=
|
||||
github.com/maruel/panicparse/v2 v2.1.1/go.mod h1:AeTWdCE4lcq8OKsLb6cHSj1RWHVSnV9HBCk7sKLF4Jg=
|
||||
@@ -337,7 +340,6 @@ github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
@@ -391,8 +393,8 @@ github.com/syncthing/notify v0.0.0-20210616190510-c6b7342338d2/go.mod h1:J0q59IW
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20200815071216-d9e9293bd0f7 h1:udtnv1cokhJYqnUfCMCppJ71bFN9VKfG1BQ6UsYZnx8=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20200815071216-d9e9293bd0f7/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/thejerf/suture/v4 v4.0.1 h1:CLnC1wxLAiHA5zTbbvhSWMupVuGe5ZJ7YddWE3lvb4M=
|
||||
github.com/thejerf/suture/v4 v4.0.1/go.mod h1:g0e8vwskm9tI0jRjxrnA6lSr0q6OfPdWJVX7G5bVWRs=
|
||||
github.com/thejerf/suture/v4 v4.0.2 h1:VxIH/J8uYvqJY1+9fxi5GBfGRkRZ/jlSOP6x9HijFQc=
|
||||
github.com/thejerf/suture/v4 v4.0.2/go.mod h1:g0e8vwskm9tI0jRjxrnA6lSr0q6OfPdWJVX7G5bVWRs=
|
||||
github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
|
||||
github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
@@ -407,7 +409,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
@@ -507,7 +508,6 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210716203947-853a461950ff/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210924151903-3ad01bbaa167 h1:eDd+TJqbgfXruGQ5sJRU7tEtp/58OAx4+Ayjxg4SM+4=
|
||||
golang.org/x/net v0.0.0-20210924151903-3ad01bbaa167/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -585,7 +585,6 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c h1:taxlMj0D/1sOAuv/CbSD+MMDof2vbyPTqz5FNYKpXt8=
|
||||
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -652,8 +651,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.6 h1:SIasE1FVIQOWz2GEAHFOmoW7xchJcqlucjSULTL0Ag4=
|
||||
golang.org/x/tools v0.1.6/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
body {
|
||||
padding-bottom: 70px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Външна команда управлява версиите. Тя трябва да премахне файла от синхронизираната папка. Ако в пътя до приложението има интервали, то той трябва да бъде поставен в кавички.",
|
||||
"Anonymous Usage Reporting": "Анонимно отчитане на употреба",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Форматът на данните за анонимно отчитане на употреба е променен. Желаете ли да използвате него вместо стария?",
|
||||
"Apply": "Прилагане",
|
||||
"Are you sure you want to continue?": "Сигурни ли сте, че желаете да продължите?",
|
||||
"Are you sure you want to override all remote changes?": "Сигурни ли сте, че желаете да отмените всички промени, направени отдалечено?",
|
||||
"Are you sure you want to permanently delete all these files?": "Сигурни ли сте, че желаете всички тези файлове да бъдат безвъзвратно премахнати?",
|
||||
@@ -61,7 +62,7 @@
|
||||
"Connection Error": "Грешка при осъществяване на връзка",
|
||||
"Connection Type": "Вид на връзката",
|
||||
"Connections": "Връзки",
|
||||
"Continuously watching for changes is now available within Syncthing. This will detect changes on disk and issue a scan on only the modified paths. The benefits are that changes are propagated quicker and that less full scans are required.": "Syncthing вече разполага с постоянно наблюдение за промени. Така се забелязват промените на дисковото устройство и се обхождат само променените папки. Ползите са, че промените се разпространяват по-бързо и с по-малко на брой пълни обхождания.",
|
||||
"Continuously watching for changes is now available within Syncthing. This will detect changes on disk and issue a scan on only the modified paths. The benefits are that changes are propagated quicker and that less full scans are required.": "Syncthing вече разполага с постоянно наблюдение за промени. Така се отчитат промените на дисковото устройство и се обхождат само повлияните папки. Ползите са, че промените се разпространяват по-бързо и с по-малко на брой пълни обхождания.",
|
||||
"Copied from elsewhere": "Копирано от другаде",
|
||||
"Copied from original": "Копирано от източника",
|
||||
"Copyright © 2014-2019 the following Contributors:": "Всички права запазени © 2014-2019 за следните сътрудници:",
|
||||
@@ -77,10 +78,10 @@
|
||||
"Defaults": "Подразбирани",
|
||||
"Delete": "Изтрий",
|
||||
"Delete Unexpected Items": "Премахване на неочакваните",
|
||||
"Deleted": "Изтрито",
|
||||
"Deleted {%file%}": "{{file}} премахнат",
|
||||
"Deselect All": "Изчистване",
|
||||
"Deselect devices to stop sharing this folder with.": "Махнете отметката от устройство, за да спрете споделяне с него.",
|
||||
"Deselect folders to stop sharing with this device.": "Махнете отметката от папка, за да спрете споделяне устройствто.",
|
||||
"Deselect folders to stop sharing with this device.": "Махнете отметката пред папката, за да спрете споделянето ѝ с устройството.",
|
||||
"Device": "Устройство",
|
||||
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Устройство \"{{name}}\" ({{device}}) с адрес {{address}} желае да се свърже. Да бъде ли добавено?",
|
||||
"Device ID": "Идентификатор на устройство",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Броят версии трябва да бъде число и не може да бъде празно.",
|
||||
"The path cannot be blank.": "Пътят не може да бъде празен.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "Ограничението на скоростта трябва да бъде положително число (0: неограничено)",
|
||||
"The remote device has not accepted sharing this folder.": "Отдалеченото устройство не е приело да споделя папката.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Интервалът на обхождане трябва да е положителен брой секунди.",
|
||||
"There are no devices to share this folder with.": "Няма устройства, с които да споделите папката.",
|
||||
"There are no file versions to restore.": "Файлът няма версии, които да бъдат възстановени.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Час на последна промяна на елемента",
|
||||
"Today": "Днес",
|
||||
"Trash Can File Versioning": "Версии от вида „кошче за отпадъци“",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Вид",
|
||||
"UNIX Permissions": "Права на UNIX",
|
||||
"Unavailable": "Няма налични",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Несподелени папки",
|
||||
"Untrusted": "Недоверено",
|
||||
"Up to Date": "Синхронизирано",
|
||||
"Updated": "Обновено",
|
||||
"Updated {%file%}": "{{file}} обновен",
|
||||
"Upgrade": "Обновяване",
|
||||
"Upgrade To {%version%}": "Обновяване до {{version}}",
|
||||
"Upgrading": "Обновяване",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Un comandament extern maneja el versionat. És necessari eliminar el fitxer de la carpeta compartida. Si la ruta a l'aplicació conté espais, hi ha que ficar-los entre cometes.",
|
||||
"Anonymous Usage Reporting": "Informe d'ús anònim",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "El format del informe anònim d'ús ha canviat. Vols canviar al nou format?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Are you sure you want to continue?",
|
||||
"Are you sure you want to override all remote changes?": "Are you sure you want to override all remote changes?",
|
||||
"Are you sure you want to permanently delete all these files?": "Are you sure you want to permanently delete all these files?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Defaults",
|
||||
"Delete": "Esborrar",
|
||||
"Delete Unexpected Items": "Delete Unexpected Items",
|
||||
"Deleted": "Esborrat",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Anul·lar tota la selecció",
|
||||
"Deselect devices to stop sharing this folder with.": "Deselect devices to stop sharing this folder with.",
|
||||
"Deselect folders to stop sharing with this device.": "Deselect folders to stop sharing with this device.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "El nombre de versions deu ser un nombre i no pot estar buit.",
|
||||
"The path cannot be blank.": "La ruta no pot estar buida.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "El llímit del ritme deu ser un nombre no negatiu (0: sense llímit)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "L'interval de reescaneig deu ser un nombre positiu de segons.",
|
||||
"There are no devices to share this folder with.": "There are no devices to share this folder with.",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Hora a la que l'ítem fou modificat per última vegada",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "Versionat d'arxius de la paperera",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Tipus",
|
||||
"UNIX Permissions": "UNIX Permissions",
|
||||
"Unavailable": "No disponible",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Unshared Folders",
|
||||
"Untrusted": "Untrusted",
|
||||
"Up to Date": "Actualitzat",
|
||||
"Updated": "Actualitzat",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Actualitzar",
|
||||
"Upgrade To {%version%}": "Actualitzar a {{version}}",
|
||||
"Upgrading": "Actualitzant",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Správu verzí obstarává externí příkaz. U toho je třeba, aby neaktuální soubory jím byly odsouvány pryč ze sdílené složky. Pokud popis umístění tohoto příkazu obsahuje mezeru, je třeba popis umístění uzavřít do uvozovek.",
|
||||
"Anonymous Usage Reporting": "Anonymní hlášení o používání",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Formát anonymního hlášení o používání byl změněn. Chcete přejít na nový formát?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Skutečně si přejete pokračovat?",
|
||||
"Are you sure you want to override all remote changes?": "Skutečně si přejete přebít všechny vzdálené změny?",
|
||||
"Are you sure you want to permanently delete all these files?": "Skutečně chcete smazat všechny tyto soubory?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Výchozí hodnoty",
|
||||
"Delete": "Smazat",
|
||||
"Delete Unexpected Items": "Smazat neočekávané položky",
|
||||
"Deleted": "Smazáno",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Zrušit výběr všeho",
|
||||
"Deselect devices to stop sharing this folder with.": "Zrušte výběr zařízení, se kterými již nemá být tato složka sdílena.",
|
||||
"Deselect folders to stop sharing with this device.": "Zrušte výběr složek, které se mají přestat sdílet s tímto zařízením.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Je třeba, aby počet verzí bylo číslo a nemůže zůstat nevyplněné.",
|
||||
"The path cannot be blank.": "Popis umístění nemůže zůstat nevyplněný.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "Je třeba, aby limit rychlosti bylo kladné číslo (0: bez limitu)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Je třeba, aby interval opakování skenování bylo kladné číslo.",
|
||||
"There are no devices to share this folder with.": "Nejsou žádná zařízení, se kterými lze sdílet tuto složku.",
|
||||
"There are no file versions to restore.": "Žádné verze souboru k obnovení.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Čas poslední modifikace položky",
|
||||
"Today": "Dnes",
|
||||
"Trash Can File Versioning": "Ponechávat jednu předchozí verzi (jako Koš) ",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Typ",
|
||||
"UNIX Permissions": "UNIX oprávnění",
|
||||
"Unavailable": "Nedostupné",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Nesdílené složky",
|
||||
"Untrusted": "Bez důvěry",
|
||||
"Up to Date": "Aktuální",
|
||||
"Updated": "Aktualizováno",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Přechod na novější verzi",
|
||||
"Upgrade To {%version%}": "Aktualizovat na {{version}}",
|
||||
"Upgrading": "Aktualizuje se",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "En ekstern kommando styrer versioneringen. Den skal fjerne filen fra den delte mappe. Hvis stien til programmet indeholder mellemrum, bør den sættes i anførselstegn.",
|
||||
"Anonymous Usage Reporting": "Anonym brugerstatistik",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Formatet for anonym brugerstatistik er ændret. Vil du flytte til det nye format?",
|
||||
"Apply": "Anvend",
|
||||
"Are you sure you want to continue?": "Fortsætte?",
|
||||
"Are you sure you want to override all remote changes?": "Tilsidesæt alle eksterne ændringer?",
|
||||
"Are you sure you want to permanently delete all these files?": "Slette valgte filer permanent?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Standarder",
|
||||
"Delete": "Slet",
|
||||
"Delete Unexpected Items": "Slet ikke forventede elementer ",
|
||||
"Deleted": "Slettet",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Fravælg alle",
|
||||
"Deselect devices to stop sharing this folder with.": "Fravælg enheder for at stoppe mappe deling.",
|
||||
"Deselect folders to stop sharing with this device.": "Fravælg mapper for at stoppe deling med denne enhed.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Antallet af versioner skal være et tal og feltet må ikke være tomt.",
|
||||
"The path cannot be blank.": "Stien må ikke være tom.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "Hastighedsbegrænsningen skal være et ikke-negativt tal (0: ingen begrænsning)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Genskanningsintervallet skal være et ikke-negativt antal sekunder.",
|
||||
"There are no devices to share this folder with.": "Der er ingen enheder at dele denne mappe med.",
|
||||
"There are no file versions to restore.": "Der er ingen fil versioner at gendanne.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Tidspunkt for seneste ændring af filen",
|
||||
"Today": "I dag",
|
||||
"Trash Can File Versioning": "Versionering med papirkurv",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Type",
|
||||
"UNIX Permissions": "UNIX rettigheder",
|
||||
"Unavailable": "Ikke tilgængelig",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Ikke delte mapper",
|
||||
"Untrusted": "Ikke troværdig",
|
||||
"Up to Date": "Fuldt opdateret",
|
||||
"Updated": "Opdateret",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Opgradér",
|
||||
"Upgrade To {%version%}": "Opgradér til {{version}}",
|
||||
"Upgrading": "Opgraderer",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Ein externer Befehl behandelt die Versionierung. Die Datei aus dem freigegebenen Ordner muss entfernen werden. Wenn der Pfad der Anwendung Leerzeichen enthält, sollte dieser in Anführungszeichen stehen.",
|
||||
"Anonymous Usage Reporting": "Anonymer Nutzungsbericht",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Das Format des anonymen Nutzungsberichts hat sich geändert. Möchten Sie auf das neue Format umsteigen?",
|
||||
"Apply": "Anwenden",
|
||||
"Are you sure you want to continue?": "Sind Sie sicher, dass Sie fortfahren möchten?",
|
||||
"Are you sure you want to override all remote changes?": "Sind Sie sicher, dass Sie alle entfernten Änderungen überschreiben möchten?",
|
||||
"Are you sure you want to permanently delete all these files?": "Sind Sie sicher, dass Sie all diese Dateien dauerhaft löschen möchten?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Vorgaben",
|
||||
"Delete": "Löschen",
|
||||
"Delete Unexpected Items": "Unerwartete Elemente löschen",
|
||||
"Deleted": "Gelöscht",
|
||||
"Deleted {%file%}": "{{file}} gelöscht",
|
||||
"Deselect All": "Alle abwählen",
|
||||
"Deselect devices to stop sharing this folder with.": "Geräte abwählen, um diesen Ordner nicht mehr damit zu teilen.",
|
||||
"Deselect folders to stop sharing with this device.": "Ordner abwählen, um sie nicht mehr für mit diesem Gerät zu teilen.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Die Anzahl von Versionen muss eine Ganzzahl und darf nicht leer sein.",
|
||||
"The path cannot be blank.": "Der Pfad darf nicht leer sein.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "Das Datenratelimit muss eine nicht negative Zahl sein (0 = kein Limit).",
|
||||
"The remote device has not accepted sharing this folder.": "Dieser geteilte Ordner wurde vom Gerät nicht angenommen.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Das Scanintervall muss eine nicht negative Anzahl (in Sekunden) sein.",
|
||||
"There are no devices to share this folder with.": "Es gibt keine Geräte, mit denen dieser Ordner geteilt werden kann.",
|
||||
"There are no file versions to restore.": "Es gibt keine Dateiversionen zum Wiederherstellen.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Zeit der letzten Änderung des Elements",
|
||||
"Today": "Heute",
|
||||
"Trash Can File Versioning": "Papierkorb Dateiversionierung",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Typ",
|
||||
"UNIX Permissions": "UNIX-Berechtigungen",
|
||||
"Unavailable": " Nicht verfügbar",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Nicht geteilte Ordner",
|
||||
"Untrusted": "Nicht vertraut",
|
||||
"Up to Date": "Aktuell",
|
||||
"Updated": "Aktualisiert",
|
||||
"Updated {%file%}": "{{file}} aktualisiert",
|
||||
"Upgrade": "Aktualisierung",
|
||||
"Upgrade To {%version%}": "Aktualisierung auf {{version}}",
|
||||
"Upgrading": "Wird aktualisiert",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Μια εξωτερική εντολή χειρίζεται την τήρηση εκδόσεων και αναλαμβάνει να αφαιρέσει το αρχείο από τον συγχρονισμένο φάκελο. Αν η διαδρομή προς την εφαρμογή περιέχει διαστήματα, πρέπει να εσωκλείεται σε εισαγωγικά. ",
|
||||
"Anonymous Usage Reporting": "Ανώνυμα στοιχεία χρήσης",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Η μορφή της αναφοράς ανώνυμων στοιχείων χρήσης έχει αλλάξει. Επιθυμείτε να μεταβείτε στη νέα μορφή;",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Are you sure you want to continue?",
|
||||
"Are you sure you want to override all remote changes?": "Are you sure you want to override all remote changes?",
|
||||
"Are you sure you want to permanently delete all these files?": "Are you sure you want to permanently delete all these files?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Defaults",
|
||||
"Delete": "Διαγραφή",
|
||||
"Delete Unexpected Items": "Delete Unexpected Items",
|
||||
"Deleted": "Διαγραμμένα",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Αποεπιλογή όλων",
|
||||
"Deselect devices to stop sharing this folder with.": "Αποεπιλέξτε συσκευές για να σταματήσει ο διαμοιρασμός του φακέλου με αυτές.",
|
||||
"Deselect folders to stop sharing with this device.": "Deselect folders to stop sharing with this device.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Ο αριθμός εκδόσεων πρέπει να είναι αριθμός και σίγουρα όχι κενό.",
|
||||
"The path cannot be blank.": "Το μονοπάτι δεν μπορεί να είναι κενό.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "Το όριο ταχύτητας πρέπει να είναι ένας μη-αρνητικός αριθμός (0: χωρίς όριο)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Ο χρόνος επανελέγχου για αλλαγές είναι σε δευτερόλεπτα (δηλ. θετικός αριθμός).",
|
||||
"There are no devices to share this folder with.": "Δεν υπάρχουν συσκευές με τις οποίες διαμοιράζεται αυτός ο φάκελος.",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Ώρα τελευταίας τροποποίησης του στοιχείου",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "Τήρηση εκδόσεων κάδου ανακύκλωσης",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Τύπος",
|
||||
"UNIX Permissions": "Άδειες αρχείων UNIX",
|
||||
"Unavailable": "Μη διαθέσιμο",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Unshared Folders",
|
||||
"Untrusted": "Untrusted",
|
||||
"Up to Date": "Ενημερωμένη",
|
||||
"Updated": "Ενημερωμένο",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Αναβάθμιση",
|
||||
"Upgrade To {%version%}": "Αναβάθμιση στην έκδοση {{version}}",
|
||||
"Upgrading": "Αναβάθμιση",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.",
|
||||
"Anonymous Usage Reporting": "Anonymous Usage Reporting",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Anonymous usage report format has changed. Would you like to move to the new format?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Are you sure you want to continue?",
|
||||
"Are you sure you want to override all remote changes?": "Are you sure you want to override all remote changes?",
|
||||
"Are you sure you want to permanently delete all these files?": "Are you sure you want to permanently delete all these files?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Defaults",
|
||||
"Delete": "Delete",
|
||||
"Delete Unexpected Items": "Delete Unexpected Items",
|
||||
"Deleted": "Deleted",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Deselect All",
|
||||
"Deselect devices to stop sharing this folder with.": "Deselect devices to stop sharing this folder with.",
|
||||
"Deselect folders to stop sharing with this device.": "Deselect folders to stop sharing with this device.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "The number of versions must be a number and cannot be blank.",
|
||||
"The path cannot be blank.": "The path cannot be blank.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "The rate limit must be a non-negative number (0: no limit)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "The rescan interval must be a non-negative number of seconds.",
|
||||
"There are no devices to share this folder with.": "There are no devices to share this folder with.",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Time the item was last modified",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "Bin File Versioning",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Type",
|
||||
"UNIX Permissions": "UNIX Permissions",
|
||||
"Unavailable": "Unavailable",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Unshared Folders",
|
||||
"Untrusted": "Untrusted",
|
||||
"Up to Date": "Up to Date",
|
||||
"Updated": "Updated",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Upgrade",
|
||||
"Upgrade To {%version%}": "Upgrade To {{version}}",
|
||||
"Upgrading": "Upgrading",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.",
|
||||
"Anonymous Usage Reporting": "Anonymous Usage Reporting",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Anonymous usage report format has changed. Would you like to move to the new format?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Are you sure you want to continue?",
|
||||
"Are you sure you want to override all remote changes?": "Are you sure you want to override all remote changes?",
|
||||
"Are you sure you want to permanently delete all these files?": "Are you sure you want to permanently delete all these files?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Defaults",
|
||||
"Delete": "Delete",
|
||||
"Delete Unexpected Items": "Delete Unexpected Items",
|
||||
"Deleted": "Deleted",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Deselect All",
|
||||
"Deselect devices to stop sharing this folder with.": "Deselect devices to stop sharing this folder with.",
|
||||
"Deselect folders to stop sharing with this device.": "Deselect folders to stop sharing with this device.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "The number of versions must be a number and cannot be blank.",
|
||||
"The path cannot be blank.": "The path cannot be blank.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "The rate limit must be a non-negative number (0: no limit)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "The rescan interval must be a non-negative number of seconds.",
|
||||
"There are no devices to share this folder with.": "There are no devices to share this folder with.",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Time the item was last modified",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "Rubbish Bin File Versioning",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Type",
|
||||
"UNIX Permissions": "UNIX Permissions",
|
||||
"Unavailable": "Unavailable",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Unshared Folders",
|
||||
"Untrusted": "Untrusted",
|
||||
"Up to Date": "Up to Date",
|
||||
"Updated": "Updated",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Upgrade",
|
||||
"Upgrade To {%version%}": "Upgrade to {{version}}",
|
||||
"Upgrading": "Upgrading",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.",
|
||||
"Anonymous Usage Reporting": "Anonymous Usage Reporting",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Anonymous usage report format has changed. Would you like to move to the new format?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Are you sure you want to continue?",
|
||||
"Are you sure you want to override all remote changes?": "Are you sure you want to override all remote changes?",
|
||||
"Are you sure you want to permanently delete all these files?": "Are you sure you want to permanently delete all these files?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Defaults",
|
||||
"Delete": "Delete",
|
||||
"Delete Unexpected Items": "Delete Unexpected Items",
|
||||
"Deleted": "Deleted",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Deselect All",
|
||||
"Deselect devices to stop sharing this folder with.": "Deselect devices to stop sharing this folder with.",
|
||||
"Deselect folders to stop sharing with this device.": "Deselect folders to stop sharing with this device.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "The number of versions must be a number and cannot be blank.",
|
||||
"The path cannot be blank.": "The path cannot be blank.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "The rate limit must be a non-negative number (0: no limit)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "The rescan interval must be a non-negative number of seconds.",
|
||||
"There are no devices to share this folder with.": "There are no devices to share this folder with.",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Time the item was last modified",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "Trash Can File Versioning",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Type",
|
||||
"UNIX Permissions": "UNIX Permissions",
|
||||
"Unavailable": "Unavailable",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Unshared Folders",
|
||||
"Untrusted": "Untrusted",
|
||||
"Up to Date": "Up to Date",
|
||||
"Updated": "Updated",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Upgrade",
|
||||
"Upgrade To {%version%}": "Upgrade To {{version}}",
|
||||
"Upgrading": "Upgrading",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Ekstera komando manipulas la version. Ĝi devas forigi la dosieron el la komunigita dosierujo. Se la vojo al la apliko elhavas blankoj, ĝi devas esti inter citiloj.",
|
||||
"Anonymous Usage Reporting": "Anonima Raporto de Uzado",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Formato de anonima raporto de uzado ŝanĝis. Ĉu vi ŝatus transiri al la nova formato?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Ĉu vi certas, ke vi volas daŭrigi?",
|
||||
"Are you sure you want to override all remote changes?": "Ĉu vi certas, ke vi volas transpasi ĉiujn forajn ŝanĝojn?",
|
||||
"Are you sure you want to permanently delete all these files?": "Ĉu vi certas, ke vi volas porĉiame forigi ĉiujn ĉi tiujn dosierojn?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Defaults",
|
||||
"Delete": "Forigu",
|
||||
"Delete Unexpected Items": "Delete Unexpected Items",
|
||||
"Deleted": "Forigita",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Malelekti Ĉiujn",
|
||||
"Deselect devices to stop sharing this folder with.": "Malelekti aparatojn por ĉesi komunigi tiun ĉi dosierujon kun ili.",
|
||||
"Deselect folders to stop sharing with this device.": "Deselect folders to stop sharing with this device.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "La nombro da versioj devas esti nombro kaj ne povas esti malplena.",
|
||||
"The path cannot be blank.": "La vojo ne povas esti malplena.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "La rapideca limo devas esti pozitiva nombro (0: senlimo)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "La intervalo de reskano devas esti pozitiva nombro da sekundoj.",
|
||||
"There are no devices to share this folder with.": "Estas neniu aparato kun kiu komunigi tiun ĉi dosierujon.",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Tempo de lasta modifo de la ero",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "Rubuja Dosiera Versionado",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Tipo",
|
||||
"UNIX Permissions": "Permesoj UNIX",
|
||||
"Unavailable": "Ne disponebla",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Unshared Folders",
|
||||
"Untrusted": "Untrusted",
|
||||
"Up to Date": "Ĝisdata",
|
||||
"Updated": "Ĝisdatigita",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Altgradigo",
|
||||
"Upgrade To {%version%}": "Altgradigi Al {{version}}",
|
||||
"Upgrading": "Altgradigata",
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"Add Folder": "Agregar Carpeta",
|
||||
"Add Remote Device": "Añadir un dispositivo",
|
||||
"Add devices from the introducer to our device list, for mutually shared folders.": "Añadir dispositivos desde el introductor a nuestra lista de dispositivos, para las carpetas compartidas mutuamente.",
|
||||
"Add ignore patterns": "Agregar patrones a ignorar",
|
||||
"Add ignore patterns": "Añadir patrones a ignorar",
|
||||
"Add new folder?": "¿Agregar una carpeta nueva?",
|
||||
"Additionally the full rescan interval will be increased (times 60, i.e. new default of 1h). You can also configure it manually for every folder later after choosing No.": "De manera adicional, el intervalo de escaneo será incrementado (por ejemplo, times 60, establece un nuevo intervalo por defecto de una hora). También puedes configurarlo manualmente para cada carpeta tras elegir el número.",
|
||||
"Address": "Dirección",
|
||||
@@ -19,7 +19,7 @@
|
||||
"Advanced": "Avanzado",
|
||||
"Advanced Configuration": "Configuración Avanzada",
|
||||
"All Data": "Todos los datos",
|
||||
"All Time": "All Time",
|
||||
"All Time": "Todo el tiempo",
|
||||
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "Todos las carpetas compartidas con este equipo deben ser protegidas con una contraseña, de manera que todos los datos enviados sean ilegibles sin la contraseña dada.",
|
||||
"Allow Anonymous Usage Reporting?": "¿Deseas permitir el envío anónimo de informes de uso?",
|
||||
"Allowed Networks": "Redes permitidas",
|
||||
@@ -28,14 +28,15 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Un comando externo maneja el versionado. Tiene que eliminar el fichero de la carpeta compartida. Si la ruta a la aplicación contiene espacios, hay que escribirla entre comillas.",
|
||||
"Anonymous Usage Reporting": "Informe anónimo de uso",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "El formato del informe anónimo de uso ha cambiado. ¿Quieres cambiar al nuevo formato?",
|
||||
"Are you sure you want to continue?": "¿Está seguro(a) de que desea continuar?",
|
||||
"Are you sure you want to override all remote changes?": "¿Está seguro(a) de que desea sobreescribir todos los cambios remotos?",
|
||||
"Are you sure you want to permanently delete all these files?": "¿Estás seguro(a) de que quieres eliminar permanentemente todos estos ficheros?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "¿Seguro que quieres continuar?",
|
||||
"Are you sure you want to override all remote changes?": "¿Seguro que quieres sobreescribir todos los cambios remotos?",
|
||||
"Are you sure you want to permanently delete all these files?": "¿Seguro que quieres eliminar permanentemente todos estos archivos?",
|
||||
"Are you sure you want to remove device {%name%}?": "¿Estás seguro de que quieres quitar el dispositivo {{name}}?",
|
||||
"Are you sure you want to remove folder {%label%}?": "¿Estás seguro de que quieres quitar la carpeta {{label}}?",
|
||||
"Are you sure you want to restore {%count%} files?": "¿Estás seguro de que quieres restaurar {{count}} ficheros?",
|
||||
"Are you sure you want to revert all local changes?": "¿Está seguro(a) de que desea revertir todos los cambios locales?",
|
||||
"Are you sure you want to upgrade?": "¿Está seguro(a) de que desea actualizar?",
|
||||
"Are you sure you want to revert all local changes?": "¿Seguro que quieres revertir todos los cambios locales?",
|
||||
"Are you sure you want to upgrade?": "¿Seguro que quieres actualizar?",
|
||||
"Auto Accept": "Auto aceptar",
|
||||
"Automatic Crash Reporting": "Informe automático de errores",
|
||||
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Ahora la actualización automática permite elegir entre versiones estables o versiones candidatas.",
|
||||
@@ -48,10 +49,10 @@
|
||||
"Cancel": "Cancelar",
|
||||
"Changelog": "Registro de cambios",
|
||||
"Clean out after": "Limpiar tras",
|
||||
"Cleaning Versions": "Limpiando Versiones",
|
||||
"Cleanup Interval": "Intervalo de Limpieza",
|
||||
"Cleaning Versions": "Limpiando versiones",
|
||||
"Cleanup Interval": "Intervalo de limpieza",
|
||||
"Click to see discovery failures": "Clica para ver fallos de descubrimiento.",
|
||||
"Click to see full identification string and QR code.": "Haga clic para ver la cadena de identificación completa y su código QR.",
|
||||
"Click to see full identification string and QR code.": "Haz clic para ver la cadena de identificación completa y el código QR.",
|
||||
"Close": "Cerrar",
|
||||
"Command": "Acción",
|
||||
"Comment, when used at the start of a line": "Comentar, cuando se usa al comienzo de una línea",
|
||||
@@ -66,18 +67,18 @@
|
||||
"Copied from original": "Copiado del original",
|
||||
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 los siguientes Colaboradores:",
|
||||
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Crear patrones a ignorar, sobreescribiendo un fichero existente en {{path}}.",
|
||||
"Currently Shared With Devices": "Actualmente Compartida Con Los Equipos",
|
||||
"Custom Range": "Custom Range",
|
||||
"Currently Shared With Devices": "Actualmente compartida con los equipos",
|
||||
"Custom Range": "Rango personalizado",
|
||||
"Danger!": "¡Peligro!",
|
||||
"Debugging Facilities": "Ayudas a la depuración",
|
||||
"Default Configuration": "Configuración Por Defecto",
|
||||
"Default Device": "Equipo Por Defecto",
|
||||
"Default Folder": "Carpeta Por Defecto",
|
||||
"Default Configuration": "Configuración por defecto",
|
||||
"Default Device": "Equipo por defecto",
|
||||
"Default Folder": "Carpeta por defecto",
|
||||
"Default Folder Path": "Ruta de la carpeta por defecto",
|
||||
"Defaults": "Valores Por Defecto",
|
||||
"Defaults": "Valores por defecto",
|
||||
"Delete": "Eliminar",
|
||||
"Delete Unexpected Items": "Borrar Elementos Inesperados",
|
||||
"Deleted": "Eliminado",
|
||||
"Delete Unexpected Items": "Borrar elementos inesperados",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Deseleccionar Todo",
|
||||
"Deselect devices to stop sharing this folder with.": "Deseleccione los equipos con los cuales dejar de compartir esta carpeta.",
|
||||
"Deselect folders to stop sharing with this device.": "Deseleccione las carpetas para dejar de compartir con este equipo.",
|
||||
@@ -130,7 +131,7 @@
|
||||
"Error": "Error",
|
||||
"External File Versioning": "Versionado externo de fichero",
|
||||
"Failed Items": "Elementos fallidos",
|
||||
"Failed to load file versions.": "Failed to load file versions.",
|
||||
"Failed to load file versions.": "Error al cargar las versiones del archivo.",
|
||||
"Failed to load ignore patterns.": "Fallo al cargar patrones a ignorar",
|
||||
"Failed to setup, retrying": "Fallo al configurar, reintentando",
|
||||
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Se espera un fallo al conectar a los servidores IPv6 si no hay conectividad IPv6.",
|
||||
@@ -185,9 +186,9 @@
|
||||
"Keep Versions": "Mantener versiones",
|
||||
"LDAP": "LDAP",
|
||||
"Largest First": "Más grande primero",
|
||||
"Last 30 Days": "Last 30 Days",
|
||||
"Last 7 Days": "Last 7 Days",
|
||||
"Last Month": "Last Month",
|
||||
"Last 30 Days": "Últimos 30 días",
|
||||
"Last 7 Days": "Últimos 7 días",
|
||||
"Last Month": "Último mes",
|
||||
"Last Scan": "Último escaneo",
|
||||
"Last seen": "Visto por última vez",
|
||||
"Latest Change": "Último Cambio",
|
||||
@@ -377,21 +378,23 @@
|
||||
"The number of versions must be a number and cannot be blank.": "El número de versiones debe ser un número y no puede estar vacío.",
|
||||
"The path cannot be blank.": "La ruta no puede estar vacía.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "El límite de velocidad debe ser un número no negativo (0: sin límite)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "El intervalo de actualización debe ser un número positivo de segundos.",
|
||||
"There are no devices to share this folder with.": "No hay equipos con los cuales compartir esta carpeta.",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
"There are no file versions to restore.": "No hay versiones de archivo que restaurar.",
|
||||
"There are no folders to share with this device.": "No hay carpetas para compartir con este equipo.",
|
||||
"They are retried automatically and will be synced when the error is resolved.": "Se reintentarán de forma automática y se sincronizarán cuando se resuelva el error.",
|
||||
"This Device": "Este Dispositivo",
|
||||
"This Month": "This Month",
|
||||
"This Month": "Este mes",
|
||||
"This can easily give hackers access to read and change any files on your computer.": "Esto podría permitir fácilmente el acceso a hackers para leer y modificar cualquier fichero de tu equipo.",
|
||||
"This device cannot automatically discover other devices or announce its own address to be found by others. Only devices with statically configured addresses can connect.": "Este dispositivo no puede descubrir automáticamente a otros dispositivos o anunciar su propia dirección para que sea encontrado con otros. Solo dispositivos con direcciones configuradas como estáticas pueden conectarse.",
|
||||
"This is a major version upgrade.": "Hay una actualización importante.",
|
||||
"This setting controls the free space required on the home (i.e., index database) disk.": "Este ajuste controla el espacio libre necesario en el disco principal (por ejemplo, el índice de la base de datos).",
|
||||
"Time": "Hora",
|
||||
"Time the item was last modified": "Tiempo en el que se modificó el ítem por última vez",
|
||||
"Today": "Today",
|
||||
"Today": "Hoy",
|
||||
"Trash Can File Versioning": "Versionado de archivos de la papelera",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Tipo",
|
||||
"UNIX Permissions": "Permisos de UNIX",
|
||||
"Unavailable": "No disponible",
|
||||
@@ -402,11 +405,11 @@
|
||||
"Unignore": "Designorar",
|
||||
"Unknown": "Desconocido",
|
||||
"Unshared": "No compartido",
|
||||
"Unshared Devices": "Equipos no Compartidos",
|
||||
"Unshared Folders": "Carpetas no Compartidas",
|
||||
"Untrusted": "No Confiable",
|
||||
"Unshared Devices": "Equipos no compartidos",
|
||||
"Unshared Folders": "Carpetas no compartidas",
|
||||
"Untrusted": "No confiable",
|
||||
"Up to Date": "Actualizado",
|
||||
"Updated": "Actualizado",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Actualizar",
|
||||
"Upgrade To {%version%}": "Actualizar a {{version}}",
|
||||
"Upgrading": "Actualizando",
|
||||
@@ -420,9 +423,9 @@
|
||||
"Versions": "Versiones",
|
||||
"Versions Path": "Ruta de las versiones",
|
||||
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Las versiones se borran automáticamente si son más antiguas que la edad máxima o exceden el número de ficheros permitidos en un intervalo.",
|
||||
"Waiting to Clean": "Esperando para Limpiar",
|
||||
"Waiting to Scan": "Esperando para Escanear",
|
||||
"Waiting to Sync": "Esperando para Sincronizar",
|
||||
"Waiting to Clean": "Esperando para limpiar",
|
||||
"Waiting to Scan": "Esperando para escanear",
|
||||
"Waiting to Sync": "Esperando para sincronizar",
|
||||
"Warning": "Advertencia",
|
||||
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "¡Peligro! Esta ruta es un directorio principal de la carpeta ya existente \"{{otherFolder}}\".",
|
||||
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "'Peligro! Esta ruta es un subdirectorio de la carpeta ya existente \"{{otherFolderLabel}}\" ({{otherFolder}}).",
|
||||
@@ -435,7 +438,7 @@
|
||||
"When adding a new device, keep in mind that this device must be added on the other side too.": "Cuando añada un nuevo dispositivo, tenga en cuenta que este debe añadirse también en el otro lado.",
|
||||
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "Cuando añada una nueva carpeta, tenga en cuenta que su ID se usa para unir carpetas entre dispositivos. Son sensibles a las mayúsculas y deben coincidir exactamente entre todos los dispositivos.",
|
||||
"Yes": "Si",
|
||||
"Yesterday": "Yesterday",
|
||||
"Yesterday": "Ayer",
|
||||
"You can also select one of these nearby devices:": "Puedes seleccionar también uno de estos dispositivos cercanos:",
|
||||
"You can change your choice at any time in the Settings dialog.": "Puedes cambiar tu elección en cualquier momento en el panel de Ajustes.",
|
||||
"You can read more about the two release channels at the link below.": "Puedes leer más sobre los dos método de publicación de versiones en el siguiente enlace.",
|
||||
@@ -443,7 +446,7 @@
|
||||
"You have no ignored folders.": "No tienes carpetas ignoradas.",
|
||||
"You have unsaved changes. Do you really want to discard them?": "Tienes cambios sin guardar. ¿Quieres descartarlos?",
|
||||
"You must keep at least one version.": "Debes mantener al menos una versión.",
|
||||
"You should never add or change anything locally in a \"{%receiveEncrypted%}\" folder.": "Nunca debe agregar o cambiar nada localmente en una carpeta \"{{receiveEncrypted}}\".",
|
||||
"You should never add or change anything locally in a \"{%receiveEncrypted%}\" folder.": "Nunca debes añadir o cambiar nada localmente en una carpeta \"{{receiveEncrypted}}\".",
|
||||
"days": "días",
|
||||
"directories": "directorios",
|
||||
"files": "archivos",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Un comando externo maneja las versiones. Tienes que eliminar el archivo de la carpeta compartida. Si la ruta a la aplicación contiene espacios, ésta debe estar entre comillas.",
|
||||
"Anonymous Usage Reporting": "Informe anónimo de uso",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "El formato del informe de uso anónimo a cambiado. ¿Desearía usar el nuevo formato?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "¿Está seguro(a) de que desea continuar?",
|
||||
"Are you sure you want to override all remote changes?": "¿Está seguro(a) de que desea sobreescribir todos los cambios remotos?",
|
||||
"Are you sure you want to permanently delete all these files?": "¿Está seguro de que desea eliminar permanente todos estos archivos?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Valores Predeterminados",
|
||||
"Delete": "Eliminar",
|
||||
"Delete Unexpected Items": "Borrar Elementos Inesperados",
|
||||
"Deleted": "Eliminado",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Deseleccionar Todo",
|
||||
"Deselect devices to stop sharing this folder with.": "Deseleccionar dispositivos con los cuales dejar de compartir esta carpeta.",
|
||||
"Deselect folders to stop sharing with this device.": "Deseleccionar carpetas para dejar de compartir con este dispositivo.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "El número de versiones debe ser un número y no puede estar vacío.",
|
||||
"The path cannot be blank.": "La ruta no puede estar vacía.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "El límite de velocidad debe ser un número no negativo (0: sin límite)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "El intervalo de actualización debe ser un número positivo de segundos.",
|
||||
"There are no devices to share this folder with.": "No hay dispositivos con los cuales compartir esta carpeta.",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Hora en que el ítem fue modificado por última vez",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "Versionado de archivos de la papelera",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Tipo",
|
||||
"UNIX Permissions": "Permisos de UNIX",
|
||||
"Unavailable": "No disponible",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Carpetas no Compartidas",
|
||||
"Untrusted": "No Confiable",
|
||||
"Up to Date": "Actualizado",
|
||||
"Updated": "Actualizado",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Actualizar",
|
||||
"Upgrade To {%version%}": "Actualizar a {{version}}",
|
||||
"Upgrading": "Actualizando",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Kanpoko kontrolagailu batek fitxategien bertsioak kudeatzen ditu. Fitxategiak kendu behar ditu errepertorio sinkronizatuan. Aplikaziorako ibilbideak espazioak baditu, komatxo artean egon behar du.",
|
||||
"Anonymous Usage Reporting": "Izenik gabeko erabiltze erreportak",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Erabilera anonimoko txostenaren formatua aldatu egin da. Formatu berria erabili nahi duzu?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Ziur zaude jarraitu nahi duzula?",
|
||||
"Are you sure you want to override all remote changes?": "Ziur zaude urruneko aldaketa guztiak gainidatzi nahi dituzula?",
|
||||
"Are you sure you want to permanently delete all these files?": "Ziur zaude fitxategi guzti hauek betirako ezabatu nahi dituzula?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Lehenetsiak",
|
||||
"Delete": "Kendu",
|
||||
"Delete Unexpected Items": "Ezabatu ustekabeko elementuak",
|
||||
"Deleted": "Kendua",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Hautaketa guztia kendu",
|
||||
"Deselect devices to stop sharing this folder with.": "Desautatu karpeta honekin partekatu nahi ez dituzun gailuak.",
|
||||
"Deselect folders to stop sharing with this device.": "Desautatu karpetak gailu honekin partekatzeari uzteko.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Bertsioen kopuruak numerikoa behar du izan eta ez da hutsa izaiten ahal",
|
||||
"The path cannot be blank.": "Bidea ez da hutsa izaiten ahal",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "Ixuriaren emaria ez da negatiboa izaiten ahal (0 = mugarik gabekoa)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Ikerketaren tartea ez da segundo kopuru negatiboa izaiten ahal",
|
||||
"There are no devices to share this folder with.": "Ez dago partekatutako erabilera horri gehitzeko gailurik.",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Itema azkenekoz aldatu zen ordua",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "Zakarrontzia",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Mota",
|
||||
"UNIX Permissions": "UNIX baimenak",
|
||||
"Unavailable": "Ez dago erabilgarri",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Partekatu gabeko karpetak",
|
||||
"Untrusted": "Ez da fidagarria",
|
||||
"Up to Date": "Eguneratua",
|
||||
"Updated": "Berritua",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Aktualizatu",
|
||||
"Upgrade To {%version%}": "Egunetaratu {{version}}-ari buruz",
|
||||
"Upgrading": "Syncthing-en egunetaratzea",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Ulkoinen komento hallitsee versionnin. Sen täytyy poistaa tiedosto synkronoidusta kansiosta. Mikäli ohjelman polussa on välilyöntejä se on laitettava lainausmerkkeihin.",
|
||||
"Anonymous Usage Reporting": "Anonyymi käyttöraportointi",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Anonyymi käyttöraportti on muuttunut. Haluatko vaihtaa uuteen muotoon?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Are you sure you want to continue?",
|
||||
"Are you sure you want to override all remote changes?": "Are you sure you want to override all remote changes?",
|
||||
"Are you sure you want to permanently delete all these files?": "Are you sure you want to permanently delete all these files?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Defaults",
|
||||
"Delete": "Poista",
|
||||
"Delete Unexpected Items": "Delete Unexpected Items",
|
||||
"Deleted": "Poistettu",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Poista valinnat",
|
||||
"Deselect devices to stop sharing this folder with.": "Deselect devices to stop sharing this folder with.",
|
||||
"Deselect folders to stop sharing with this device.": "Deselect folders to stop sharing with this device.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Versioiden määrän rulee olla numero, eikä se voi olla tyhjä.",
|
||||
"The path cannot be blank.": "Polku ei voi olla tyhjä.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "Nopeusrajan tulee olla positiivinen luku tai nolla. (0: ei rajaa)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Uudelleenskannauksen aikavälin tulee olla ei-negatiivinen numero sekunteja.",
|
||||
"There are no devices to share this folder with.": "There are no devices to share this folder with.",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Aika jolloin kohdetta viimeksi muokattiin",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "Roskakorin tiedostoversiointi",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Tyyppi",
|
||||
"UNIX Permissions": "UNIX Permissions",
|
||||
"Unavailable": "Ei saatavilla",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Unshared Folders",
|
||||
"Untrusted": "Untrusted",
|
||||
"Up to Date": "Ajan tasalla",
|
||||
"Updated": "Päivitetty",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Päivitys",
|
||||
"Upgrade To {%version%}": "Päivitä versioon {{version}}",
|
||||
"Upgrading": "Päivitetään",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Une commande externe gère les versions de fichiers. Il lui incombe de supprimer les fichiers du répertoire partagé. Si le chemin contient des espaces, il doit être spécifié entre guillemets.",
|
||||
"Anonymous Usage Reporting": "Rapport anonyme de statistiques d'utilisation",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Le format du rapport anonyme d'utilisation a changé. Voulez-vous passer au nouveau format ?",
|
||||
"Apply": "Appliquer",
|
||||
"Are you sure you want to continue?": "Confirmez-vous ?",
|
||||
"Are you sure you want to override all remote changes?": "Voulez-vous vraiment écraser tous les changements distants ?",
|
||||
"Are you sure you want to permanently delete all these files?": "Êtes-vous sûrs de vouloir définitivement supprimer tous ces fichiers ?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Personnalisation",
|
||||
"Delete": "Supprimer",
|
||||
"Delete Unexpected Items": "Supprimer les éléments inattendus",
|
||||
"Deleted": "Supprimé",
|
||||
"Deleted {%file%}": "{{file}} supprimé",
|
||||
"Deselect All": "Tout déselectionner",
|
||||
"Deselect devices to stop sharing this folder with.": "Désélectionnez les appareils avec lesquels vous ne souhaitez plus partager ces données.",
|
||||
"Deselect folders to stop sharing with this device.": "Désélectionnez les partages auxquels cet appareil doit plus participer.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Le nombre de versions doit être numérique, et ne peut pas être vide.",
|
||||
"The path cannot be blank.": "Le chemin ne peut pas être vide.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "La limite de débit ne doit pas être négative (0 = pas de limite)",
|
||||
"The remote device has not accepted sharing this folder.": "L'appareil distant n'a pas (encore ?) accepté de partager ce répertoire.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "L'intervalle d'analyse ne doit pas être un nombre négatif de secondes.",
|
||||
"There are no devices to share this folder with.": "Il n'y a aucun appareil à ajouter à ce partage.",
|
||||
"There are no file versions to restore.": "Aucune version de fichier à restaurer.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Dernière modification de l'élément",
|
||||
"Today": "Aujourd'hui",
|
||||
"Trash Can File Versioning": "Style poubelle",
|
||||
"Twitter": "Piaf",
|
||||
"Type": "Type",
|
||||
"UNIX Permissions": "Permissions UNIX",
|
||||
"Unavailable": "Indisponible",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Non partagés",
|
||||
"Untrusted": "Retirer la confiance (chiffrer tous les partages)",
|
||||
"Up to Date": "À jour",
|
||||
"Updated": "Mis à jour",
|
||||
"Updated {%file%}": "{{file}} modifié",
|
||||
"Upgrade": "Mettre à jour",
|
||||
"Upgrade To {%version%}": "Mettre à jour vers {{version}}",
|
||||
"Upgrading": "Mise à jour de Syncthing",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "In ekstern kommando soarget foar it ferzjebehear. It moat de triem út de dielde map fuortsmite. As it paad nei de applikaasje romtes hat, moat it tusken oanheltekens sette wurden.",
|
||||
"Anonymous Usage Reporting": "Anonym brûkensrapportaazje",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "It formaat fan de rapportaazje fan anonime gebrûksynformaasje is feroare. Wolle jo op dit nije formaat oerstappe?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Binne jo der wis fan dat jo trochgean wolle?",
|
||||
"Are you sure you want to override all remote changes?": "Are you sure you want to override all remote changes?",
|
||||
"Are you sure you want to permanently delete all these files?": "Binne jo der wis fan dat jo al dizze bestannen permanint wiskje wolle?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Standertwearden",
|
||||
"Delete": "Fuortsmite",
|
||||
"Delete Unexpected Items": " Unferwachte items wiskje",
|
||||
"Deleted": "Fuortsmiten",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Alles Deselektearje",
|
||||
"Deselect devices to stop sharing this folder with.": "Kies de apparaten om dizze map net langer mei te dielen.",
|
||||
"Deselect folders to stop sharing with this device.": "Deselektearje mappen om it dielen mei dit apparaat te stopjen.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "It tal fan ferzjes moat in nûmer wêze en mei net leech wêze.",
|
||||
"The path cannot be blank.": "It paad mei net leech wêze.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "It fluggenslimyt moat in posityf nûmer wêze (0: gjin limyt)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "It wersken-ynterfal moat in posityf tal fan sekonden wêze.",
|
||||
"There are no devices to share this folder with.": "Der binne gjin apparaten om dizze map mei te dielen.",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Tiidstip dat it ûnderdiel foar it lest oanpast waard.",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "Jiskefet-triemferzjebehear",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Type",
|
||||
"UNIX Permissions": "UNIX-Rjochten",
|
||||
"Unavailable": "Net beskikber",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Net-dielde mappen",
|
||||
"Untrusted": "Net betroud",
|
||||
"Up to Date": "By de tiid",
|
||||
"Updated": "Fernijt",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Fernije",
|
||||
"Upgrade To {%version%}": "Fernije nei {{version}}",
|
||||
"Upgrading": "Oan it fernijen",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Külső program kezeli a fájlverzió-követést. Az távolítja el a fájlt a megosztott mappából. Ha az alkalmazás útvonala szóközöket tartalmaz, zárójelezni szükséges az útvonalat.",
|
||||
"Anonymous Usage Reporting": "Névtelen felhasználási adatok küldése",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "A névtelen használati jelentés formátuma megváltozott. Szeretnél áttérni az új formátumra?",
|
||||
"Apply": "Alkalmazás",
|
||||
"Are you sure you want to continue?": "Biztosan folytatható?",
|
||||
"Are you sure you want to override all remote changes?": "Biztos, hogy felülírható minden távoli módosítás?",
|
||||
"Are you sure you want to permanently delete all these files?": "Biztos, hogy véglegesen törölhetőek mindezek a fájlok?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Alapértelmezések",
|
||||
"Delete": "Törlés",
|
||||
"Delete Unexpected Items": "Váratlan elemek törlése",
|
||||
"Deleted": "Törölve",
|
||||
"Deleted {%file%}": "Törölt {{file}}",
|
||||
"Deselect All": "Kijelölés megszüntetése",
|
||||
"Deselect devices to stop sharing this folder with.": "Azon eszközök kijelölésének törlése, amelyekkel e mappa megosztása leállítandó.",
|
||||
"Deselect folders to stop sharing with this device.": "Szüntesse meg a mappák kijelölését a mappák megosztásának leállításához ezzel az eszközzel.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "A megtartott verziók száma nem lehet üres.",
|
||||
"The path cannot be blank.": "Az elérési útvonal nem lehet üres.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "A sebességlimitnek pozitív számnak kell lennie (0: nincs limit)",
|
||||
"The remote device has not accepted sharing this folder.": "A távoli eszköz nem fogadta el ennek a mappának a megosztását.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Az átnézési intervallum nullánál nagyobb másodperc érték kell legyen.",
|
||||
"There are no devices to share this folder with.": "Nincsenek eszközök, amelyekkel megosztható lenne a mappa.",
|
||||
"There are no file versions to restore.": "Nincsenek visszaállítható fájlverziók.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Az idő, amikor utoljára módosítva lett az elem",
|
||||
"Today": "Ma",
|
||||
"Trash Can File Versioning": "Szemetes fájlverzió-követés",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Típus",
|
||||
"UNIX Permissions": "UNIX jogosultságok",
|
||||
"Unavailable": "Nem elérhető",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Nem megosztott mappák",
|
||||
"Untrusted": "Nem megbízható",
|
||||
"Up to Date": "Friss",
|
||||
"Updated": "Frissítve",
|
||||
"Updated {%file%}": "Frissített {{file}}",
|
||||
"Upgrade": "Frissítés",
|
||||
"Upgrade To {%version%}": "Frissítés a verzióra: {{version}}",
|
||||
"Upgrading": "Frissítés",
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"Advanced": "Tingkat Lanjut",
|
||||
"Advanced Configuration": "Konfigurasi Tingkat Lanjut",
|
||||
"All Data": "Semua Data",
|
||||
"All Time": "All Time",
|
||||
"All Time": "Semua Waktu",
|
||||
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "Semua folder yang dibagi dengan perangkat ini harus dilindungi dengan sandi, sehingga semua data tidak dapat dilihat tanpa sandi.",
|
||||
"Allow Anonymous Usage Reporting?": "Izinkan Laporan Penggunaan Anonim?",
|
||||
"Allowed Networks": "Jaringan Terizinkan",
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Perintah eksternal menangani pemversian. Ia harus menghapus berkas dari folder yang dibagi. Jika lokasi aplikasi terdapat spasi, itu harus dikutip.",
|
||||
"Anonymous Usage Reporting": "Pelaporan Penggunaan Anonim",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Format pelaporan penggunaan anonim telah berubah. Maukah anda pindah menggunakan format yang baru?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Apakah anda yakin ingin lanjut?",
|
||||
"Are you sure you want to override all remote changes?": "Apakah anda yakin ingin menimpa semua perubahan jarak jauh?",
|
||||
"Are you sure you want to permanently delete all these files?": "Apakah anda yakin ingin menghapus semua berkas berikut secara permanen?",
|
||||
@@ -46,7 +47,7 @@
|
||||
"Be careful!": "Harap hati-hati!",
|
||||
"Bugs": "Bugs",
|
||||
"Cancel": "Batal",
|
||||
"Changelog": "Log perubahan",
|
||||
"Changelog": "Log Perubahan",
|
||||
"Clean out after": "Bersihkan setelah",
|
||||
"Cleaning Versions": "Versi Pembersihan",
|
||||
"Cleanup Interval": "Interval Pembersihan",
|
||||
@@ -67,7 +68,7 @@
|
||||
"Copyright © 2014-2019 the following Contributors:": "Hak cipta © 2014-2019 Kontributor berikut ini:",
|
||||
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Membuat pola pengabaian, menimpa sebuah file yang sudah ada di {{path}}.",
|
||||
"Currently Shared With Devices": "Sekarang Terbagi Dengan Perangkat",
|
||||
"Custom Range": "Custom Range",
|
||||
"Custom Range": "Rentang Kustom",
|
||||
"Danger!": "Bahaya!",
|
||||
"Debugging Facilities": "Fasilitas Debug",
|
||||
"Default Configuration": "Konfigurasi Bawaan",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Bawaan",
|
||||
"Delete": "Hapus",
|
||||
"Delete Unexpected Items": "Hapus Barang Tidak Terduga",
|
||||
"Deleted": "Terhapus",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Batal Pilih Semua",
|
||||
"Deselect devices to stop sharing this folder with.": "Batal pilih perangkat untuk memberhentikan pembagian folder ini.",
|
||||
"Deselect folders to stop sharing with this device.": "Batal pilih folder untuk memberhentikan pembagian dengan perangkat ini.",
|
||||
@@ -119,7 +120,7 @@
|
||||
"Edit Folder Defaults": "Sunting Bawaan Folder",
|
||||
"Editing {%path%}.": "Menyunting {{path}}.",
|
||||
"Enable Crash Reporting": "Akitfkan Pelaporan Crash",
|
||||
"Enable NAT traversal": "Aktifkan traversal NAT",
|
||||
"Enable NAT traversal": "Aktifkan Traversal NAT",
|
||||
"Enable Relaying": "Aktifkan Relay",
|
||||
"Enabled": "Aktif",
|
||||
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Masukkan nomor yang bukan negatif (contoh \"2.35\") dan pilih sebuah unit. Persentase adalah bagian dari total ukuran penyimpanan.",
|
||||
@@ -130,7 +131,7 @@
|
||||
"Error": "Galat",
|
||||
"External File Versioning": "Pemversian Berkas Eksternal",
|
||||
"Failed Items": "Berkas yang gagal",
|
||||
"Failed to load file versions.": "Failed to load file versions.",
|
||||
"Failed to load file versions.": "Gagal memuat versi berkas.",
|
||||
"Failed to load ignore patterns.": "Gagal memuat pola pengabaian.",
|
||||
"Failed to setup, retrying": "Gagal menyiapkan, mengulang",
|
||||
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Gagal untuk menyambung ke server IPv6 itu disangka apabila tidak ada konektivitas IPv6.",
|
||||
@@ -157,7 +158,7 @@
|
||||
"GUI Authentication Password": "Sandi Otentikasi GUI",
|
||||
"GUI Authentication User": "Pengguna Otentikasi GUI",
|
||||
"GUI Authentication: Set User and Password": "Otentikasi GUI: Atur Pengguna dan Sandi",
|
||||
"GUI Listen Address": "Alamat Mendengar GUI",
|
||||
"GUI Listen Address": "Alamat Pendengaran GUI",
|
||||
"GUI Theme": "Tema GUI",
|
||||
"General": "Umum",
|
||||
"Generate": "Generasi",
|
||||
@@ -185,9 +186,9 @@
|
||||
"Keep Versions": "Jumlah Versi yang Disimpan",
|
||||
"LDAP": "LDAP",
|
||||
"Largest First": "Terbesar Dahulu",
|
||||
"Last 30 Days": "Last 30 Days",
|
||||
"Last 7 Days": "Last 7 Days",
|
||||
"Last Month": "Last Month",
|
||||
"Last 30 Days": "30 Hari Terakhir",
|
||||
"Last 7 Days": "7 Hari Terakhir",
|
||||
"Last Month": "Bulan Lalu",
|
||||
"Last Scan": "Scan Terakhir",
|
||||
"Last seen": "Terakhir dilihat",
|
||||
"Latest Change": "Perubahan Terbaru",
|
||||
@@ -305,7 +306,7 @@
|
||||
"Share Folders With Device": "Bagi Folder Dengan Perangkat",
|
||||
"Share this folder?": "Bagi Folder Ini?",
|
||||
"Shared Folders": "Folder Yang Dibagi",
|
||||
"Shared With": "Dibagi dengan",
|
||||
"Shared With": "Dibagi Dengan",
|
||||
"Sharing": "Pembagian",
|
||||
"Show ID": "Tampilkan ID",
|
||||
"Show QR": "Tampilkan QR",
|
||||
@@ -377,21 +378,23 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Jumlah versi harus berupa angka dan tidak dapat kosong.",
|
||||
"The path cannot be blank.": "Lokasi tidak dapat kosong.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "Pembatasan kecepatan harus berupa angka positif (0: tidak terbatas)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Interval pemindaian ulang harus berupa angka positif.",
|
||||
"There are no devices to share this folder with.": "Tidak ada perangkat untuk membagikan folder ini.",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
"There are no file versions to restore.": "Tidak ada versi berkas untuk dipulihkan.",
|
||||
"There are no folders to share with this device.": "Tidak ada folder untuk dibagi dengan perangkat ini.",
|
||||
"They are retried automatically and will be synced when the error is resolved.": "Mereka diulang secara otomatis dan akan disinkron ketika galat telah terselesaikan.",
|
||||
"This Device": "Perangkat Ini",
|
||||
"This Month": "This Month",
|
||||
"This Month": "Bulan Ini",
|
||||
"This can easily give hackers access to read and change any files on your computer.": "Ini dapat dengan mudah memberi peretas akses untuk melihat dan mengubah file apapun dalam komputer anda.",
|
||||
"This device cannot automatically discover other devices or announce its own address to be found by others. Only devices with statically configured addresses can connect.": "Perangkat ini tidak dapat menemukan perangkat lain secara otomatis atau mengumumkan alamat sendiri untuk dapat ditemukan oleh perangkat lain. Hanya perangkat dengan konfigurasi alamat statik dapat menyambung.",
|
||||
"This is a major version upgrade.": "Ini adalah peningkatan versi besar.",
|
||||
"This setting controls the free space required on the home (i.e., index database) disk.": "Pengaturan ini mengontrol jumlah penyimpanan kosong yang dibutuhkan dalam penyimpanan utama (contoh database indeks).",
|
||||
"Time": "Waktu",
|
||||
"Time the item was last modified": "Waktu file terakhir dimodifikasi",
|
||||
"Today": "Today",
|
||||
"Today": "Hari Ini",
|
||||
"Trash Can File Versioning": "Pemversian Berkas Tempat Sampah",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Tipe",
|
||||
"UNIX Permissions": "Izin UNIX",
|
||||
"Unavailable": "Tidak Tersedia",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Folder Tidak Terbagi",
|
||||
"Untrusted": "Tidak Terpercaya",
|
||||
"Up to Date": "Tersinkron",
|
||||
"Updated": "Diperbarui",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Tingkatkan",
|
||||
"Upgrade To {%version%}": "Tingkatkan Ke {{version}}",
|
||||
"Upgrading": "Meningkatkan",
|
||||
@@ -432,10 +435,10 @@
|
||||
"Watch for Changes": "Pantau Perubahan",
|
||||
"Watching for Changes": "Memantau Perubahan",
|
||||
"Watching for changes discovers most changes without periodic scanning.": "Memantau perubahan menemukan kebanyakan perubahan tanpa pemindaian periodik.",
|
||||
"When adding a new device, keep in mind that this device must be added on the other side too.": "When adding a new device, keep in mind that this device must be added on the other side too.",
|
||||
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.",
|
||||
"When adding a new device, keep in mind that this device must be added on the other side too.": "Ketika menambah perangkat baru, perlu diingat bahwa perangkat ini juga harus ditambahkan pada sisi lain juga.",
|
||||
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "Ketika menambah sebuah folder baru, perlu diingat bahwa ID Folder digunakan untuk mengikat folder antar perangkat. Mereka peka terhadap kapitalisasi huruf dan harus sama pada semua perangkat.",
|
||||
"Yes": "Iya",
|
||||
"Yesterday": "Yesterday",
|
||||
"Yesterday": "Kemarin",
|
||||
"You can also select one of these nearby devices:": "Anda juga dapat memilih salah satu perangkat disekitar berikut:",
|
||||
"You can change your choice at any time in the Settings dialog.": "Anda dapat mengubah pilihan anda dalam dialog Pengaturan.",
|
||||
"You can read more about the two release channels at the link below.": "Anda dapat membaca lebih lanjut tentang dua saluran rilis pada tautan di bawah.",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Il controllo versione è gestito da un comando esterno. Quest'ultimo deve rimuovere il file dalla cartella condivisa. Se il percorso dell'applicazione contiene spazi, deve essere indicato tra virgolette.",
|
||||
"Anonymous Usage Reporting": "Statistiche Anonime di Utilizzo",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Il formato delle statistiche anonime di utilizzo è cambiato. Vuoi passare al nuovo formato?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Sei sicuro di voler continuare?",
|
||||
"Are you sure you want to override all remote changes?": "Sei sicuro di voler sovrascrivere tutte le modifiche remote?",
|
||||
"Are you sure you want to permanently delete all these files?": "Sei sicuro di voler eliminare definitivamente tutti questi file?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Impostazioni predefinite",
|
||||
"Delete": "Elimina",
|
||||
"Delete Unexpected Items": "Elimina elementi imprevisti",
|
||||
"Deleted": "Cancellato",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Deseleziona tutto",
|
||||
"Deselect devices to stop sharing this folder with.": "Deseleziona i dispositivi con cui interrompere la condivisione di questa cartella.",
|
||||
"Deselect folders to stop sharing with this device.": "Deseleziona le cartelle per interromperne la condivisione con questo dispositivo.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Il numero di versioni dev'essere un numero e non può essere vuoto.",
|
||||
"The path cannot be blank.": "Il percorso non può essere vuoto.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "Il limite di banda deve essere un numero non negativo (0: nessun limite)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "L'intervallo di scansione deve essere un numero non negativo secondi.",
|
||||
"There are no devices to share this folder with.": "Non ci sono dispositivi con cui condividere questa cartella.",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Ora dell'ultima modifica degli elementi",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "Controllo Versione con Cestino",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Tipo",
|
||||
"UNIX Permissions": "Permessi UNIX",
|
||||
"Unavailable": "Non disponibile",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Cartelle non condivise",
|
||||
"Untrusted": "Non attendibile",
|
||||
"Up to Date": "Sincronizzato",
|
||||
"Updated": "Aggiornato",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Aggiornamento",
|
||||
"Upgrade To {%version%}": "Aggiorna alla {{version}}",
|
||||
"Upgrading": "Aggiornamento",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.",
|
||||
"Anonymous Usage Reporting": "匿名での使用状況レポート",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "匿名での使用状況レポートのフォーマットが変わりました。新形式でのレポートに移行しますか?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "続行してもよろしいですか?",
|
||||
"Are you sure you want to override all remote changes?": "リモートでの変更をすべて上書きしてもよろしいですか?",
|
||||
"Are you sure you want to permanently delete all these files?": "これらのファイルをすべて完全に削除してもよろしいですか?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "デフォルト",
|
||||
"Delete": "削除",
|
||||
"Delete Unexpected Items": "予期しないアイテムを削除",
|
||||
"Deleted": "削除",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "すべて選択解除",
|
||||
"Deselect devices to stop sharing this folder with.": "このフォルダの共有を停止したいデバイスがある場合は、当該デバイスの選択を解除してください。",
|
||||
"Deselect folders to stop sharing with this device.": "このデバイスとの共有を停止するフォルダーを選択解除します。",
|
||||
@@ -88,7 +89,7 @@
|
||||
"Device Name": "デバイス名",
|
||||
"Device is untrusted, enter encryption password": "Device is untrusted, enter encryption password",
|
||||
"Device rate limits": "デバイス速度制限",
|
||||
"Device that last modified the item": "Device that last modified the item",
|
||||
"Device that last modified the item": "項目を最後に変更したデバイス",
|
||||
"Devices": "デバイス",
|
||||
"Disable Crash Reporting": "クラッシュレポートを無効にする",
|
||||
"Disabled": "無効",
|
||||
@@ -202,7 +203,7 @@
|
||||
"Local Discovery": "LAN内で探索",
|
||||
"Local State": "ローカル状態",
|
||||
"Local State (Total)": "ローカル状態 (合計)",
|
||||
"Locally Changed Items": "Locally Changed Items",
|
||||
"Locally Changed Items": "ローカルで変更された項目",
|
||||
"Log": "ログ",
|
||||
"Log tailing paused. Scroll to the bottom to continue.": "ログのリアルタイム表示を停止しています。下部までスクロールすると再開されます。",
|
||||
"Logs": "ログ",
|
||||
@@ -211,8 +212,8 @@
|
||||
"Maximum Age": "最大保存日数",
|
||||
"Metadata Only": "メタデータのみ",
|
||||
"Minimum Free Disk Space": "同期を停止する最小空きディスク容量",
|
||||
"Mod. Device": "Mod. Device",
|
||||
"Mod. Time": "Mod. Time",
|
||||
"Mod. Device": "変更デバイス",
|
||||
"Mod. Time": "変更日時",
|
||||
"Move to top of queue": "最優先にする",
|
||||
"Multi level wildcard (matches multiple directory levels)": "多階層ワイルドカード (複数のディレクトリ階層にマッチします)",
|
||||
"Never": "記録なし",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "保持するバージョン数は数値を指定してください。空欄にはできません。",
|
||||
"The path cannot be blank.": "パスを入力してください。",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "帯域制限値は0以上で指定して下さい。 (0で無制限)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "再スキャン間隔は0秒以上で指定してください。",
|
||||
"There are no devices to share this folder with.": "どのデバイスともフォルダーを共有していません。",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -389,9 +391,10 @@
|
||||
"This is a major version upgrade.": "メジャーアップグレードです。",
|
||||
"This setting controls the free space required on the home (i.e., index database) disk.": "この設定は、ホームディスク (インデックスデータベースがあるディスク) で必要な空き容量を管理します。",
|
||||
"Time": "日時",
|
||||
"Time the item was last modified": "Time the item was last modified",
|
||||
"Time the item was last modified": "項目を最後に変更した日時",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "ゴミ箱によるバージョン管理",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "タイプ",
|
||||
"UNIX Permissions": "UNIX パーミッション",
|
||||
"Unavailable": "利用不可",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "非共有のフォルダー",
|
||||
"Untrusted": "信頼しない",
|
||||
"Up to Date": "最新",
|
||||
"Updated": "更新",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "アップグレード",
|
||||
"Upgrade To {%version%}": "{{version}} にアップグレードする",
|
||||
"Upgrading": "アップグレード中",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"A device with that ID is already added.": "이 ID 번호를 가진 기기가 이미 추가되어 있습니다.",
|
||||
"A device with that ID is already added.": "이 식별자를 가진 기기가 이미 추가되어 있습니다.",
|
||||
"A negative number of days doesn't make sense.": "일수를 음수로 입력하는 것은 말이 되지 않습니다.",
|
||||
"A new major version may not be compatible with previous versions.": "새로운 주요 버전이 이전 버전과 호환되지 않을 수 있습니다.",
|
||||
"A new major version may not be compatible with previous versions.": "새로운 주요 버전이 이전 버전들과 호환되지 않을 수 있습니다.",
|
||||
"API Key": "API 키",
|
||||
"About": "정보",
|
||||
"Action": "동작",
|
||||
@@ -20,7 +20,7 @@
|
||||
"Advanced Configuration": "고급 설정",
|
||||
"All Data": "전체 데이터",
|
||||
"All Time": "전체 기간",
|
||||
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "송신하는 데이터 모두를 비밀번호 없이 읽을 수 없도록 이 기기와 공유한 모든 폴더를 비밀번호로 보호해야 합니다.",
|
||||
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "송신하는 데이터 전체를 비밀번호 없이 읽을 수 없도록 이 기기와 공유한 모든 폴더를 비밀번호로 보호해야 합니다.",
|
||||
"Allow Anonymous Usage Reporting?": "익명 사용 보고를 허용하시겠습니까?",
|
||||
"Allowed Networks": "허가된 망",
|
||||
"Alphabetic": "가나다순",
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "외부 명령이 파일 버전을 관리합니다. 공유 폴더에서 파일을 삭제해야 합니다. 응용 프로그램의 경로에 공백이 있으면 따옴표로 묶어야 합니다.",
|
||||
"Anonymous Usage Reporting": "익명 사용 보고",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "익명 사용 보고의 형식이 변경되었습니다. 새 형식으로 설정을 변경하시겠습니까?",
|
||||
"Apply": "적용",
|
||||
"Are you sure you want to continue?": "계속하시겠습니까?",
|
||||
"Are you sure you want to override all remote changes?": "다른 기기의 변경 항목 모두를 덮어쓰시겠습니까?",
|
||||
"Are you sure you want to permanently delete all these files?": "이 파일 모두를 영구 삭제하시겠습니까?",
|
||||
@@ -66,7 +67,7 @@
|
||||
"Copied from original": "원본에서 복사됨",
|
||||
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 하위 기여자들:",
|
||||
"Creating ignore patterns, overwriting an existing file at {%path%}.": "무시 양식 생성 중; {{path}} 경로의 기존 파일을 덮어씁니다.",
|
||||
"Currently Shared With Devices": "현재 공유된 기기",
|
||||
"Currently Shared With Devices": "공유된 기기",
|
||||
"Custom Range": "사용자 설정 기간",
|
||||
"Danger!": "위험!",
|
||||
"Debugging Facilities": "디버그 기능",
|
||||
@@ -77,18 +78,18 @@
|
||||
"Defaults": "기본 설정",
|
||||
"Delete": "삭제",
|
||||
"Delete Unexpected Items": "예기치 못한 항목 삭제",
|
||||
"Deleted": "삭제됨",
|
||||
"Deleted {%file%}": "{{file}} 삭제됨",
|
||||
"Deselect All": "모두 선택 해제",
|
||||
"Deselect devices to stop sharing this folder with.": "현재 폴더를 공유하지 않을 기기를 선택 해제하십시오.",
|
||||
"Deselect folders to stop sharing with this device.": "현재 기기와 공유하지 않을 폴더를 선택 해제하십시오.",
|
||||
"Device": "기기",
|
||||
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "\"{{name}}\" ({{device}} 기기가 {{address}}) 주소에서 접속을 요청했습니다. 새 기기를 추가하시겠습니까?",
|
||||
"Device ID": "기기 ID 번호",
|
||||
"Device ID": "기기 식별자",
|
||||
"Device Identification": "기기 식별자",
|
||||
"Device Name": "기기명",
|
||||
"Device is untrusted, enter encryption password": "신뢰하지 않는 기기입니다; 암호화 비밀번호를 입력하십시오",
|
||||
"Device rate limits": "기기 속도 제한",
|
||||
"Device that last modified the item": "항목 최근 수정 기기",
|
||||
"Device that last modified the item": "항목을 가장 최근에 수정한 기기",
|
||||
"Devices": "기기",
|
||||
"Disable Crash Reporting": "충돌 보고 비활성화",
|
||||
"Disabled": "비활성화됨",
|
||||
@@ -96,7 +97,7 @@
|
||||
"Disabled periodic scanning and enabled watching for changes": "주기적 탐색 비활성화됨 및 변경 항목 감시 활성화됨",
|
||||
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "주기적 탐색 비활성화됨 및 변경 항목 감시 설정에 실패함; 1분마다 재시도 중:",
|
||||
"Disables comparing and syncing file permissions. Useful on systems with nonexistent or custom permissions (e.g. FAT, exFAT, Synology, Android).": "파일 권한의 비교 및 동기화가 비활성화됩니다. FAT, exFAT, Synology, Android 등 파일 권한이 존재하지 않거나 비표준 파일 권한을 사용하는 체제에서 유용합니다.",
|
||||
"Discard": "일시적 무시",
|
||||
"Discard": "무시",
|
||||
"Disconnected": "연결 끊김",
|
||||
"Disconnected (Unused)": "연결 끊김(미사용)",
|
||||
"Discovered": "탐지됨",
|
||||
@@ -117,7 +118,7 @@
|
||||
"Edit Device Defaults": "기기 기본 설정 편집",
|
||||
"Edit Folder": "폴더 편집",
|
||||
"Edit Folder Defaults": "폴더 기본 설정 편집",
|
||||
"Editing {%path%}.": "{{path}} 경로 편집 중",
|
||||
"Editing {%path%}.": "{{path}} 편집 중입니다.",
|
||||
"Enable Crash Reporting": "충돌 보고 활성화",
|
||||
"Enable NAT traversal": "NAT 통과 활성화",
|
||||
"Enable Relaying": "중계 활성화",
|
||||
@@ -133,7 +134,7 @@
|
||||
"Failed to load file versions.": "파일 버전을 불러오기에 실패했습니다.",
|
||||
"Failed to load ignore patterns.": "무시 양식을 불러오기에 실패했습니다.",
|
||||
"Failed to setup, retrying": "설정 적용 실패; 재시도 중",
|
||||
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "IPv6 연결이 없을 때는 IPv6 서버에 접속하지 못하는 것이 정상입니다.",
|
||||
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "IPv6에 연결되어 있지 않을 때는 IPv6 서버에 접속하지 못하는 것이 정상입니다.",
|
||||
"File Pull Order": "파일 수신 순서",
|
||||
"File Versioning": "파일 버전 관리",
|
||||
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Syncthing에 의해 교체 또는 삭제된 파일은 .stversions 폴더로 이동됩니다.",
|
||||
@@ -144,7 +145,7 @@
|
||||
"Filter by date": "날짜별 검색",
|
||||
"Filter by name": "이름별 검색",
|
||||
"Folder": "폴더",
|
||||
"Folder ID": "폴더 ID 번호",
|
||||
"Folder ID": "폴더 식별자",
|
||||
"Folder Label": "폴더명",
|
||||
"Folder Path": "폴더 경로",
|
||||
"Folder Type": "폴더 유형",
|
||||
@@ -161,8 +162,8 @@
|
||||
"GUI Theme": "GUI 테마",
|
||||
"General": "일반",
|
||||
"Generate": "생성",
|
||||
"Global Discovery": "글로벌 탐지",
|
||||
"Global Discovery Servers": "글로벌 탐지 서버",
|
||||
"Global Discovery": "외부 탐지",
|
||||
"Global Discovery Servers": "외부 탐지 서버",
|
||||
"Global State": "전체 기기 상태",
|
||||
"Help": "도움말",
|
||||
"Home page": "홈페이지",
|
||||
@@ -176,7 +177,7 @@
|
||||
"Ignore patterns can only be added after the folder is created. If checked, an input field to enter ignore patterns will be presented after saving.": "무시 양식은 폴더가 생성된 후에만 추가할 수 있습니다. 체크할 경우, 폴더를 저장할 다음에 무시 양식을 입력하기 위한 새 창으로 이동합니다.",
|
||||
"Ignored Devices": "무시한 기기",
|
||||
"Ignored Folders": "무시한 폴더",
|
||||
"Ignored at": "무시된 기기",
|
||||
"Ignored at": "무시한 일자",
|
||||
"Incoming Rate Limit (KiB/s)": "수신 속도 제한(KiB/s)",
|
||||
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "잘못된 설정은 폴더의 내용을 훼손하거나 Syncthing을 작동하지 못하게 할 수 있습니다.",
|
||||
"Introduced By": "소개한 기기",
|
||||
@@ -189,7 +190,7 @@
|
||||
"Last 7 Days": "지난 7일",
|
||||
"Last Month": "지난 달",
|
||||
"Last Scan": "최근 탐색",
|
||||
"Last seen": "최근 접속",
|
||||
"Last seen": "최근 연결",
|
||||
"Latest Change": "최신 변경 항목",
|
||||
"Learn more": "더 알아보기",
|
||||
"Limit": "제한",
|
||||
@@ -199,7 +200,7 @@
|
||||
"Loading data...": "데이터를 불러오는 중...",
|
||||
"Loading...": "불러오는 중...",
|
||||
"Local Additions": "현재 기기 추가 항목",
|
||||
"Local Discovery": "로컬 탐지",
|
||||
"Local Discovery": "내부 탐지",
|
||||
"Local State": "현재 기기 상태",
|
||||
"Local State (Total)": "현재 기기 상태(합계)",
|
||||
"Locally Changed Items": "현재 기기 변경 항목",
|
||||
@@ -215,18 +216,18 @@
|
||||
"Mod. Time": "수정 시간",
|
||||
"Move to top of queue": "대기열 상단으로 이동",
|
||||
"Multi level wildcard (matches multiple directory levels)": "다중 수준 와일드카드(여러 단계의 디렉토리에서 적용됨)",
|
||||
"Never": "사용 안 함",
|
||||
"Never": "기록 없음",
|
||||
"New Device": "새 기기",
|
||||
"New Folder": "새 폴더",
|
||||
"Newest First": "최신 파일 순",
|
||||
"No": "아니요",
|
||||
"No File Versioning": "파일 버전 관리 안 함",
|
||||
"No File Versioning": "파일 버전을 관리하지 않음",
|
||||
"No files will be deleted as a result of this operation.": "이 작업의 결과로는 아무 파일도 삭제되지 않습니다.",
|
||||
"No upgrades": "업데이트 안 함",
|
||||
"No upgrades": "업데이트하지 않음",
|
||||
"Not shared": "공유되지 않음",
|
||||
"Notice": "공지",
|
||||
"OK": "확인",
|
||||
"Off": "꺼짐",
|
||||
"Off": "하지 않음",
|
||||
"Oldest First": "오랜 파일 순",
|
||||
"Optional descriptive label for the folder. Can be different on each device.": "폴더를 묘사하는 선택적 이름입니다. 기기마다 달리 설정해도 됩니다.",
|
||||
"Options": "옵션",
|
||||
@@ -307,13 +308,13 @@
|
||||
"Shared Folders": "공유된 폴더",
|
||||
"Shared With": "공유된 기기",
|
||||
"Sharing": "공유",
|
||||
"Show ID": "기기 ID 번호 보기",
|
||||
"Show ID": "기기 식별자 보기",
|
||||
"Show QR": "QR 코드 보기",
|
||||
"Show detailed discovery status": "탐지 현황 상세 보기",
|
||||
"Show detailed listener status": "대기자 현황 상세 보기",
|
||||
"Show diff with previous version": "이전 버전과의 diff 보기",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "기기 ID 번호를 대신해 기기 목록에서 나타납니다. 다른 기기에 선택적 기본값 이름으로 통보됩니다.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "기기 ID 번호를 대신해 기기 목록에서 나타납니다. 비워 둘 경우 다른 기기에서 통보받은 이름으로 갱신됩니다.",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "기기 식별자를 대신해 기기 목록에서 나타납니다. 다른 기기에 선택적 기본값 이름으로 통보됩니다.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "기기 식별자를 대신해 기기 목록에서 나타납니다. 비워 둘 경우 다른 기기에서 통보받은 이름으로 갱신됩니다.",
|
||||
"Shutdown": "종료",
|
||||
"Shutdown Complete": "종료 완료",
|
||||
"Simple File Versioning": "간단한 파일 버전 관리",
|
||||
@@ -350,22 +351,22 @@
|
||||
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "시작 옵션이 GUI 주소를 덮어쓰고 있습니다. 덮어쓰기가 지속되는 동안에는 설정을 변경할 수 없습니다.",
|
||||
"The Syncthing Authors": "The Syncthing Authors",
|
||||
"The Syncthing admin interface is configured to allow remote access without a password.": "Syncthing의 관리자 인터페이스가 비밀번호 없이 원격 접속할 수 있도록 설정되어 있습니다.",
|
||||
"The aggregated statistics are publicly available at the URL below.": "수집된 통계는 아래의 주소에서 공람되어 있습니다.",
|
||||
"The aggregated statistics are publicly available at the URL below.": "수집된 통계는 아래의 주소에서 공람할 수 있습니다.",
|
||||
"The cleanup interval cannot be blank.": "정리 간격은 비워 둘 수 없습니다.",
|
||||
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "설정이 저장되었으나 아직 활성화되지 않았습니다. 새 설정을 활성화하려면 Syncthing을 재시작하십시오.",
|
||||
"The device ID cannot be blank.": "기기 ID 번호는 비워 둘 수 없습니다.",
|
||||
"The device ID to enter here can be found in the \"Actions > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "이 자리에 입력할 기기 ID 번호는 다른 기기의 \"동작 > 기기 ID 번호 보기\"에서 찾을 수 있습니다. 공백과 하이픈은 선택적입니다(무시됩니다).",
|
||||
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "암호화된 사용 보고서는 매일 전송됩니다. 사용 중인 운영체제, 폴더 크기와 응용 프로그램 버전을 추적하기 위해서입니다. 만일 보고되는 정보가 변경되면 이 알림창이 다시 표시됩니다.",
|
||||
"The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "입력한 기기 ID 번호가 올바르지 않습니다. 52 또는 56자의 알파벳과 숫자로 구성되어야 하며, 공백과 하이픈은 선택적입니다.",
|
||||
"The folder ID cannot be blank.": "폴더 ID 번호는 비워 둘 수 없습니다.",
|
||||
"The folder ID must be unique.": "폴더 ID 번호는 유일무이해야 합니다.",
|
||||
"The device ID cannot be blank.": "기기 식별자는 비워 둘 수 없습니다.",
|
||||
"The device ID to enter here can be found in the \"Actions > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "이 자리에 입력할 기기 식별자는 다른 기기의 \"동작 > 기기 식별자 보기\"에서 찾을 수 있습니다. 공백과 하이픈은 선택적입니다(무시됩니다).",
|
||||
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "암호화된 사용 보고서는 매일 전송됩니다. 사용 중인 운영체제, 폴더 크기와 응용 프로그램의 버전을 추적하기 위해서입니다. 만일 보고되는 정보가 변경되면 이 알림창이 다시 표시될 예정입니다.",
|
||||
"The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "입력한 기기 식별자가 올바르지 않습니다. 52 또는 56자의 알파벳과 숫자로 구성되어야 하며, 공백과 하이픈은 선택적입니다.",
|
||||
"The folder ID cannot be blank.": "폴더 식별자는 비워 둘 수 없습니다.",
|
||||
"The folder ID must be unique.": "폴더 식별자는 유일무이해야 합니다.",
|
||||
"The folder content on other devices will be overwritten to become identical with this device. Files not present here will be deleted on other devices.": "다른 기기의 폴더 내용을 현재 기기와 동일하도록 덮어씁니다. 현재 기기의 폴더에 존재하지 않는 파일은 다른 기기에서 삭제됩니다.",
|
||||
"The folder content on this device will be overwritten to become identical with other devices. Files newly added here will be deleted.": "현재 기기의 폴더 내용을 다른 기기와 동일하도록 덮어쓰입니다. 현재 기기의 폴더에 새로 추가된 파일은 삭제됩니다.",
|
||||
"The folder path cannot be blank.": "폴더 경로는 비워 둘 수 없습니다.",
|
||||
"The following intervals are used: for the first hour a version is kept every 30 seconds, for the first day a version is kept every hour, for the first 30 days a version is kept every day, until the maximum age a version is kept every week.": "다음과 같은 간격이 사용됩니다: 첫 한 시간 동안은 30초마다, 첫 하루 동안은 1시간마다, 첫 30일 동안은 1일마다, 그리고 최대 보관 기간까지는 1주일마다 버전이 보관됩니다.",
|
||||
"The following items could not be synchronized.": "다음 항목이 동기화되지 못했습니다.",
|
||||
"The following items were changed locally.": "다음 항목이 현재 기기에서 변경되었습니다.",
|
||||
"The following methods are used to discover other devices on the network and announce this device to be found by others:": "망 내의 다른 기기 탐지 및 현재 기기 통보를 위한 다음 방식이 실행 중입니다:",
|
||||
"The following methods are used to discover other devices on the network and announce this device to be found by others:": "망 내의 다른 기기 탐지 및 현재 기기 통보를 위한 다음 방식이 사용 중입니다:",
|
||||
"The following unexpected items were found.": "다음 예기치 못한 항목이 발견되었습니다.",
|
||||
"The interval must be a positive number of seconds.": "간격은 초 단위의 양수여야 합니다.",
|
||||
"The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.": "버전 폴더를 정리하는 초 단위의 간격입니다. 주기적 정리를 비활성화하려면 0을 입력하십시오.",
|
||||
@@ -377,21 +378,23 @@
|
||||
"The number of versions must be a number and cannot be blank.": "버전 개수는 숫자여야 하며 비워 둘 수 없습니다.",
|
||||
"The path cannot be blank.": "경로는 비워 둘 수 없습니다.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "속도 제한은 양수여야 합니다(0: 무제한)",
|
||||
"The remote device has not accepted sharing this folder.": "다른 기기가 이 폴더의 공유를 승인하지 않았습니다.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "재탐색 간격은 초 단위의 양수여야 합니다.",
|
||||
"There are no devices to share this folder with.": "이 폴더를 공유할 기기가 없습니다.",
|
||||
"There are no file versions to restore.": "복구할 파일 버전이 없습니다.",
|
||||
"There are no folders to share with this device.": "이 기기와 공유할 폴더가 없습니다.",
|
||||
"They are retried automatically and will be synced when the error is resolved.": "자동 재시도 중이며 문제가 해결되는 대로 동기화됩니다.",
|
||||
"They are retried automatically and will be synced when the error is resolved.": "자동 재시도 중이며 문제가 해결되는 즉시 동기화될 예정입니다.",
|
||||
"This Device": "현재 기기",
|
||||
"This Month": "이번 달",
|
||||
"This can easily give hackers access to read and change any files on your computer.": "이로 인해서는 해커가 손쉽게 컴퓨터의 모든 파일을 읽고 편집할 수 있게 됩니다.",
|
||||
"This can easily give hackers access to read and change any files on your computer.": "이로 인해서는 해커들이 현재 컴퓨터의 모든 파일을 손쉽게 읽고 변경할 수 있게 됩니다.",
|
||||
"This device cannot automatically discover other devices or announce its own address to be found by others. Only devices with statically configured addresses can connect.": "이 기기는 다른 기기를 자동으로 탐지하거나 다른 기기로부터 발견되도록 자신의 주소를 통보할 수 없습니다. 고정 주소로 설정한 기기만이 현재 기기에 접속할 수 있습니다.",
|
||||
"This is a major version upgrade.": "주요 버전 업데이트입니다.",
|
||||
"This setting controls the free space required on the home (i.e., index database) disk.": "이 설정은 홈(즉, 인덕스 데이터베이스) 저장 장치의 여유 공간을 관리합니다.",
|
||||
"Time": "시간",
|
||||
"Time the item was last modified": "항목 최근 변경 시간",
|
||||
"Time the item was last modified": "항목이 가장 최근에 수정된 시간",
|
||||
"Today": "오늘",
|
||||
"Trash Can File Versioning": "휴지통을 통한 파일 버전 관리",
|
||||
"Twitter": "트위터",
|
||||
"Type": "유형",
|
||||
"UNIX Permissions": "UNIX 권한",
|
||||
"Unavailable": "변경 불가",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "공유되지 않은 폴더",
|
||||
"Untrusted": "신뢰하지 않음",
|
||||
"Up to Date": "최신 상태",
|
||||
"Updated": "업데이트 완료",
|
||||
"Updated {%file%}": "{{file}} 업데이트됨",
|
||||
"Upgrade": "업데이트",
|
||||
"Upgrade To {%version%}": "{{version}}으로 업데이트",
|
||||
"Upgrading": "업데이트 중",
|
||||
@@ -433,7 +436,7 @@
|
||||
"Watching for Changes": "변경 항목 감시",
|
||||
"Watching for changes discovers most changes without periodic scanning.": "변경 항목 감시는 주기적으로 탐색하지 않아도 대부분의 변경 항목을 탐지합니다.",
|
||||
"When adding a new device, keep in mind that this device must be added on the other side too.": "새 기기를 추가할 때는 추가한 기기에서도 현재 기기를 추가해야 합니다.",
|
||||
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "새 폴더를 추가할 때 폴더 ID 번호는 기기 간에 폴더를 묶어줍니다. 대소문자가 구분되며 모든 기기에서 동일해야 합니다.",
|
||||
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "새 폴더를 추가할 때 폴더 식별자는 기기 간에 폴더를 묶어줍니다. 대소문자가 구분되며 모든 기기에서 동일해야 합니다.",
|
||||
"Yes": "예",
|
||||
"Yesterday": "어제",
|
||||
"You can also select one of these nearby devices:": "주변의 기기 중 하나를 선택할 수도 있습니다.",
|
||||
@@ -448,13 +451,13 @@
|
||||
"directories": "개의 폴더",
|
||||
"files": "개의 파일",
|
||||
"full documentation": "전체 사용 설명서",
|
||||
"items": "항목",
|
||||
"items": "개의 항목",
|
||||
"seconds": "초",
|
||||
"theme-name-black": "검은색",
|
||||
"theme-name-dark": "어두운 색",
|
||||
"theme-name-default": "기본 색",
|
||||
"theme-name-light": "밝은 색",
|
||||
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} 기기에서 \"{{folder}}\" 폴더를 공유하길 원합니다.",
|
||||
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} 기기에서 \"{{folderlabel}}\" ({{folder}}) 폴더를 공유하길 원합니다.",
|
||||
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} 기기가 \"{{folder}}\" 폴더를 공유하길 원합니다.",
|
||||
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} 기기가 \"{{folderlabel}}\" ({{folder}}) 폴더를 공유하길 원합니다.",
|
||||
"{%reintroducer%} might reintroduce this device.": "{{reintroducer}} 기기에서 이 기기를 다시 소개할 수 있습니다."
|
||||
}
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Išorinė komanda apdoroja versijų valdymą. Ji turi pašalinti failą iš bendrinamo aplanko. Jei kelyje į programą yra tarpų, jie turėtų būti imami į kabutes.",
|
||||
"Anonymous Usage Reporting": "Anoniminė naudojimo ataskaita",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Anoniminės naudojimo ataskaitos formatas pasikeitė. Ar norėtumėte pereiti prie naujojo formato?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Ar tikrai norite tęsti?",
|
||||
"Are you sure you want to override all remote changes?": "Ar tikrai norite nustelbti visus nuotolinius pakeitimus?",
|
||||
"Are you sure you want to permanently delete all these files?": "Ar tikrai norite visam laikui ištrinti visus šiuos failus?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Numatytosios reikšmės",
|
||||
"Delete": "Ištrinti",
|
||||
"Delete Unexpected Items": "Ištrinti netikėtus elementus",
|
||||
"Deleted": "Ištrinta",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Nuimti žymėjimą nuo visų",
|
||||
"Deselect devices to stop sharing this folder with.": "Panaikinti įrenginių pasirinkimą, kad su jais būtų nustota bendrinti šį aplanką. ",
|
||||
"Deselect folders to stop sharing with this device.": "Deselect folders to stop sharing with this device.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Versijų skaičius turi būti skaitmuo ir negali būti tuščias laukelis.",
|
||||
"The path cannot be blank.": "Kelias negali būti tuščias.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "Srauto maksimalus greitis privalo būti ne neigiamas skaičius (0: nėra apribojimo)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Nuskaitymo dažnis negali būti neigiamas skaičius.",
|
||||
"There are no devices to share this folder with.": "Nėra įrenginių su kuriais bendrinti šį aplanką.",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Laikas, kai elementas buvo paskutinį kartą modifikuotas",
|
||||
"Today": "Šiandien",
|
||||
"Trash Can File Versioning": "Šiukšliadėžės versijų valdymas",
|
||||
"Twitter": "„Twitter“",
|
||||
"Type": "Tipas",
|
||||
"UNIX Permissions": "UNIX leidimai",
|
||||
"Unavailable": "Neprieinama",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Unshared Folders",
|
||||
"Untrusted": "Untrusted",
|
||||
"Up to Date": "Atnaujinta",
|
||||
"Updated": "Atnaujinta",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Atnaujinimas",
|
||||
"Upgrade To {%version%}": "Atnaujinti į {{version}}",
|
||||
"Upgrading": "Atnaujinama",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "En ekstern kommando tar hånd om versjoneringen. Den må fjerne filen fra den delte mappen. Hvis stien til programmet inneholder mellomrom, må den siteres.",
|
||||
"Anonymous Usage Reporting": "Anonym innsamling av brukerdata",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Det anonyme bruksrapportformatet har endret seg. Ønsker du å gå over til det nye formatet?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Are you sure you want to continue?",
|
||||
"Are you sure you want to override all remote changes?": "Are you sure you want to override all remote changes?",
|
||||
"Are you sure you want to permanently delete all these files?": "Are you sure you want to permanently delete all these files?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Defaults",
|
||||
"Delete": "Slett",
|
||||
"Delete Unexpected Items": "Delete Unexpected Items",
|
||||
"Deleted": "Slettet",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Fjern alle markeringer",
|
||||
"Deselect devices to stop sharing this folder with.": "Deselect devices to stop sharing this folder with.",
|
||||
"Deselect folders to stop sharing with this device.": "Deselect folders to stop sharing with this device.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Antall versjoner må være et tall og kan ikke være tomt.",
|
||||
"The path cannot be blank.": "Plasseringen kan ikke være tom.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "Hastighetsbegrensningen kan ikke være et negativt tall (0: ingen begrensing)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Antall sekund for intervallet kan ikke være negativt.",
|
||||
"There are no devices to share this folder with.": "There are no devices to share this folder with.",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Tidspunktet elementet sist ble endret",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "Papirkurv versjonskontroll",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Type",
|
||||
"UNIX Permissions": "UNIX Permissions",
|
||||
"Unavailable": "Utilgjengelig",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Unshared Folders",
|
||||
"Untrusted": "Untrusted",
|
||||
"Up to Date": "Oppdatert",
|
||||
"Updated": "Oppdatert",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Oppgradere",
|
||||
"Upgrade To {%version%}": "Oppgrader til {{version}}",
|
||||
"Upgrading": "Oppgraderer",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Een externe opdracht regelt het versiebeheer. Hij moet het bestand verwijderen uit de gedeelde map. Als het pad naar de toepassing spaties bevat, moet dit tussen aanhalingstekens geplaatst worden.",
|
||||
"Anonymous Usage Reporting": "Anonieme gebruikersstatistieken",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Het formaat voor anonieme gebruikersrapporten is gewijzigd. Wilt u naar het nieuwe formaat overschakelen?",
|
||||
"Apply": "Toepassen",
|
||||
"Are you sure you want to continue?": "Weet u zeker dat u wilt doorgaan?",
|
||||
"Are you sure you want to override all remote changes?": "Weet u zeker dat u alle externe wijzigingen wilt overschrijven?",
|
||||
"Are you sure you want to permanently delete all these files?": "Weet u zeker dat u al deze bestanden permanent wilt verwijderen?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Standaardwaarden",
|
||||
"Delete": "Verwijderen",
|
||||
"Delete Unexpected Items": "Onverwachte items verwijderen",
|
||||
"Deleted": "Verwijderd",
|
||||
"Deleted {%file%}": "{{file}} verwijderd",
|
||||
"Deselect All": "Alles deselecteren",
|
||||
"Deselect devices to stop sharing this folder with.": "Deselecteer apparaten om er deze map niet meer mee te delen.",
|
||||
"Deselect folders to stop sharing with this device.": "Deselecteer mappen om te stoppen met delen met dit apparaat.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Het aantal versies moet een getal zijn en mag niet leeg ziijn.",
|
||||
"The path cannot be blank.": "Het pad mag niet leeg zijn.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "De snelheidsbegrenzing moet een positief getal zijn (0: geen begrenzing)",
|
||||
"The remote device has not accepted sharing this folder.": "Het externe apparaat heeft het delen van deze map niet geaccepteerd.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Het interval voor opnieuw scannen moet een positief aantal seconden zijn.",
|
||||
"There are no devices to share this folder with.": "Er zijn geen apparaten om deze map mee te delen.",
|
||||
"There are no file versions to restore.": "Er zijn geen bestandsversies om te herstellen.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Tijdstip waarop het item laatst gewijzigd is",
|
||||
"Today": "Vandaag",
|
||||
"Trash Can File Versioning": "Prullenbak-versiebeheer",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Type",
|
||||
"UNIX Permissions": "UNIX-machtigingen",
|
||||
"Unavailable": "Niet beschikbaar",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Niet-gedeelde mappen",
|
||||
"Untrusted": "Niet vertrouwd",
|
||||
"Up to Date": "Bijgewerkt",
|
||||
"Updated": "Bijgewerkt",
|
||||
"Updated {%file%}": "{{file}} bijgewerkt",
|
||||
"Upgrade": "Bijwerken",
|
||||
"Upgrade To {%version%}": "Bijwerken naar {{version}}",
|
||||
"Upgrading": "Bijwerken",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"A device with that ID is already added.": "Urządzenie o tym numerze ID jest już dodane.",
|
||||
"A device with that ID is already added.": "Urządzenie o tym identyfikatorze jest już dodane.",
|
||||
"A negative number of days doesn't make sense.": "Ujemna wartość liczbowa dni nie ma sensu.",
|
||||
"A new major version may not be compatible with previous versions.": "Nowa duża wersja może nie być kompatybilna z poprzednimi wersjami.",
|
||||
"API Key": "Klucz API",
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Zewnętrzne polecenie odpowiedzialne jest za wersjonowanie. Musi ono usunąć plik ze współdzielonego folderu. Jeżeli ścieżka do aplikacji zawiera spacje, to powinna ona być zamknięta w cudzysłowie.",
|
||||
"Anonymous Usage Reporting": "Anonimowe statystyki użycia",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Format anonimowych statystyk użycia uległ zmianie. Czy chcesz przejść na nowy format?",
|
||||
"Apply": "Zastosuj",
|
||||
"Are you sure you want to continue?": "Czy na pewno chcesz kontynuować?",
|
||||
"Are you sure you want to override all remote changes?": "Czy na pewno chcesz nadpisać wszystkie zmiany zdalne?",
|
||||
"Are you sure you want to permanently delete all these files?": "Czy na pewno chcesz nieodwracalnie usunąć wszystkie te pliki?",
|
||||
@@ -77,13 +78,13 @@
|
||||
"Defaults": "Domyślne",
|
||||
"Delete": "Usuń",
|
||||
"Delete Unexpected Items": "Usuń elementy nieoczekiwane",
|
||||
"Deleted": "Usunięto",
|
||||
"Deleted {%file%}": "Usunięto {{file}}",
|
||||
"Deselect All": "Odznacz wszystkie",
|
||||
"Deselect devices to stop sharing this folder with.": "Odznacz urządzenia, z którymi chcesz przestać współdzielić ten folder.",
|
||||
"Deselect folders to stop sharing with this device.": "Odznacz foldery, które chcesz przestać współdzielić z tym urządzeniem.",
|
||||
"Device": "Urządzenie",
|
||||
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Urządzenie o nazwie \"{{name}}\" {{device}} pod adresem ({{address}}) chce się połączyć. Czy dodać nowe urządzenie?",
|
||||
"Device ID": "Numer ID urządzenia",
|
||||
"Device ID": "Identyfikator urządzenia",
|
||||
"Device Identification": "Identyfikator urządzenia",
|
||||
"Device Name": "Nazwa urządzenia",
|
||||
"Device is untrusted, enter encryption password": "Urządzenie jest niezaufane; wprowadź szyfrujące hasło",
|
||||
@@ -144,7 +145,7 @@
|
||||
"Filter by date": "Filtruj według daty",
|
||||
"Filter by name": "Filtruj według nazwy",
|
||||
"Folder": "Folder",
|
||||
"Folder ID": "Numer ID folderu",
|
||||
"Folder ID": "Identyfikator folderu",
|
||||
"Folder Label": "Etykieta folderu",
|
||||
"Folder Path": "Ścieżka folderu",
|
||||
"Folder Type": "Rodzaj folderu",
|
||||
@@ -307,13 +308,13 @@
|
||||
"Shared Folders": "Współdzielone foldery",
|
||||
"Shared With": "Współdzielony z",
|
||||
"Sharing": "Współdzielenie",
|
||||
"Show ID": "Pokaż numer ID",
|
||||
"Show ID": "Pokaż identyfikator",
|
||||
"Show QR": "Pokaż kod QR",
|
||||
"Show detailed discovery status": "Pokaż szczegółowy stan odnajdywania",
|
||||
"Show detailed listener status": "Pokaż szczegółowy stan nasłuchujących",
|
||||
"Show diff with previous version": "Pokaż diff z poprzednią wersją",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Widoczna na liście urządzeń zamiast numeru ID urządzenia. Będzie anonsowana do innych urządzeń jako opcjonalna nazwa domyślna.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Widoczna na liście urządzeń zamiast numeru ID urządzenia. Będzie zaktualizowana do nazwy anonsowanej przez urządzenie, jeżeli pozostanie pusta.",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Widoczna na liście urządzeń zamiast identyfikatora urządzenia. Będzie anonsowana do innych urządzeń jako opcjonalna nazwa domyślna.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Widoczna na liście urządzeń zamiast identyfikatora urządzenia. Zostanie zaktualizowana do nazwy anonsowanej przez urządzenie, jeżeli pozostanie pusta.",
|
||||
"Shutdown": "Wyłącz",
|
||||
"Shutdown Complete": "Wyłączanie ukończone",
|
||||
"Simple File Versioning": "Proste wersjonowanie plików",
|
||||
@@ -353,12 +354,12 @@
|
||||
"The aggregated statistics are publicly available at the URL below.": "Zebrane statystyki są publicznie dostępne pod poniższym adresem.",
|
||||
"The cleanup interval cannot be blank.": "Przedział czasowy czyszczenia nie może być pusty.",
|
||||
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Ustawienia zostały zapisane, ale nie są jeszcze aktywne. Syncthing musi zostać uruchomiony ponownie, aby aktywować nowe ustawienia.",
|
||||
"The device ID cannot be blank.": "Numer ID urządzenia nie może być puste.",
|
||||
"The device ID to enter here can be found in the \"Actions > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "Numer ID urządzenia do wpisania tutaj można znaleźć w oknie \"Działania > Pokaż numer ID\" na innym urządzeniu. Spacje i myślniki są opcjonalne (ignorowane).",
|
||||
"The device ID cannot be blank.": "Identyfikator urządzenia nie może być pusty.",
|
||||
"The device ID to enter here can be found in the \"Actions > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "Identyfikator urządzenia do wpisania tutaj można znaleźć w oknie \"Działania > Pokaż identyfikator\" na innym urządzeniu. Spacje i myślniki są opcjonalne (ignorowane).",
|
||||
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Zaszyfrowane statystyki użycia są wysyłane codziennie. Używane są one do śledzenia popularności systemów, rozmiarów folderów oraz wersji programu. Jeżeli wysyłane statystyki ulegną zmianie, zostaniesz poproszony o ponowne udzielenie zgody w tym oknie.",
|
||||
"The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "Wprowadzony numer ID urządzenia wygląda na niepoprawny. Musi ono zawierać 52 lub 56 znaków składających się z liter i cyfr. Spacje i myślniki są opcjonalne.",
|
||||
"The folder ID cannot be blank.": "Numer ID folderu nie może być pusty.",
|
||||
"The folder ID must be unique.": "Numer ID folderu musi być niepowtarzalny.",
|
||||
"The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "Wprowadzony identyfikator urządzenia wygląda na niepoprawny. Musi on zawierać 52 lub 56 znaków składających się z liter i cyfr. Spacje i myślniki są opcjonalne.",
|
||||
"The folder ID cannot be blank.": "Identyfikator folderu nie może być pusty.",
|
||||
"The folder ID must be unique.": "Identyfikator folderu musi być niepowtarzalny.",
|
||||
"The folder content on other devices will be overwritten to become identical with this device. Files not present here will be deleted on other devices.": "Zawartość folderu na innych urządzeniach zostanie nadpisana tak, aby upodobnić się do tego urządzenia. Pliki nieobecne tutaj zostaną usunięte na innych urządzeniach.",
|
||||
"The folder content on this device will be overwritten to become identical with other devices. Files newly added here will be deleted.": "Zawartość folderu na tym urządzeniu zostanie nadpisana tak, aby upodobnić się do innych urządzeń. Pliki nowo dodane tutaj zostaną usunięte.",
|
||||
"The folder path cannot be blank.": "Ścieżka folderu nie może być pusta.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Liczba wersji musi być wartością liczbową oraz nie może być pusta.",
|
||||
"The path cannot be blank.": "Ścieżka nie może być pusta.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "Ograniczenie prędkości musi być nieujemną wartością liczbową (0: brak ograniczeń)",
|
||||
"The remote device has not accepted sharing this folder.": "Urządzenie zdalne nie wyraziło zgody na udostępnienie tego folderu.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Przedział czasowy ponownego skanowania musi być nieujemną liczbą sekund.",
|
||||
"There are no devices to share this folder with.": "Brak urządzeń, z którymi można współdzielić ten folder.",
|
||||
"There are no file versions to restore.": "Brak wersji plików, które można przywrócić.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Czas ostatniej modyfikacji elementu",
|
||||
"Today": "Dzisiaj",
|
||||
"Trash Can File Versioning": "Wersjonowanie plików w koszu",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Rodzaj",
|
||||
"UNIX Permissions": "UNIX-owe uprawnienia",
|
||||
"Unavailable": "Niedostępne",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Niewspółdzielone foldery",
|
||||
"Untrusted": "Niezaufany",
|
||||
"Up to Date": "Aktualny",
|
||||
"Updated": "Zaktualizowano",
|
||||
"Updated {%file%}": "Zaktualizowano {{file}}",
|
||||
"Upgrade": "Aktualizacja",
|
||||
"Upgrade To {%version%}": "Aktualizuj do {{version}}",
|
||||
"Upgrading": "Aktualizowanie",
|
||||
@@ -433,7 +436,7 @@
|
||||
"Watching for Changes": "Obserwowanie zmian",
|
||||
"Watching for changes discovers most changes without periodic scanning.": "Obserwowanie wykrywa większość zmian bez potrzeby okresowego skanowania.",
|
||||
"When adding a new device, keep in mind that this device must be added on the other side too.": "Dodając nowe urządzenie pamiętaj, że musi ono zostać dodane także po drugiej stronie.",
|
||||
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "Dodając nowy folder pamiętaj, że numer ID jest używany do parowania folderów pomiędzy urządzeniami. Wielkość liter ma znaczenie i musi on być identyczny na wszystkich urządzeniach.",
|
||||
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "Dodając nowy folder pamiętaj, że identyfikator używany jest do parowania folderów pomiędzy urządzeniami. Wielkość liter ma znaczenie i musi być on identyczny na wszystkich urządzeniach.",
|
||||
"Yes": "Tak",
|
||||
"Yesterday": "Wczoraj",
|
||||
"You can also select one of these nearby devices:": "Możesz również wybrać jedno z pobliskich urządzeń:",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Um comando externo controla o controle de versão. Tem que remover o arquivo da pasta compartilhada. Se o caminho para o aplicativo contiver espaços, ele deve ser colocado entre aspas.",
|
||||
"Anonymous Usage Reporting": "Relatórios anônimos de uso",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "O formato do relatório anônimo de uso mudou. Gostaria de usar o formato novo?",
|
||||
"Apply": "Aplicar",
|
||||
"Are you sure you want to continue?": "Deseja realmente continuar?",
|
||||
"Are you sure you want to override all remote changes?": "Tem a certeza que quer sobrepor todas as alterações remotas?",
|
||||
"Are you sure you want to permanently delete all these files?": "Deseja realmente excluir todos estes arquivos permanentemente?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Padrões",
|
||||
"Delete": "Apagar",
|
||||
"Delete Unexpected Items": "Excluir Itens Inesperados",
|
||||
"Deleted": "Apagado",
|
||||
"Deleted {%file%}": "{{file}} excluído",
|
||||
"Deselect All": "Desmarcar Todos",
|
||||
"Deselect devices to stop sharing this folder with.": "Desmarque os dispositivos com os quais parar de compartilhar esta pasta.",
|
||||
"Deselect folders to stop sharing with this device.": "Desmarque as pastas para interromper o compartilhamento com este dispositivo.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "O número de versões deve ser um valor numérico. O campo não pode ficar vazio.",
|
||||
"The path cannot be blank.": "O caminho não pode ficar vazio.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "O limite de velocidade deve ser um número positivo (0: sem limite)",
|
||||
"The remote device has not accepted sharing this folder.": "O dispositivo remoto não aceitou compartilhar esta pasta.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "O intervalo entre verificações deve ser um número positivo de segundos.",
|
||||
"There are no devices to share this folder with.": "Não há dispositivos com os quais compartilhar esta pasta.",
|
||||
"There are no file versions to restore.": "Não há versões do arquivo para restaurar.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Momento em que o item foi modificado pela última vez",
|
||||
"Today": "Hoje",
|
||||
"Trash Can File Versioning": "Lixeira",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Tipo",
|
||||
"UNIX Permissions": "Permissões UNIX",
|
||||
"Unavailable": "Não disponível",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Pastas Não Compartilhadas",
|
||||
"Untrusted": "Não confiável",
|
||||
"Up to Date": "Em sincronia",
|
||||
"Updated": "Atualizado",
|
||||
"Updated {%file%}": "{{file}} atualizado",
|
||||
"Upgrade": "Atualização",
|
||||
"Upgrade To {%version%}": "Atualizar para {{version}}",
|
||||
"Upgrading": "Atualizando",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Um comando externo controla as versões. Esse comando tem que remover o ficheiro da pasta partilhada. Se o caminho para a aplicação contiver espaços, então terá de o escrever entre aspas.",
|
||||
"Anonymous Usage Reporting": "Enviar relatórios anónimos de utilização",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "O formato do relatório anónimo de utilização foi alterado. Gostaria de mudar para o novo formato?",
|
||||
"Apply": "Aplicar",
|
||||
"Are you sure you want to continue?": "Tem a certeza de que quer continuar?",
|
||||
"Are you sure you want to override all remote changes?": "Tem a certeza que quer sobrepor todas as alterações remotas?",
|
||||
"Are you sure you want to permanently delete all these files?": "Tem a certeza de que quer eliminar permanentemente todos estes ficheiros?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Predefinições",
|
||||
"Delete": "Eliminar",
|
||||
"Delete Unexpected Items": "Eliminar itens inesperados",
|
||||
"Deleted": "Eliminado",
|
||||
"Deleted {%file%}": "{{file}} eliminado",
|
||||
"Deselect All": "Retirar todas as selecções",
|
||||
"Deselect devices to stop sharing this folder with.": "Retire a selecção para deixar de partilhar a pasta com esses dispositivos.",
|
||||
"Deselect folders to stop sharing with this device.": "Retire a selecção das pastas para deixar de as partilhar com este dispositivo.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "O número de versões tem que ser um número e não pode estar vazio.",
|
||||
"The path cannot be blank.": "O caminho não pode estar vazio.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "O limite de velocidade tem que ser um número que não seja negativo (0: sem limite)",
|
||||
"The remote device has not accepted sharing this folder.": "O dispositivo remoto não aceitou a partilha desta pasta.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "O intervalo entre verificações tem que ser um valor não negativo de segundos.",
|
||||
"There are no devices to share this folder with.": "Não existem quaisquer dispositivos com os quais se possa partilhar esta pasta.",
|
||||
"There are no file versions to restore.": "Não existem versões do ficheiro para restaurar.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Quando o item foi modificado pela última vez",
|
||||
"Today": "Hoje",
|
||||
"Trash Can File Versioning": "Reciclagem",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Tipo",
|
||||
"UNIX Permissions": "Permissões UNIX",
|
||||
"Unavailable": "Indisponível",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Pastas não partilhadas",
|
||||
"Untrusted": "Não fiável",
|
||||
"Up to Date": "Em sincronia",
|
||||
"Updated": "Actualizado",
|
||||
"Updated {%file%}": "{{file}} modificado",
|
||||
"Upgrade": "Actualizar",
|
||||
"Upgrade To {%version%}": "Actualizar para {{version}}",
|
||||
"Upgrading": "Actualizando",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "O comandă externă gestionează versiunea. Trebuie să elimine fișierul din folderul partajat. Dacă calea către aplicație conține spații, ar trebui să fie pusă între ghilimele.",
|
||||
"Anonymous Usage Reporting": "Raport Anonim despre Folosirea Aplicației",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Formatul raportului de utilizare anonim s-a schimbat. Doriți să vă mutați în noul format?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Ești sigur ca vrei sa continui?",
|
||||
"Are you sure you want to override all remote changes?": "Are you sure you want to override all remote changes?",
|
||||
"Are you sure you want to permanently delete all these files?": "Sigur doriți să ștergeți definitiv toate aceste fișiere?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Defaults",
|
||||
"Delete": "Şterge",
|
||||
"Delete Unexpected Items": "Delete Unexpected Items",
|
||||
"Deleted": "Șters",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Deselect All",
|
||||
"Deselect devices to stop sharing this folder with.": "Deselect devices to stop sharing this folder with.",
|
||||
"Deselect folders to stop sharing with this device.": "Deselect folders to stop sharing with this device.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Numărul de versiuni trebuie să fie un număr şi nu poate fi gol.",
|
||||
"The path cannot be blank.": "Locația nu poate fi goală.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "The rate limit must be a non-negative number (0: no limit)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Intervalul de rescanare trebuie să nu fie un număr negativ de secunde. ",
|
||||
"There are no devices to share this folder with.": "There are no devices to share this folder with.",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Time the item was last modified",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "Trash Can File Versioning",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Type",
|
||||
"UNIX Permissions": "UNIX Permissions",
|
||||
"Unavailable": "Unavailable",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Unshared Folders",
|
||||
"Untrusted": "Untrusted",
|
||||
"Up to Date": "La Zi",
|
||||
"Updated": "Updated",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Upgrade",
|
||||
"Upgrade To {%version%}": "Actualizează La Versiunea {{version}}",
|
||||
"Upgrading": "Se Actualizează",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Для версионирования используется внешняя программа. Ей нужно удалить файл из общей папки. Если путь к приложению содержит пробелы, его нужно взять в кавычки.",
|
||||
"Anonymous Usage Reporting": "Анонимный отчет об использовании",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Формат анонимных отчётов изменился. Хотите переключиться на новый формат?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Уверены, что хотите продолжить?",
|
||||
"Are you sure you want to override all remote changes?": "Уверены, что хотите перезаписать все удалённые изменения?",
|
||||
"Are you sure you want to permanently delete all these files?": "Уверены, что хотите навсегда удалить эти файлы?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Стандартные параметры",
|
||||
"Delete": "Удалить",
|
||||
"Delete Unexpected Items": "Удалить неожиданные элементы",
|
||||
"Deleted": "Удалено",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Снять выделение",
|
||||
"Deselect devices to stop sharing this folder with.": "Отмените выбор устройств, чтобы прекратить совместное использование этой папки.",
|
||||
"Deselect folders to stop sharing with this device.": "Отмените выбор папок, чтобы прекратить совместное использование с этим устройством.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Количество версий должно быть числом и не может быть пустым.",
|
||||
"The path cannot be blank.": "Путь не может быть пустым.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "Скорость должна быть неотрицательным числом (0: нет ограничения)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Интервал пересканирования должен быть неотрицательным количеством секунд.",
|
||||
"There are no devices to share this folder with.": "Нет устройств, для которых будет доступна эта папка.",
|
||||
"There are no file versions to restore.": "Нет версий файла для восстановления.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Время последней модификации объекта",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "Использовать версионность для файлов в Корзине",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Тип",
|
||||
"UNIX Permissions": "Разрешения UNIX",
|
||||
"Unavailable": "Недоступно",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Не общедоступные папки",
|
||||
"Untrusted": "Ненадёжный",
|
||||
"Up to Date": "В актуальном состоянии",
|
||||
"Updated": "Обновлено",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Обновить",
|
||||
"Upgrade To {%version%}": "Обновить до {{version}}",
|
||||
"Upgrading": "Обновление",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.",
|
||||
"Anonymous Usage Reporting": "Anonymné hlásenie o používaní",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Formát anonymného hlásenia o používaní sa zmenil. Chcete prejsť na nový formát?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Are you sure you want to continue?",
|
||||
"Are you sure you want to override all remote changes?": "Are you sure you want to override all remote changes?",
|
||||
"Are you sure you want to permanently delete all these files?": "Určite chcete vymazať všetky tieto súbory?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Defaults",
|
||||
"Delete": "Delete",
|
||||
"Delete Unexpected Items": "Delete Unexpected Items",
|
||||
"Deleted": "Zmazané",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Odznačiť všetko",
|
||||
"Deselect devices to stop sharing this folder with.": "Deselect devices to stop sharing this folder with.",
|
||||
"Deselect folders to stop sharing with this device.": "Deselect folders to stop sharing with this device.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Počet verzií musí byť číslo a nemôže byť prázdny.",
|
||||
"The path cannot be blank.": "Cesta nemôže byť prázdna.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "Limit rýchlosti musí byť kladné číslo (0: bez limitu)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "The rescan interval must be a non-negative number of seconds.",
|
||||
"There are no devices to share this folder with.": "There are no devices to share this folder with.",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Čas poslednej zmeny položky",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "Verzie súborov v koši",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Typ",
|
||||
"UNIX Permissions": "UNIX Permissions",
|
||||
"Unavailable": "Nedostupné",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Unshared Folders",
|
||||
"Untrusted": "Untrusted",
|
||||
"Up to Date": "Aktuálne",
|
||||
"Updated": "Aktualizované",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Aktualizácia",
|
||||
"Upgrade To {%version%}": "Aktualizovať na {{version}}",
|
||||
"Upgrading": "Aktualizácia",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Zunanji ukaz upravlja z različicami. To mora odstraniti datoteko od deljene mape. Če pot do aplikacije vsebuje presledke, jo postavite v dvojne narekovaje.",
|
||||
"Anonymous Usage Reporting": "Brezimno poročanje o uporabi",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Format anonimnega poročanja uporabe se je spremenil. Ali želite se premakniti na novi format?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Ste prepričani, da želite nadaljevati?",
|
||||
"Are you sure you want to override all remote changes?": "Ali ste prepričani, da želite preglasiti vse oddaljene spremembe?",
|
||||
"Are you sure you want to permanently delete all these files?": "Ste prepričani, da želite trajno izbrisati datoteke?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Privzeti",
|
||||
"Delete": "Izbriši",
|
||||
"Delete Unexpected Items": "Izbrišite nepričakovane predmete",
|
||||
"Deleted": "Izbrisana",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Prekliči vse",
|
||||
"Deselect devices to stop sharing this folder with.": "Prekliči izbiro naprav, z katerimi ne želiš več deliti mape.",
|
||||
"Deselect folders to stop sharing with this device.": "Prekliči mape, da se ne delijo več z to napravo.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Število različic mora biti število in ne more biti prazno.",
|
||||
"The path cannot be blank.": "Pot ne more biti prazna.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "Omejitev stopnje odzivnosti mora biti nenegativno število (0: brez omejitve)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Interval skeniranja mora biti pozitivna številka.",
|
||||
"There are no devices to share this folder with.": "Ni naprav za skupno rabo te mape.",
|
||||
"There are no file versions to restore.": "Ni različic od datotek za obnoviti.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Čas, ko je bil element nazadnje spremenjen",
|
||||
"Today": "Danes",
|
||||
"Trash Can File Versioning": "Beleženje različic datotek s Smetnjakom",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Vrsta",
|
||||
"UNIX Permissions": "UNIX dovoljenja",
|
||||
"Unavailable": "Ni na voljo",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Mape, ki niso v skupni rabi",
|
||||
"Untrusted": "Nezaupno",
|
||||
"Up to Date": "Posodobljeno",
|
||||
"Updated": "Posodobljeno",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Posodobi",
|
||||
"Upgrade To {%version%}": "Posodobi na različico {{version}}",
|
||||
"Upgrading": "Posodabljanje",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Ett externt kommando hanterar versionen. Det måste ta bort filen från den delade mappen. Om sökvägen till applikationen innehåller mellanslag bör den citeras.",
|
||||
"Anonymous Usage Reporting": "Anonym användarstatistiksrapportering",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Anonymt användningsrapportformat har ändrats. Vill du flytta till det nya formatet?",
|
||||
"Apply": "Tillämpa",
|
||||
"Are you sure you want to continue?": "Är du säker på att du vill fortsätta?",
|
||||
"Are you sure you want to override all remote changes?": "Är du säker på att du vill åsidosätta alla fjärrändringar?",
|
||||
"Are you sure you want to permanently delete all these files?": "Är du säker på att du vill ta bort alla dessa filer permanent?",
|
||||
@@ -77,9 +78,9 @@
|
||||
"Defaults": "Standard",
|
||||
"Delete": "Ta bort",
|
||||
"Delete Unexpected Items": "Ta bort oväntade objekt",
|
||||
"Deleted": "Borttagna",
|
||||
"Deleted {%file%}": "Tog bort {{file}}",
|
||||
"Deselect All": "Avmarkera alla",
|
||||
"Deselect devices to stop sharing this folder with.": "Avmarkera enheter för att sluta dela denna mapp med.",
|
||||
"Deselect devices to stop sharing this folder with.": "Avmarkera enheter som du vill sluta dela denna mapp med.",
|
||||
"Deselect folders to stop sharing with this device.": "Avmarkera mappar för att sluta dela med denna enhet.",
|
||||
"Device": "Enhet",
|
||||
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Enhet \"{{name}}\" ({{device}} på {{address}}) vill ansluta. Lägg till ny enhet?",
|
||||
@@ -249,9 +250,9 @@
|
||||
"Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:": "Periodisk skanning vid givet intervall och misslyckades med att ställa in bevakning av ändringar, försöker igen var 1:e minut:",
|
||||
"Permanently add it to the ignore list, suppressing further notifications.": "Lägg till det permanent i ignoreringslistan och undertryck ytterligare aviseringar.",
|
||||
"Permissions": "Behörigheter",
|
||||
"Please consult the release notes before performing a major upgrade.": "Vänligen läs igenom versionsnyheterna innan du utför en större uppgradering.",
|
||||
"Please set a GUI Authentication User and Password in the Settings dialog.": "Vänligen ställ in en autentiseringsanvändare och ett lösenord för det grafiska användargränssnittet i dialogrutan Inställningar.",
|
||||
"Please wait": "Vänligen vänta",
|
||||
"Please consult the release notes before performing a major upgrade.": "Läs igenom versionsnyheterna innan du utför en större uppgradering.",
|
||||
"Please set a GUI Authentication User and Password in the Settings dialog.": "Ställ in en autentiseringsanvändare och ett lösenord för det grafiska användargränssnittet i dialogrutan Inställningar.",
|
||||
"Please wait": "Vänta",
|
||||
"Prefix indicating that the file can be deleted if preventing directory removal": "Prefix som indikerar att filen kan tas bort om den förhindrar mappborttagning",
|
||||
"Prefix indicating that the pattern should be matched without case sensitivity": "Prefix som indikerar att mönstret ska matchas utan skiftlägeskänslighet",
|
||||
"Preparing to Sync": "Förberedelser för synkronisering",
|
||||
@@ -345,7 +346,7 @@
|
||||
"Syncthing is upgrading.": "Syncthing uppgraderas.",
|
||||
"Syncthing now supports automatically reporting crashes to the developers. This feature is enabled by default.": "Syncthing stöder nu automatiskt kraschrapportering till utvecklarna. Denna funktion är aktiverad som standard.",
|
||||
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing verkar vara avstängd eller så är det problem med din internetanslutning. Försöker igen...",
|
||||
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing verkar ha drabbats av ett problem med behandlingen av din förfrågan. Vänligen uppdatera sidan eller starta om Syncthing om problemet kvarstår.",
|
||||
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing verkar ha drabbats av ett problem med behandlingen av din förfrågan. Uppdatera sidan eller starta om Syncthing om problemet kvarstår.",
|
||||
"Take me back": "Ta mig tillbaka",
|
||||
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "Den grafiska gränssnittsadressen åsidosätts av startalternativ. Ändringar här träder inte i kraft så länge åsidosättningen är på plats.",
|
||||
"The Syncthing Authors": "Syncthing-upphovsmän",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Antalet versioner måste vara ett nummer och kan inte lämnas tomt.",
|
||||
"The path cannot be blank.": "Sökvägen kan inte vara tom.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "Frekvensgränsen måste vara ett icke-negativt tal (0: ingen gräns)",
|
||||
"The remote device has not accepted sharing this folder.": "Fjärrenheten har inte accepterat delning av den här mappen.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Förnyelseintervallet måste vara ett positivt antal sekunder",
|
||||
"There are no devices to share this folder with.": "Det finns inga enheter att dela denna mapp med.",
|
||||
"There are no file versions to restore.": "Det finns inga filversioner att återställa.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Tidpunkten objektet var senast ändrad",
|
||||
"Today": "Idag",
|
||||
"Trash Can File Versioning": "Papperskorgs filversionshantering",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Typ",
|
||||
"UNIX Permissions": "UNIX-behörigheter",
|
||||
"Unavailable": "Otillgänglig",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Odelade mappar",
|
||||
"Untrusted": "Opålitlig",
|
||||
"Up to Date": "Uppdaterad",
|
||||
"Updated": "Uppdaterade",
|
||||
"Updated {%file%}": "Uppdaterade {{file}}",
|
||||
"Upgrade": "Uppgradering",
|
||||
"Upgrade To {%version%}": "Uppgradera till {{version}}",
|
||||
"Upgrading": "Uppgraderar",
|
||||
@@ -415,7 +418,7 @@
|
||||
"Usage reporting is always enabled for candidate releases.": "Användningsrapportering är alltid aktiverad för kandidatutgåvor.",
|
||||
"Use HTTPS for GUI": "Använd HTTPS för gränssnitt",
|
||||
"Use notifications from the filesystem to detect changed items.": "Använd aviseringar från filsystemet för att upptäcka ändrade objekt.",
|
||||
"Username/Password has not been set for the GUI authentication. Please consider setting it up.": "Användarnamn/lösenord har inte ställts in för autentisering av det grafiska gränssnittet. Vänligen överväg att ställa in det.",
|
||||
"Username/Password has not been set for the GUI authentication. Please consider setting it up.": "Användarnamn/lösenord har inte ställts in för autentisering av det grafiska gränssnittet. Överväg att ställa in det.",
|
||||
"Version": "Version",
|
||||
"Versions": "Versioner",
|
||||
"Versions Path": "Sökväg för versioner",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Harici bir komut sürümlendirmeyi gerçekleştirir. Dosyayı paylaşılan klasörden kaldırmak zorundadır. Eğer uygulama yolu boşluklar içeriyorsa, tırnak içine alınmalıdır.",
|
||||
"Anonymous Usage Reporting": "İsimsiz Kullanım Bildirme",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "İsimsiz kullanım raporu biçimi değişti. Yeni biçime geçmek ister misiniz?",
|
||||
"Apply": "Uygula",
|
||||
"Are you sure you want to continue?": "Devam etmek istediğinize emin misiniz?",
|
||||
"Are you sure you want to override all remote changes?": "Tüm uzak değişiklikleri geçersiz kılmak istediğinize emin misiniz?",
|
||||
"Are you sure you want to permanently delete all these files?": "Tüm bu dosyaları kalıcı olarak silmek istediğinize emin misiniz?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Varsayılanlar",
|
||||
"Delete": "Sil",
|
||||
"Delete Unexpected Items": "Beklenmeyen Öğeleri Sil",
|
||||
"Deleted": "Silinen",
|
||||
"Deleted {%file%}": "{{file}} silindi",
|
||||
"Deselect All": "Tüm Seçimi Kaldır",
|
||||
"Deselect devices to stop sharing this folder with.": "Bu klasörün paylaşımının durdurulacağı cihazların seçimini kaldırın.",
|
||||
"Deselect folders to stop sharing with this device.": "Bu cihazla paylaşımı durdurulacak klasörlerin seçimini kaldırın.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Sürüm sayısı bir sayı olmak zorundadır ve boş bırakılamaz.",
|
||||
"The path cannot be blank.": "Yol boş olamaz.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "Hız sınırı negatif olmayan bir sayı olmak zorundadır (0: sınır yok)",
|
||||
"The remote device has not accepted sharing this folder.": "Uzak cihaz bu klasörü paylaşmayı kabul etmedi.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Yeniden tarama aralığı negatif olmayan bir saniye sayısı olmak zorundadır.",
|
||||
"There are no devices to share this folder with.": "Bu klasörün paylaşılacağı cihazlar yok.",
|
||||
"There are no file versions to restore.": "Geri yüklenecek dosya sürümleri yok.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Öğenin son düzenlendiği zaman",
|
||||
"Today": "Bugün",
|
||||
"Trash Can File Versioning": "Çöp Kutusu Dosyası Sürümlendirme",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Tür",
|
||||
"UNIX Permissions": "Unix İzinleri",
|
||||
"Unavailable": "Kullanılamaz",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Paylaşılmayan Klasörler",
|
||||
"Untrusted": "Güvenilmez",
|
||||
"Up to Date": "Güncel",
|
||||
"Updated": "Güncellenen",
|
||||
"Updated {%file%}": "{{file}} güncellendi",
|
||||
"Upgrade": "Yükselt",
|
||||
"Upgrade To {%version%}": "{{version}} Sürümüne Yükselt",
|
||||
"Upgrading": "Yükseltiliyor",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Зовнішня команда керування версіями. Вона має видалити файл із спільної директорії. Якщо шлях до програми містить пробіли, він буде взятий у лапки.",
|
||||
"Anonymous Usage Reporting": "Анонімна статистика використання",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Змінився формат анонімного звіту про користування. Бажаєте перейти на новий формат?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Are you sure you want to continue?",
|
||||
"Are you sure you want to override all remote changes?": "Are you sure you want to override all remote changes?",
|
||||
"Are you sure you want to permanently delete all these files?": "Are you sure you want to permanently delete all these files?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Defaults",
|
||||
"Delete": "Видалити",
|
||||
"Delete Unexpected Items": "Delete Unexpected Items",
|
||||
"Deleted": "Видалене",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "Зняти вибір з усіх",
|
||||
"Deselect devices to stop sharing this folder with.": "Зніміть вибір з пристроїв, які не матимуть доступу до цієї директорії.",
|
||||
"Deselect folders to stop sharing with this device.": "Deselect folders to stop sharing with this device.",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "Кількість версій повинна бути цифрою та не може бути порожньою.",
|
||||
"The path cannot be blank.": "Шлях не може бути порожнім.",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "Швидкість має бути додатнім числом.",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "Інтервал повторного сканування повинен бути неід’ємною величиною.",
|
||||
"There are no devices to share this folder with.": "Відсутні пристрої, які мають доступ до цієї директорії.",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "Час останньої зміни елемента:",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "Версіонування файлів у кошику ",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "Тип",
|
||||
"UNIX Permissions": "UNIX дозволи",
|
||||
"Unavailable": "Недоступно",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "Unshared Folders",
|
||||
"Untrusted": "Untrusted",
|
||||
"Up to Date": "Актуальна версія",
|
||||
"Updated": "Оновлено",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "Оновлення",
|
||||
"Upgrade To {%version%}": "Оновити до {{version}}",
|
||||
"Upgrading": "Оновлення",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "外部命令接管了版本控制。该外部命令必须自行从共享文件夹中删除该文件。如果此应用程序的路径包含空格,应该用半角引号括起来。",
|
||||
"Anonymous Usage Reporting": "匿名使用报告",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "匿名使用情况的报告格式已经变更。是否要迁移到新的格式?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "您确定要继续吗?",
|
||||
"Are you sure you want to override all remote changes?": "您确定要覆盖所有远程更改吗? ",
|
||||
"Are you sure you want to permanently delete all these files?": "确认要永久删除这些文件吗?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "默认值",
|
||||
"Delete": "删除",
|
||||
"Delete Unexpected Items": "删除特殊项目",
|
||||
"Deleted": "已删除",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "取消全选",
|
||||
"Deselect devices to stop sharing this folder with.": "反选设备以停止共享此文件夹",
|
||||
"Deselect folders to stop sharing with this device.": "取消选择文件夹以停止与此设备共享。",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "保留版本数量必须为数字,且不能为空。",
|
||||
"The path cannot be blank.": "路径不能为空。",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "传输速度限制为非负整数(0 表示不限制)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "扫描间隔单位为秒,且不能为负数。",
|
||||
"There are no devices to share this folder with.": "没有设备共享此文件夹",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "该项最近修改的时间",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "回收站式版本控制",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "类型",
|
||||
"UNIX Permissions": "UNIX权限",
|
||||
"Unavailable": "无效",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "非共享文件夹",
|
||||
"Untrusted": "不可信的",
|
||||
"Up to Date": "同步完成",
|
||||
"Updated": "已更新",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "更新",
|
||||
"Upgrade To {%version%}": "升级至版本 {{version}}",
|
||||
"Upgrading": "升级中",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "外部命令接管了版本控制。該外部命令必須自行從共享文件夾中刪除該文件。如果此應用程序的路徑包含空格,應該用半角引號括起來。",
|
||||
"Anonymous Usage Reporting": "匿名使用報告",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "匿名使用情況的報告格式已經變更。是否要遷移到新的格式?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "Are you sure you want to continue?",
|
||||
"Are you sure you want to override all remote changes?": "Are you sure you want to override all remote changes?",
|
||||
"Are you sure you want to permanently delete all these files?": "Are you sure you want to permanently delete all these files?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "Defaults",
|
||||
"Delete": "Delete",
|
||||
"Delete Unexpected Items": "刪除不需要項目",
|
||||
"Deleted": "已刪除",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "取消全選",
|
||||
"Deselect devices to stop sharing this folder with.": "反選設備以停止共享此文件夾",
|
||||
"Deselect folders to stop sharing with this device.": "停止選擇文件夾以停止與此設備共享。",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "保留版本數量必須為數字,且不能為空。",
|
||||
"The path cannot be blank.": "路徑不能為空。",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "傳輸速度限制為非負整數(0 表示不限制)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "掃瞄間隔單位為秒,且不能為負數。",
|
||||
"There are no devices to share this folder with.": "沒有設備共享此文件夾",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "該項最近修改的時間",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "回收站式版本控制",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "類型",
|
||||
"UNIX Permissions": "UNIX權限",
|
||||
"Unavailable": "無效",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "未共享的文件夾",
|
||||
"Untrusted": "不信任",
|
||||
"Up to Date": "同步完成",
|
||||
"Updated": "已更新",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "更新",
|
||||
"Upgrade To {%version%}": "升級至版本 {{version}}",
|
||||
"Upgrading": "升級中",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "外部指令接管了版本控制。它必須將檔案自分享資料夾中移除。如果應用程式的路徑包含了空格,則必須使用雙引號刮起。",
|
||||
"Anonymous Usage Reporting": "匿名數據回報",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "匿名數據回報格式已經變更,想要移至新格式嗎?",
|
||||
"Apply": "Apply",
|
||||
"Are you sure you want to continue?": "您確定要繼續嗎?",
|
||||
"Are you sure you want to override all remote changes?": "Are you sure you want to override all remote changes?",
|
||||
"Are you sure you want to permanently delete all these files?": "確認永久刪除檔案?",
|
||||
@@ -77,7 +78,7 @@
|
||||
"Defaults": "預設",
|
||||
"Delete": "刪除",
|
||||
"Delete Unexpected Items": "刪除不預期的項目",
|
||||
"Deleted": "已刪除",
|
||||
"Deleted {%file%}": "Deleted {{file}}",
|
||||
"Deselect All": "取消選取全部",
|
||||
"Deselect devices to stop sharing this folder with.": "取消選擇裝置以停用與其共享資料夾。",
|
||||
"Deselect folders to stop sharing with this device.": "取消選擇資料夾以停用與此裝置共享。",
|
||||
@@ -377,6 +378,7 @@
|
||||
"The number of versions must be a number and cannot be blank.": "每個檔案要保留的舊版本數量必須是數字且不能為空白。",
|
||||
"The path cannot be blank.": "路徑不能空白。",
|
||||
"The rate limit must be a non-negative number (0: no limit)": "限制速率必須為非負的數字 (0: 不設限制)",
|
||||
"The remote device has not accepted sharing this folder.": "The remote device has not accepted sharing this folder.",
|
||||
"The rescan interval must be a non-negative number of seconds.": "重新掃描間隔必須為一個非負數的秒數。",
|
||||
"There are no devices to share this folder with.": "沒有裝置可以共享此資料夾。",
|
||||
"There are no file versions to restore.": "There are no file versions to restore.",
|
||||
@@ -392,6 +394,7 @@
|
||||
"Time the item was last modified": "前次修改時間",
|
||||
"Today": "Today",
|
||||
"Trash Can File Versioning": "垃圾筒式檔案版本控制",
|
||||
"Twitter": "Twitter",
|
||||
"Type": "類型",
|
||||
"UNIX Permissions": "UNIX 權限",
|
||||
"Unavailable": "無法使用",
|
||||
@@ -406,7 +409,7 @@
|
||||
"Unshared Folders": "未共享的資料夾",
|
||||
"Untrusted": "不信任",
|
||||
"Up to Date": "最新",
|
||||
"Updated": "已更新",
|
||||
"Updated {%file%}": "Updated {{file}}",
|
||||
"Upgrade": "更新",
|
||||
"Upgrade To {%version%}": "更新至 {{version}}",
|
||||
"Upgrading": "正在升級",
|
||||
|
||||
@@ -532,7 +532,9 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th><span class="fas fa-fw fa-share-alt"></span> <span translate>Shared With</span></th>
|
||||
<td class="text-right" ng-attr-title="{{sharesFolder(folder)}}">{{sharesFolder(folder)}}</td>
|
||||
<td class="text-right">
|
||||
<span tooltip data-original-title="{{sharesFolder(folder)}} {{folderHasUnacceptedDevices(folder) ? '<br/>(<sup>1</sup>' + ('The remote device has not accepted sharing this folder.' | translate) + ')' : ''}}" ng-bind-html="sharesFolder(folder)"></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="folderStats[folder.id].lastScan">
|
||||
<th><span class="far fa-fw fa-clock"></span> <span translate>Last Scan</span></th>
|
||||
@@ -545,9 +547,8 @@
|
||||
<th><span class="fas fa-fw fa-exchange-alt"></span> <span translate>Latest Change</span></th>
|
||||
<td class="text-right">
|
||||
<span tooltip data-original-title="{{folderStats[folder.id].lastFile.filename}} @ {{folderStats[folder.id].lastFile.at | date:'yyyy-MM-dd HH:mm:ss'}}">
|
||||
<span translate ng-if="!folderStats[folder.id].lastFile.deleted">Updated</span>
|
||||
<span translate ng-if="folderStats[folder.id].lastFile.deleted">Deleted</span>
|
||||
{{folderStats[folder.id].lastFile.filename | basename}}
|
||||
<span translate translate-value-file="{{folderStats[folder.id].lastFile.filename | basename}}" ng-if="!folderStats[folder.id].lastFile.deleted">Updated {%file%}</span>
|
||||
<span translate translate-value-file="{{folderStats[folder.id].lastFile.filename | basename}}" ng-if="folderStats[folder.id].lastFile.deleted">Deleted {%file%}</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -667,9 +668,9 @@
|
||||
<th><span class="fas fa-fw fa-sitemap"></span> <span translate>Listeners</span></th>
|
||||
<td class="text-right">
|
||||
<span class="data" tooltip data-original-title="{{'Show detailed listener status' | translate}}.">
|
||||
<a href="" ng-class="{'text-success': listenersFailed.length == 0, 'text-danger': listenersFailed.length == listenersTotal}" ng-click="showListenerStatus()">
|
||||
{{listenersTotal-listenersFailed.length}}/{{listenersTotal}}
|
||||
</a>
|
||||
<a href="" ng-class="{'text-success': listenersTotal > 0 && listenersFailed.length == 0, 'text-danger': listenersTotal > 0 && listenersFailed.length == listenersTotal}" ng-click="showListenerStatus()">
|
||||
{{listenersTotal-listenersFailed.length}}/{{listenersTotal}}
|
||||
</a>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -678,8 +679,8 @@
|
||||
<td class="text-right">
|
||||
<span class="data" tooltip data-original-title="{{'Show detailed discovery status' | translate}}.">
|
||||
<a href="" ng-class="{'text-success': discoveryFailed.length == 0, 'text-danger': discoveryFailed.length == discoveryTotal}" ng-click="showDiscoveryStatus()">
|
||||
{{discoveryTotal-discoveryFailed.length}}/{{discoveryTotal}}
|
||||
</a>
|
||||
{{discoveryTotal-discoveryFailed.length}}/{{discoveryTotal}}
|
||||
</a>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -833,7 +834,9 @@
|
||||
</tr>
|
||||
<tr ng-if="deviceFolders(deviceCfg).length > 0">
|
||||
<th><span class="fas fa-fw fa-folder"></span> <span translate>Folders</span></th>
|
||||
<td class="text-right" ng-attr-title="{{deviceFolders(deviceCfg).map(folderLabel).join(', ')}}">{{deviceFolders(deviceCfg).map(folderLabel).join(", ")}}</td>
|
||||
<td class="text-right">
|
||||
<span tooltip data-original-title="{{sharedFolders(deviceCfg)}} {{deviceHasUnacceptedFolders(deviceCfg) ? '<br/>(<sup>1</sup>' + ('The remote device has not accepted sharing this folder.' | translate) + ')' : '' }}" ng-bind-html="sharedFolders(deviceCfg)"></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="deviceCfg.remoteGUIPort > 0">
|
||||
<th><span class="fas fa-fw fa-desktop"></span> <span translate>Remote GUI</span></th>
|
||||
@@ -892,13 +895,13 @@
|
||||
<div class="container">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a class="navbar-link" href="https://syncthing.net/" target="_blank"><span class="fas fa-home"></span> <span translate>Home page</span></a></li>
|
||||
<li><a class="navbar-link" href="https://docs.syncthing.net/" target="_blank"><span class="fas fa-book"></span> <span translate>Documentation</span></a></li>
|
||||
<li><a class="navbar-link" href="{{docsURL()}}" target="_blank"><span class="fas fa-book"></span> <span translate>Documentation</span></a></li>
|
||||
<li><a class="navbar-link" href="https://forum.syncthing.net" target="_blank"><span class="fas fa-question-circle"></span> <span translate>Support</span></a></li>
|
||||
<li><a class="navbar-link" href="https://data.syncthing.net/" target="_blank"><span class="fas fa-bar-chart"></span> <span translate>Statistics</span></a></li>
|
||||
<li><a class="navbar-link" href="https://github.com/syncthing/syncthing/releases" target="_blank"><span class="far fa-file-alt"></span> <span translate>Changelog</span></a></li>
|
||||
<li><a class="navbar-link" href="https://github.com/syncthing/syncthing/issues" target="_blank"><span class="fas fa-bug"></span> <span translate>Bugs</span></a></li>
|
||||
<li><a class="navbar-link" href="https://github.com/syncthing/syncthing" target="_blank"><span class="fas fa-wrench"></span> <span translate>Source Code</span></a></li>
|
||||
<li><a class="navbar-link" href="https://twitter.com/syncthing" target="_blank"><span class="fab fa-twitter"></span> Twitter</a></li>
|
||||
<li><a class="navbar-link" href="https://twitter.com/syncthing" target="_blank"><span class="fab fa-twitter"></span> <span translate>Twitter</span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<h4 class="text-center" translate>The Syncthing Authors</h4>
|
||||
<div class="row">
|
||||
<div class="col-md-12" id="contributor-list">
|
||||
Aaron Bieber, Adam Piggott, Adel Qalieh, Alan Pope, Alberto Donato, Alessandro G., Alex Lindeman, Alex Xu, Alexander Graf, Alexandre Viau, Aman Gupta, Anderson Mesquita, Andrew Dunham, Andrew Rabert, Andrey D, André Colomb, Anjan Momi, Antoine Lamielle, Antony Male, Anur, Aranjedeath, Arkadiusz Tymiński, Arthur Axel fREW Schmidt, Artur Zubilewicz, Audrius Butkevicius, Aurélien Rainone, BAHADIR YILMAZ, Bart De Vries, Ben Curthoys, Ben Schulz, Ben Shepherd, Ben Sidhom, Benedikt Heine, Benedikt Morbach, Benjamin Nater, Benno Fünfstück, Benny Ng, Boqin Qin, Boris Rybalkin, Brandon Philips, Brendan Long, Brian R. Becker, Caleb Callaway, Carsten Hagemann, Cathryne Linenweaver, Cedric Staniewski, Chih-Hsuan Yen, Choongkyu, Chris Howie, Chris Joel, Chris Tonkinson, Christian Prescott, Colin Kennedy, Cromefire_, Cyprien Devillez, Dale Visser, Dan, Daniel Bergmann, Daniel Harte, Daniel Martí, Darshil Chanpura, David Rimmer, Denis A., Dennis Wilson, Dmitry Saveliev, Domenic Horner, Dominik Heidler, Elias Jarlebring, Elliot Huffman, Emil Hessman, Eric Lesiuta, Erik Meitner, Evgeny Kuznetsov, Federico Castagnini, Felix Ableitner, Felix Lampe, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gahl Saraf, Gilli Sigurdsson, Gleb Sinyavskiy, Graham Miln, Han Boetes, HansK-p, Harrison Jones, Heiko Zuerker, Hugo Locurcio, Iain Barnett, Ian Johnson, Ikko Ashimine, Ilya Brin, Iskander Sharipov, Jaakko Hannikainen, Jacek Szafarkiewicz, Jack Croft, Jacob, Jake Peterson, Jakob Borg, James Patterson, Jaroslav Lichtblau, Jaroslav Malec, Jaya Chithra, Jens Diemer, Jerry Jacobs, Jesse Lucas, Jochen Voss, Johan Andersson, Johan Vromans, John Rinehart, Jonas Thelemann, Jonathan, Jonathan Cross, Jonta, Jose Manuel Delicado, Jörg Thalheim, Jędrzej Kula, Kalle Laine, Karol Różycki, Keith Turner, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Kevin Bushiri, Kevin White, Jr., Kurt Fitzner, Lars K.W. Gohlke, Lars Lehtonen, Laurent Arnoud, Laurent Etiemble, Leo Arias, Liu Siyuan, Lode Hoste, Lord Landon Agahnim, Lukas Lihotzki, Majed Abdulaziz, Marc Laporte, Marc Pujol, Marcin Dziadus, Marcus Legendre, Mario Majila, Mark Pulford, Mateusz Naściszewski, Mateusz Ż, Matic Potočnik, Matt Burke, Matt Robenolt, Matteo Ruina, Maurizio Tomasi, Max, Max Schulze, MaximAL, Maxime Thirouin, MichaIng, Michael Jephcote, Michael Ploujnikov, Michael Rienstra, Michael Tilli, Mike Boone, MikeLund, MikolajTwarog, Mingxuan Lin, Nate Morrison, Nicholas Rishel, Nico Stapelbroek, Nicolas Braud-Santoni, Nicolas Perraut, Niels Peter Roest, Nils Jakobi, NinoM4ster, Nitroretro, NoLooseEnds, Oliver Freyermuth, Otiel, Oyebanji Jacob Mayowa, Pablo, Pascal Jungblut, Paul Brit, Pawel Palenica, Paweł Rozlach, Peter Badida, Peter Dave Hello, Peter Hoeg, Peter Marquardt, Phani Rithvij, Phil Davis, Philippe Schommers, Phill Luby, Pier Paolo Ramon, Piotr Bejda, Pramodh KP, Quentin Hibon, Rahmi Pruitt, Richard Hartmann, Robert Carosi, Roberto Santalla, Robin Schoonover, Roman Zaynetdinov, Ross Smith II, Ruslan Yevdokymov, Ryan Sullivan, Sacheendra Talluri, Scott Klupfel, Sergey Mishin, Shaarad Dalvi, Simon Frei, Simon Mwepu, Sly_tom_cat, Stefan Kuntz, Stefan Tatschner, Steven Eckhoff, Suhas Gundimeda, Syncthing Release Automation, Taylor Khan, Thomas Hipp, Tim Abell, Tim Howes, Tobias Klauser, Tobias Nygren, Tobias Tom, Tom Jakubowski, Tomasz Wilczyński, Tommy Thorn, Tully Robinson, Tyler Brazier, Tyler Kropp, Unrud, Veeti Paananen, Victor Buinsky, Vil Brekin, Vladimir Rusinov, William A. Kennington III, Wulf Weich, Xavier O., Yannic A., andresvia, andyleap, boomsquared, bt90, chenrui, chucic, deepsource-autofix[bot], dependabot-preview[bot], dependabot[bot], derekriemer, desbma, georgespatton, ghjklw, greatroar, janost, jaseg, jelle van der Waa, jtagcat, klemens, marco-m, mclang, mv1005, otbutz, overkill, perewa, rubenbe, wangguoliang, wouter bolsterlee, xarx00, xjtdy888, 佛跳墙
|
||||
Jakob Borg, Audrius Butkevicius, Jesse Lucas, Simon Frei, Alexander Graf, Alexandre Viau, Anderson Mesquita, André Colomb, Antony Male, Ben Schulz, Caleb Callaway, Daniel Harte, Evgeny Kuznetsov, Lars K.W. Gohlke, Lode Hoste, Michael Ploujnikov, Nate Morrison, Philippe Schommers, Ryan Sullivan, Sergey Mishin, Stefan Tatschner, Syncthing Release Automation, Tomasz Wilczyński, Wulf Weich, dependabot-preview[bot], dependabot[bot], greatroar, Aaron Bieber, Adam Piggott, Adel Qalieh, Alan Pope, Alberto Donato, Alessandro G., Alex Lindeman, Alex Xu, Aman Gupta, Andrew Dunham, Andrew Meyer, Andrew Rabert, Andrey D, Anjan Momi, Antoine Lamielle, Anur, Aranjedeath, Arkadiusz Tymiński, Arthur Axel fREW Schmidt, Artur Zubilewicz, Aurélien Rainone, BAHADIR YILMAZ, Bart De Vries, Ben Curthoys, Ben Shepherd, Ben Sidhom, Benedikt Heine, Benedikt Morbach, Benjamin Nater, Benno Fünfstück, Benny Ng, Boqin Qin, Boris Rybalkin, Brandon Philips, Brendan Long, Brian R. Becker, Carsten Hagemann, Cathryne Linenweaver, Cedric Staniewski, Chih-Hsuan Yen, Choongkyu, Chris Howie, Chris Joel, Chris Tonkinson, Christian Prescott, Colin Kennedy, Cromefire_, Cyprien Devillez, Dale Visser, Dan, Daniel Barczyk, Daniel Bergmann, Daniel Martí, Darshil Chanpura, David Rimmer, Denis A., Dennis Wilson, Dmitry Saveliev, Domenic Horner, Dominik Heidler, Elias Jarlebring, Elliot Huffman, Emil Hessman, Eng Zer Jun, Eric Lesiuta, Erik Meitner, Federico Castagnini, Felix Ableitner, Felix Lampe, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gahl Saraf, Gilli Sigurdsson, Gleb Sinyavskiy, Graham Miln, Greg, Han Boetes, HansK-p, Harrison Jones, Heiko Zuerker, Hugo Locurcio, Iain Barnett, Ian Johnson, Ikko Ashimine, Ilya Brin, Iskander Sharipov, Jaakko Hannikainen, Jacek Szafarkiewicz, Jack Croft, Jacob, Jake Peterson, James Patterson, Jaroslav Lichtblau, Jaroslav Malec, Jaya Chithra, Jeffery To, Jens Diemer, Jerry Jacobs, Jochen Voss, Johan Andersson, Johan Vromans, John Rinehart, Jonas Thelemann, Jonathan, Jonathan Cross, Jonta, Jose Manuel Delicado, Jörg Thalheim, Jędrzej Kula, Kalle Laine, Karol Różycki, Kebin Liu, Keith Turner, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Kevin Bushiri, Kevin White, Jr., Kurt Fitzner, Lars Lehtonen, Laurent Arnoud, Laurent Etiemble, Leo Arias, Liu Siyuan, Lord Landon Agahnim, Lukas Lihotzki, Majed Abdulaziz, Marc Laporte, Marc Pujol, Marcin Dziadus, Marcus Legendre, Mario Majila, Mark Pulford, Mateusz Naściszewski, Mateusz Ż, Matic Potočnik, Matt Burke, Matt Robenolt, Matteo Ruina, Maurizio Tomasi, Max, Max Schulze, MaximAL, Maxime Thirouin, MichaIng, Michael Jephcote, Michael Rienstra, Michael Tilli, Mike Boone, MikeLund, MikolajTwarog, Mingxuan Lin, Naveen, Nicholas Rishel, Nico Stapelbroek, Nicolas Braud-Santoni, Nicolas Perraut, Niels Peter Roest, Nils Jakobi, NinoM4ster, Nitroretro, NoLooseEnds, Oliver Freyermuth, Otiel, Oyebanji Jacob Mayowa, Pablo, Pascal Jungblut, Paul Brit, Pawel Palenica, Paweł Rozlach, Peter Badida, Peter Dave Hello, Peter Hoeg, Peter Marquardt, Phani Rithvij, Phil Davis, Phill Luby, Pier Paolo Ramon, Piotr Bejda, Pramodh KP, Quentin Hibon, Rahmi Pruitt, Richard Hartmann, Robert Carosi, Roberto Santalla, Robin Schoonover, Roman Zaynetdinov, Ross Smith II, Ruslan Yevdokymov, Ryan Qian, Sacheendra Talluri, Scott Klupfel, Shaarad Dalvi, Simon Mwepu, Sly_tom_cat, Stefan Kuntz, Steven Eckhoff, Suhas Gundimeda, Syncthing Automation, Taylor Khan, Thomas Hipp, Tim Abell, Tim Howes, Tobias Klauser, Tobias Nygren, Tobias Tom, Tom Jakubowski, Tommy Thorn, Tully Robinson, Tyler Brazier, Tyler Kropp, Unrud, Veeti Paananen, Victor Buinsky, Vil Brekin, Vladimir Rusinov, William A. Kennington III, Xavier O., Yannic A., andresvia, andyleap, boomsquared, bt90, chenrui, chucic, deepsource-autofix[bot], derekriemer, desbma, georgespatton, ghjklw, ignacy123, janost, jaseg, jelle van der Waa, jtagcat, klemens, marco-m, mclang, mv1005, otbutz, overkill, perewa, red_led, rubenbe, villekalliomaki, wangguoliang, wouter bolsterlee, xarx00, xjtdy888, 佛跳墙
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<div class="col-md-6 checkbox">
|
||||
<label for="sharedwith-{{id}}">
|
||||
<input id="sharedwith-{{id}}" ng-model="selected[id]" type="checkbox" />
|
||||
<span tooltip data-original-title="{{id}}">{{label}}</span>
|
||||
<span tooltip data-original-title="{{id}}" ng-bind-html="label"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon" ng-switch="folderType !== 'receiveencrypted' && !encryptionPasswords[id]">
|
||||
<span ng-switch-when='true' class="fas fa-fw fa-unlock" />
|
||||
<span ng-switch-default class="fas fa-fw fa-lock" />
|
||||
<span ng-switch-when='true' class="fas fa-fw fa-unlock"></span>
|
||||
<span ng-switch-default class="fas fa-fw fa-lock"></span>
|
||||
</span>
|
||||
<span ng-switch="folderType === 'receiveencrypted'">
|
||||
<span ng-switch-when='true'>
|
||||
@@ -30,10 +30,10 @@
|
||||
</span>
|
||||
<span ng-switch="selected[id] && folderType !== 'receiveencrypted'" class="input-group-addon">
|
||||
<span ng-switch-when='true'>
|
||||
<span class="button fas fa-fw fa-eye" ng-click="togglePasswordVisibility()" />
|
||||
<span class="button fas fa-fw fa-eye" ng-click="togglePasswordVisibility()"></span>
|
||||
</span>
|
||||
<span ng-switch-default>
|
||||
<span class="button fas fa-fw fa-eye" disabled />
|
||||
<span class="button fas fa-fw fa-eye" disabled></span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -64,19 +64,27 @@ angular.module('syncthing.core')
|
||||
PENDING_DEVICES_CHANGED: 'PendingDevicesChanged', // Emitted when pending devices were added / updated (connection from unknown ID) or removed (device is ignored or added)
|
||||
DEVICE_PAUSED: 'DevicePaused', // Emitted when a device has been paused
|
||||
DEVICE_RESUMED: 'DeviceResumed', // Emitted when a device has been resumed
|
||||
CLUSTER_CONFIG_RECEIVED: 'ClusterConfigReceived', // Emitted when receiving a remote device's cluster config
|
||||
DOWNLOAD_PROGRESS: 'DownloadProgress', // Emitted during file downloads for each folder for each file
|
||||
FAILURE: 'Failure', // Specific errors sent to the usage reporting server for diagnosis
|
||||
FOLDER_COMPLETION: 'FolderCompletion', //Emitted when the local or remote contents for a folder changes
|
||||
FOLDER_REJECTED: 'FolderRejected', // DEPRECATED: Emitted when a device sends index information for a folder we do not have, or have but do not share with the device in question
|
||||
PENDING_FOLDERS_CHANGED: 'PendingFoldersChanged', // Emitted when pending folders were added / updated (offered by some device, but not shared to them) or removed (folder ignored or added or no longer offered from the remote device)
|
||||
FOLDER_SUMMARY: 'FolderSummary', // Emitted when folder contents have changed locally
|
||||
ITEM_FINISHED: 'ItemFinished', // Generated when Syncthing ends synchronizing a file to a newer version
|
||||
ITEM_STARTED: 'ItemStarted', // Generated when Syncthing begins synchronizing a file to a newer version
|
||||
LISTEN_ADDRESSES_CHANGED: 'ListenAddressesChanged', // Listen address resolution has changed.
|
||||
LOCAL_CHANGE_DETECTED: 'LocalChangeDetected', // Generated upon scan whenever the local disk has discovered an updated file from the previous scan.
|
||||
LOCAL_INDEX_UPDATED: 'LocalIndexUpdated', // Generated when the local index information has changed, due to synchronizing one or more items from the cluster or discovering local changes during a scan
|
||||
LOGIN_ATTEMPT: 'LoginAttempt', // Emitted on every login attempt when authentication is enabled for the GUI.
|
||||
REMOTE_CHANGE_DETECTED: 'RemoteChangeDetected', // Generated upon scan whenever a file is locally updated due to a remote change.
|
||||
REMOTE_DOWNLOAD_PROGRESS: 'RemoteDownloadProgress', // DownloadProgress message received from a connected remote device.
|
||||
REMOTE_INDEX_UPDATED: 'RemoteIndexUpdated', // Generated each time new index information is received from a device
|
||||
STARTING: 'Starting', // Emitted exactly once, when Syncthing starts, before parsing configuration etc
|
||||
STARTUP_COMPLETED: 'StartupCompleted', // Emitted exactly once, when initialization is complete and Syncthing is ready to start exchanging data with other devices
|
||||
STATE_CHANGED: 'StateChanged', // Emitted when a folder changes state
|
||||
FOLDER_ERRORS: 'FolderErrors', // Emitted when a folder has errors preventing a full sync
|
||||
FOLDER_WATCH_STATE_CHANGED: 'FolderWatchStateChanged', // Watcher routine encountered a new error, or a previous error disappeared after retrying.
|
||||
FOLDER_SCAN_PROGRESS: 'FolderScanProgress', // Emitted every ScanProgressIntervalS seconds, indicating how far into the scan it is at.
|
||||
FOLDER_PAUSED: 'FolderPaused', // Emitted when a folder is paused
|
||||
FOLDER_RESUMED: 'FolderResumed', // Emitted when a folder is resumed
|
||||
|
||||
@@ -178,7 +178,8 @@ angular.module('syncthing.core')
|
||||
|
||||
console.log('HTTPError', arg);
|
||||
online = false;
|
||||
if (!restarting) {
|
||||
// We sometimes get arg == null from angularjs - no idea why
|
||||
if (!restarting && arg) {
|
||||
if (arg.status === 0) {
|
||||
// A network error, not an HTTP error
|
||||
$scope.$emit(Events.OFFLINE);
|
||||
@@ -2365,17 +2366,37 @@ angular.module('syncthing.core')
|
||||
+ '&device=' + encodeURIComponent(deviceID));
|
||||
};
|
||||
|
||||
$scope.deviceNameMarkUnaccepted = function (deviceID, folderID) {
|
||||
var name = $scope.deviceName($scope.devices[deviceID]);
|
||||
// Add footnote if sharing was not accepted on the remote device
|
||||
if (deviceID in $scope.completion && folderID in $scope.completion[deviceID] && $scope.completion[deviceID][folderID].remoteState == 'notSharing') {
|
||||
name += '<sup>1</sup>';
|
||||
}
|
||||
return name;
|
||||
};
|
||||
|
||||
$scope.sharesFolder = function (folderCfg) {
|
||||
var names = [];
|
||||
folderCfg.devices.forEach(function (device) {
|
||||
if (device.deviceID !== $scope.myID) {
|
||||
names.push($scope.deviceName($scope.devices[device.deviceID]));
|
||||
names.push($scope.deviceNameMarkUnaccepted(device.deviceID, folderCfg.id));
|
||||
}
|
||||
});
|
||||
names.sort();
|
||||
return names.join(", ");
|
||||
};
|
||||
|
||||
$scope.folderHasUnacceptedDevices = function (folderCfg) {
|
||||
for (var deviceID in $scope.completion) {
|
||||
if (deviceID in $scope.devices
|
||||
&& folderCfg.id in $scope.completion[deviceID]
|
||||
&& $scope.completion[deviceID][folderCfg.id].remoteState == 'notSharing') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
$scope.deviceFolders = function (deviceCfg) {
|
||||
var folders = [];
|
||||
$scope.folderList().forEach(function (folder) {
|
||||
@@ -2397,6 +2418,36 @@ angular.module('syncthing.core')
|
||||
return label && label.length > 0 ? label : folderID;
|
||||
};
|
||||
|
||||
$scope.folderLabelMarkUnaccepted = function (folderID, deviceID) {
|
||||
var label = $scope.folderLabel(folderID);
|
||||
// Add footnote if sharing was not accepted on the remote device
|
||||
if (deviceID in $scope.completion && folderID in $scope.completion[deviceID] && $scope.completion[deviceID][folderID].remoteState == 'notSharing') {
|
||||
label += '<sup>1</sup>';
|
||||
}
|
||||
return label;
|
||||
};
|
||||
|
||||
$scope.sharedFolders = function (deviceCfg) {
|
||||
var labels = [];
|
||||
$scope.deviceFolders(deviceCfg).forEach(function (folderID) {
|
||||
labels.push($scope.folderLabelMarkUnaccepted(folderID, deviceCfg.deviceID));
|
||||
});
|
||||
return labels.join(', ');
|
||||
};
|
||||
|
||||
$scope.deviceHasUnacceptedFolders = function (deviceCfg) {
|
||||
if (!(deviceCfg.deviceID in $scope.completion)) {
|
||||
return false;
|
||||
}
|
||||
for (var folderID in $scope.completion[deviceCfg.deviceID]) {
|
||||
if (folderID in $scope.folders
|
||||
&& $scope.completion[deviceCfg.deviceID][folderID].remoteState == 'notSharing') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
$scope.deleteFolder = function (id) {
|
||||
hideFolderModal();
|
||||
if ($scope.currentFolder._editing != "existing") {
|
||||
@@ -2624,6 +2675,8 @@ angular.module('syncthing.core')
|
||||
maxDate: maxDate,
|
||||
ranges: ranges,
|
||||
locale: {
|
||||
applyLabel: $translate.instant("Apply"),
|
||||
cancelLabel: $translate.instant("Cancel"),
|
||||
customRangeLabel: $translate.instant("Custom Range"),
|
||||
format: 'YYYY/MM/DD HH:mm:ss',
|
||||
}
|
||||
@@ -2921,16 +2974,18 @@ angular.module('syncthing.core')
|
||||
|
||||
$scope.docsURL = function (path) {
|
||||
var url = 'https://docs.syncthing.net';
|
||||
if (path) {
|
||||
var hash = path.indexOf('#');
|
||||
if (hash != -1) {
|
||||
url += '/' + path.slice(0, hash);
|
||||
url += '?version=' + $scope.versionBase();
|
||||
url += path.slice(hash);
|
||||
} else {
|
||||
url += '/' + path;
|
||||
url += '?version=' + $scope.versionBase();
|
||||
}
|
||||
if (!path) {
|
||||
// Undefined or null should become a valid string.
|
||||
path = '';
|
||||
}
|
||||
var hash = path.indexOf('#');
|
||||
if (hash != -1) {
|
||||
url += '/' + path.slice(0, hash);
|
||||
url += '?version=' + $scope.versionBase();
|
||||
url += path.slice(hash);
|
||||
} else {
|
||||
url += '/' + path;
|
||||
url += '?version=' + $scope.versionBase();
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
@@ -83,8 +83,11 @@
|
||||
<a href="#" ng-click="selectAllSharedFolders(false)" translate>Deselect All</a></small>
|
||||
</p>
|
||||
<div class="form-group" ng-repeat="folder in currentSharing.shared">
|
||||
<share-template selected="currentSharing.selected" encryption-passwords="currentSharing.encryptionPasswords" id="{{folder.id}}" label="{{folderLabel(folder.id)}}" folder-type="{{folder.type}}" untrusted="currentDevice.untrusted" />
|
||||
<share-template selected="currentSharing.selected" encryption-passwords="currentSharing.encryptionPasswords" id="{{folder.id}}" label="{{folderLabelMarkUnaccepted(folder.id, currentDevice.deviceID)}}" folder-type="{{folder.type}}" untrusted="currentDevice.untrusted" />
|
||||
</div>
|
||||
<p class="help-block" ng-if="deviceHasUnacceptedFolders(currentDevice)">
|
||||
<sup>1</sup> <span translate>The remote device has not accepted sharing this folder.</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="form-horizontal" ng-if="currentSharing.unrelated.length">
|
||||
<label translate for="folders">Unshared Folders</label>
|
||||
|
||||
@@ -56,8 +56,11 @@
|
||||
<a href="#" ng-click="selectAllSharedDevices(false)" translate>Deselect All</a></small>
|
||||
</p>
|
||||
<div class="form-group" ng-repeat="device in currentSharing.shared">
|
||||
<share-template selected="currentSharing.selected" encryption-passwords="currentSharing.encryptionPasswords" id="{{device.deviceID}}" label="{{deviceName(device)}}" folder-type="{{currentFolder.type}}" untrusted="device.untrusted || pendingIsRemoteEncrypted(currentFolder.id, device.deviceID)" />
|
||||
<share-template selected="currentSharing.selected" encryption-passwords="currentSharing.encryptionPasswords" id="{{device.deviceID}}" label="{{deviceNameMarkUnaccepted(device.deviceID, currentFolder.id)}}" folder-type="{{currentFolder.type}}" untrusted="device.untrusted || pendingIsRemoteEncrypted(currentFolder.id, device.deviceID)" />
|
||||
</div>
|
||||
<p class="help-block" ng-if="folderHasUnacceptedDevices(currentFolder)">
|
||||
<sup>1</sup> <span translate>The remote device has not accepted sharing this folder.</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="form-horizontal" ng-if="currentSharing.unrelated.length || otherDevices().length <= 0">
|
||||
<label translate>Unshared Devices</label>
|
||||
|
||||
@@ -59,6 +59,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// Default mask excludes these very noisy event types to avoid filling the pipe.
|
||||
// FIXME: ItemStarted and ItemFinished should be excluded for the same reason.
|
||||
DefaultEventMask = events.AllEvents &^ events.LocalChangeDetected &^ events.RemoteChangeDetected
|
||||
DiskEventMask = events.LocalChangeDetected | events.RemoteChangeDetected
|
||||
EventSubBufferSize = 1000
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/locations"
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
loggermocks "github.com/syncthing/syncthing/lib/logger/mocks"
|
||||
"github.com/syncthing/syncthing/lib/model"
|
||||
modelmocks "github.com/syncthing/syncthing/lib/model/mocks"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
@@ -260,7 +261,7 @@ func TestAPIServiceRequests(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer cancel()
|
||||
t.Cleanup(cancel)
|
||||
|
||||
cases := []httpTestCase{
|
||||
// /rest/db
|
||||
@@ -298,6 +299,12 @@ func TestAPIServiceRequests(t *testing.T) {
|
||||
Type: "application/json",
|
||||
Prefix: "null",
|
||||
},
|
||||
{
|
||||
URL: "/rest/db/status?folder=default",
|
||||
Code: 200,
|
||||
Type: "application/json",
|
||||
Prefix: "",
|
||||
},
|
||||
|
||||
// /rest/stats
|
||||
{
|
||||
@@ -466,14 +473,17 @@ func TestAPIServiceRequests(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Log("Testing", tc.URL, "...")
|
||||
testHTTPRequest(t, baseURL, tc, testAPIKey)
|
||||
t.Run(cases[0].URL, func(t *testing.T) {
|
||||
testHTTPRequest(t, baseURL, tc, testAPIKey)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// testHTTPRequest tries the given test case, comparing the result code,
|
||||
// content type, and result prefix.
|
||||
func testHTTPRequest(t *testing.T, baseURL string, tc httpTestCase, apikey string) {
|
||||
// Should not be parallelized, as that just causes timeouts eventually with more test-cases
|
||||
|
||||
timeout := time.Second
|
||||
if tc.Timeout > 0 {
|
||||
timeout = tc.Timeout
|
||||
@@ -608,7 +618,7 @@ func startHTTP(cfg config.Wrapper) (string, context.CancelFunc, error) {
|
||||
}
|
||||
addrChan := make(chan string)
|
||||
mockedSummary := &modelmocks.FolderSummaryService{}
|
||||
mockedSummary.SummaryReturns(map[string]interface{}{"mocked": true}, nil)
|
||||
mockedSummary.SummaryReturns(new(model.FolderSummary), nil)
|
||||
|
||||
// Instantiate the API service
|
||||
urService := ur.New(cfg, m, connections, false)
|
||||
@@ -1136,11 +1146,7 @@ func TestBrowse(t *testing.T) {
|
||||
|
||||
pathSep := string(os.PathSeparator)
|
||||
|
||||
tmpDir, err := os.MkdirTemp("", "syncthing")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
if err := os.Mkdir(filepath.Join(tmpDir, "dir"), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -457,7 +457,7 @@ func TestIssue1262(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
actual := cfg.Folders()["test"].Filesystem().URI()
|
||||
actual := cfg.Folders()["test"].Filesystem(nil).URI()
|
||||
expected := `e:\`
|
||||
|
||||
if actual != expected {
|
||||
@@ -494,7 +494,7 @@ func TestFolderPath(t *testing.T) {
|
||||
Path: "~/tmp",
|
||||
}
|
||||
|
||||
realPath := folder.Filesystem().URI()
|
||||
realPath := folder.Filesystem(nil).URI()
|
||||
if !filepath.IsAbs(realPath) {
|
||||
t.Error(realPath, "should be absolute")
|
||||
}
|
||||
@@ -504,13 +504,10 @@ func TestFolderPath(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFolderCheckPath(t *testing.T) {
|
||||
n, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
n := t.TempDir()
|
||||
testFs := fs.NewFilesystem(fs.FilesystemTypeBasic, n)
|
||||
|
||||
err = os.MkdirAll(filepath.Join(n, "dir", ".stfolder"), os.FileMode(0777))
|
||||
err := os.MkdirAll(filepath.Join(n, "dir", ".stfolder"), os.FileMode(0777))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -602,11 +599,7 @@ func TestWindowsLineEndings(t *testing.T) {
|
||||
t.Skip("Windows specific")
|
||||
}
|
||||
|
||||
dir, err := os.MkdirTemp("", "syncthing-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
dir := t.TempDir()
|
||||
|
||||
path := filepath.Join(dir, "config.xml")
|
||||
os.Remove(path)
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/db"
|
||||
"github.com/syncthing/syncthing/lib/fs"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
@@ -42,24 +43,29 @@ func (f FolderConfiguration) Copy() FolderConfiguration {
|
||||
return c
|
||||
}
|
||||
|
||||
func (f FolderConfiguration) Filesystem() fs.Filesystem {
|
||||
// Filesystem creates a filesystem for the path and options of this folder.
|
||||
// The fset parameter may be nil, in which case no mtime handling on top of
|
||||
// the fileystem is provided.
|
||||
func (f FolderConfiguration) Filesystem(fset *db.FileSet) fs.Filesystem {
|
||||
// This is intentionally not a pointer method, because things like
|
||||
// cfg.Folders["default"].Filesystem() should be valid.
|
||||
var opts []fs.Option
|
||||
// cfg.Folders["default"].Filesystem(nil) should be valid.
|
||||
opts := make([]fs.Option, 0, 3)
|
||||
if f.FilesystemType == fs.FilesystemTypeBasic && f.JunctionsAsDirs {
|
||||
opts = append(opts, new(fs.OptionJunctionsAsDirs))
|
||||
}
|
||||
filesystem := fs.NewFilesystem(f.FilesystemType, f.Path, opts...)
|
||||
if !f.CaseSensitiveFS {
|
||||
filesystem = fs.NewCaseFilesystem(filesystem)
|
||||
opts = append(opts, new(fs.OptionDetectCaseConflicts))
|
||||
}
|
||||
return filesystem
|
||||
if fset != nil {
|
||||
opts = append(opts, fset.MtimeOption())
|
||||
}
|
||||
return fs.NewFilesystem(f.FilesystemType, f.Path, opts...)
|
||||
}
|
||||
|
||||
func (f FolderConfiguration) ModTimeWindow() time.Duration {
|
||||
dur := time.Duration(f.RawModTimeWindowS) * time.Second
|
||||
if f.RawModTimeWindowS < 1 && runtime.GOOS == "android" {
|
||||
if usage, err := disk.Usage(f.Filesystem().URI()); err != nil {
|
||||
if usage, err := disk.Usage(f.Filesystem(nil).URI()); err != nil {
|
||||
dur = 2 * time.Second
|
||||
l.Debugf(`Detecting FS at "%v" on android: Setting mtime window to 2s: err == "%v"`, f.Path, err)
|
||||
} else if strings.HasPrefix(strings.ToLower(usage.Fstype), "ext2") || strings.HasPrefix(strings.ToLower(usage.Fstype), "ext3") || strings.HasPrefix(strings.ToLower(usage.Fstype), "ext4") {
|
||||
@@ -89,7 +95,7 @@ func (f *FolderConfiguration) CreateMarker() error {
|
||||
// begin with.
|
||||
permBits = 0700
|
||||
}
|
||||
fs := f.Filesystem()
|
||||
fs := f.Filesystem(nil)
|
||||
err := fs.Mkdir(DefaultMarkerName, permBits)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -106,7 +112,7 @@ func (f *FolderConfiguration) CreateMarker() error {
|
||||
|
||||
// CheckPath returns nil if the folder root exists and contains the marker file
|
||||
func (f *FolderConfiguration) CheckPath() error {
|
||||
fi, err := f.Filesystem().Stat(".")
|
||||
fi, err := f.Filesystem(nil).Stat(".")
|
||||
if err != nil {
|
||||
if !fs.IsNotExist(err) {
|
||||
return err
|
||||
@@ -124,7 +130,7 @@ func (f *FolderConfiguration) CheckPath() error {
|
||||
return ErrPathNotDirectory
|
||||
}
|
||||
|
||||
_, err = f.Filesystem().Stat(f.MarkerName)
|
||||
_, err = f.Filesystem(nil).Stat(f.MarkerName)
|
||||
if err != nil {
|
||||
if !fs.IsNotExist(err) {
|
||||
return err
|
||||
@@ -145,7 +151,7 @@ func (f *FolderConfiguration) CreateRoot() (err error) {
|
||||
permBits = 0700
|
||||
}
|
||||
|
||||
filesystem := f.Filesystem()
|
||||
filesystem := f.Filesystem(nil)
|
||||
|
||||
if _, err = filesystem.Stat("."); fs.IsNotExist(err) {
|
||||
err = filesystem.MkdirAll(".", permBits)
|
||||
@@ -256,13 +262,13 @@ func (f *FolderConfiguration) CheckAvailableSpace(req uint64) error {
|
||||
if val <= 0 {
|
||||
return nil
|
||||
}
|
||||
fs := f.Filesystem()
|
||||
fs := f.Filesystem(nil)
|
||||
usage, err := fs.Usage(".")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if !checkAvailableSpace(req, f.MinDiskFree, usage) {
|
||||
return fmt.Errorf("insufficient space in %v %v", fs.Type(), fs.URI())
|
||||
if err := checkAvailableSpace(req, f.MinDiskFree, usage); err != nil {
|
||||
return fmt.Errorf("insufficient space in folder %v (%v): %w", f.Description(), fs.URI(), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ func migrateToConfigV23(cfg *Configuration) {
|
||||
// marker name in later versions.
|
||||
|
||||
for i := range cfg.Folders {
|
||||
fs := cfg.Folders[i].Filesystem()
|
||||
fs := cfg.Folders[i].Filesystem(nil)
|
||||
// Invalid config posted, or tests.
|
||||
if fs == nil {
|
||||
continue
|
||||
@@ -235,18 +235,18 @@ func migrateToConfigV21(cfg *Configuration) {
|
||||
switch folder.Versioning.Type {
|
||||
case "simple", "trashcan":
|
||||
// Clean out symlinks in the known place
|
||||
cleanSymlinks(folder.Filesystem(), ".stversions")
|
||||
cleanSymlinks(folder.Filesystem(nil), ".stversions")
|
||||
case "staggered":
|
||||
versionDir := folder.Versioning.Params["versionsPath"]
|
||||
if versionDir == "" {
|
||||
// default place
|
||||
cleanSymlinks(folder.Filesystem(), ".stversions")
|
||||
cleanSymlinks(folder.Filesystem(nil), ".stversions")
|
||||
} else if filepath.IsAbs(versionDir) {
|
||||
// absolute
|
||||
cleanSymlinks(fs.NewFilesystem(fs.FilesystemTypeBasic, versionDir), ".")
|
||||
} else {
|
||||
// relative to folder
|
||||
cleanSymlinks(folder.Filesystem(), versionDir)
|
||||
cleanSymlinks(folder.Filesystem(nil), versionDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,10 +83,10 @@ func CheckFreeSpace(minFree Size, usage fs.Usage) error {
|
||||
if minFree.Percentage() {
|
||||
freePct := (float64(usage.Free) / float64(usage.Total)) * 100
|
||||
if freePct < val {
|
||||
return fmt.Errorf("%.1f %% < %v", freePct, minFree)
|
||||
return fmt.Errorf("current %.2f %% < required %v", freePct, minFree)
|
||||
}
|
||||
} else if float64(usage.Free) < val {
|
||||
return fmt.Errorf("%sB < %v", formatSI(usage.Free), minFree)
|
||||
return fmt.Errorf("current %sB < required %v", formatSI(usage.Free), minFree)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -94,12 +94,12 @@ func CheckFreeSpace(minFree Size, usage fs.Usage) error {
|
||||
|
||||
// checkAvailableSpace checks that the free space does not fall below the minimum
|
||||
// required free space, considering additional required space for a future operation.
|
||||
func checkAvailableSpace(req uint64, minFree Size, usage fs.Usage) bool {
|
||||
func checkAvailableSpace(req uint64, minFree Size, usage fs.Usage) error {
|
||||
if usage.Free < req {
|
||||
return false
|
||||
return fmt.Errorf("current %sB < required %sB", formatSI(usage.Free), formatSI(req))
|
||||
}
|
||||
usage.Free -= req
|
||||
return CheckFreeSpace(minFree, usage) == nil
|
||||
return CheckFreeSpace(minFree, usage)
|
||||
}
|
||||
|
||||
func formatSI(b uint64) string {
|
||||
|
||||
@@ -159,8 +159,10 @@ func TestCheckAvailableSize(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
usage := fs.Usage{Free: tc.free, Total: tc.total}
|
||||
if ok := checkAvailableSpace(tc.req, minFree, usage); ok != tc.ok {
|
||||
t.Errorf("checkAvailableSpace(%v, %v, %v) == %v, expected %v", tc.req, minFree, usage, ok, tc.ok)
|
||||
err = checkAvailableSpace(tc.req, minFree, usage)
|
||||
t.Log(err)
|
||||
if (err == nil) != tc.ok {
|
||||
t.Errorf("checkAvailableSpace(%v, %v, %v) == %v, expected %v", tc.req, minFree, usage, err, tc.ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,12 @@
|
||||
package connections
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/url"
|
||||
@@ -21,6 +23,7 @@ import (
|
||||
"github.com/thejerf/suture/v4"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/connections/registry"
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/nat"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
@@ -294,7 +297,7 @@ func TestNextDialRegistryCleanup(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConnections(pb *testing.B) {
|
||||
func BenchmarkConnections(b *testing.B) {
|
||||
addrs := []string{
|
||||
"tcp://127.0.0.1:0",
|
||||
"quic://127.0.0.1:0",
|
||||
@@ -315,9 +318,13 @@ func BenchmarkConnections(pb *testing.B) {
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
for _, sz := range sizes {
|
||||
data := make([]byte, sz)
|
||||
if _, err := rand.Read(data); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
for _, direction := range []string{"cs", "sc"} {
|
||||
proto := strings.SplitN(addr, ":", 2)[0]
|
||||
pb.Run(fmt.Sprintf("%s_%d_%s", proto, sz, direction), func(b *testing.B) {
|
||||
b.Run(fmt.Sprintf("%s_%d_%s", proto, sz, direction), func(b *testing.B) {
|
||||
if proto == "relay" && !haveRelay {
|
||||
b.Skip("could not connect to relay")
|
||||
}
|
||||
@@ -325,61 +332,79 @@ func BenchmarkConnections(pb *testing.B) {
|
||||
if direction == "sc" {
|
||||
server, client = client, server
|
||||
}
|
||||
data := make([]byte, sz)
|
||||
if _, err := rand.Read(data); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
total := 0
|
||||
wg := sync.NewWaitGroup()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
wg := sync.NewWaitGroup()
|
||||
wg.Add(2)
|
||||
errC := make(chan error, 2)
|
||||
go func() {
|
||||
if err := sendMsg(client, data); err != nil {
|
||||
b.Fatal(err)
|
||||
if _, err := client.Write(data); err != nil {
|
||||
errC <- err
|
||||
return
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
go func() {
|
||||
if err := recvMsg(server, data); err != nil {
|
||||
b.Fatal(err)
|
||||
if _, err := io.ReadFull(server, data); err != nil {
|
||||
errC <- err
|
||||
return
|
||||
}
|
||||
total += sz
|
||||
wg.Done()
|
||||
}()
|
||||
wg.Wait()
|
||||
close(errC)
|
||||
err := <-errC
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(total / b.N))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sendMsg(c internalConn, buf []byte) error {
|
||||
n, err := c.Write(buf)
|
||||
if n != len(buf) || err != nil {
|
||||
return err
|
||||
func TestConnectionEstablishment(t *testing.T) {
|
||||
addrs := []string{
|
||||
"tcp://127.0.0.1:0",
|
||||
"quic://127.0.0.1:0",
|
||||
}
|
||||
|
||||
send := make([]byte, 128<<10)
|
||||
if _, err := rand.Read(send); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
proto := strings.SplitN(addr, ":", 2)[0]
|
||||
|
||||
t.Run(proto, func(t *testing.T) {
|
||||
withConnectionPair(t, addr, func(client, server internalConn) {
|
||||
if _, err := client.Write(send); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
recv := make([]byte, len(send))
|
||||
if _, err := io.ReadFull(server, recv); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(recv, send) {
|
||||
t.Fatal("data mismatch")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func recvMsg(c internalConn, buf []byte) error {
|
||||
for read := 0; read != len(buf); {
|
||||
n, err := c.Read(buf)
|
||||
read += n
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func withConnectionPair(b *testing.B, connUri string, h func(client, server internalConn)) {
|
||||
func withConnectionPair(b interface{ Fatal(...interface{}) }, connUri string, h func(client, server internalConn)) {
|
||||
// Root of the service tree.
|
||||
supervisor := suture.New("main", suture.Spec{
|
||||
PassThroughPanics: true,
|
||||
@@ -414,7 +439,7 @@ func withConnectionPair(b *testing.B, connUri string, h func(client, server inte
|
||||
}
|
||||
natSvc := nat.NewService(deviceId, wcfg)
|
||||
conns := make(chan internalConn, 1)
|
||||
listenSvc := lf.New(uri, wcfg, tlsCfg, conns, natSvc)
|
||||
listenSvc := lf.New(uri, wcfg, tlsCfg, conns, natSvc, registry.New())
|
||||
supervisor.Add(listenSvc)
|
||||
|
||||
var addr *url.URL
|
||||
@@ -433,7 +458,8 @@ func withConnectionPair(b *testing.B, connUri string, h func(client, server inte
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
dialer := df.New(cfg.Options, tlsCfg)
|
||||
// Purposely using a different registry: Don't want to reuse port between dialer and listener on the same device
|
||||
dialer := df.New(cfg.Options, tlsCfg, registry.New())
|
||||
|
||||
// Relays might take some time to register the device, so dial multiple times
|
||||
clientConn, err := dialer.Dial(ctx, deviceId, addr)
|
||||
@@ -447,19 +473,22 @@ func withConnectionPair(b *testing.B, connUri string, h func(client, server inte
|
||||
}
|
||||
}
|
||||
|
||||
data := []byte("hello")
|
||||
|
||||
// Quic does not start a stream until some data is sent through, so send something for the AcceptStream
|
||||
// to fire on the other side.
|
||||
if err := sendMsg(clientConn, data); err != nil {
|
||||
send := []byte("hello")
|
||||
if _, err := clientConn.Write(send); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
serverConn := <-conns
|
||||
|
||||
if err := recvMsg(serverConn, data); err != nil {
|
||||
recv := make([]byte, len(send))
|
||||
if _, err := io.ReadFull(serverConn, recv); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(recv, send) {
|
||||
b.Fatal("data mismatch")
|
||||
}
|
||||
|
||||
h(clientConn, serverConn)
|
||||
|
||||
@@ -467,7 +496,7 @@ func withConnectionPair(b *testing.B, connUri string, h func(client, server inte
|
||||
_ = serverConn.Close()
|
||||
}
|
||||
|
||||
func mustGetCert(b *testing.B) tls.Certificate {
|
||||
func mustGetCert(b interface{ Fatal(...interface{}) }) tls.Certificate {
|
||||
cert, err := tlsutil.NewCertificateInMemory("bench", 10)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
|
||||
@@ -41,6 +41,7 @@ func init() {
|
||||
|
||||
type quicDialer struct {
|
||||
commonDialer
|
||||
registry *registry.Registry
|
||||
}
|
||||
|
||||
func (d *quicDialer) Dial(ctx context.Context, _ protocol.DeviceID, uri *url.URL) (internalConn, error) {
|
||||
@@ -58,7 +59,7 @@ func (d *quicDialer) Dial(ctx context.Context, _ protocol.DeviceID, uri *url.URL
|
||||
// Given we always pass the connection to quic, it assumes it's a remote connection it never closes it,
|
||||
// So our wrapper around it needs to close it, but it only needs to close it if it's not the listening connection.
|
||||
var createdConn net.PacketConn
|
||||
listenConn := registry.Get(uri.Scheme, packetConnUnspecified)
|
||||
listenConn := d.registry.Get(uri.Scheme, packetConnUnspecified)
|
||||
if listenConn != nil {
|
||||
conn = listenConn.(net.PacketConn)
|
||||
} else {
|
||||
@@ -96,7 +97,7 @@ func (d *quicDialer) Dial(ctx context.Context, _ protocol.DeviceID, uri *url.URL
|
||||
|
||||
type quicDialerFactory struct{}
|
||||
|
||||
func (quicDialerFactory) New(opts config.OptionsConfiguration, tlsCfg *tls.Config) genericDialer {
|
||||
func (quicDialerFactory) New(opts config.OptionsConfiguration, tlsCfg *tls.Config, registry *registry.Registry) genericDialer {
|
||||
// So the idea is that we should probably try dialing every 20 seconds.
|
||||
// However it would still be nice if this was adjustable/proportional to ReconnectIntervalS
|
||||
// But prevent something silly like 1/3 = 0 etc.
|
||||
@@ -104,10 +105,13 @@ func (quicDialerFactory) New(opts config.OptionsConfiguration, tlsCfg *tls.Confi
|
||||
if quicInterval < 10 {
|
||||
quicInterval = 10
|
||||
}
|
||||
return &quicDialer{commonDialer{
|
||||
reconnectInterval: time.Duration(quicInterval) * time.Second,
|
||||
tlsCfg: tlsCfg,
|
||||
}}
|
||||
return &quicDialer{
|
||||
commonDialer: commonDialer{
|
||||
reconnectInterval: time.Duration(quicInterval) * time.Second,
|
||||
tlsCfg: tlsCfg,
|
||||
},
|
||||
registry: registry,
|
||||
}
|
||||
}
|
||||
|
||||
func (quicDialerFactory) Priority() int {
|
||||
|
||||
@@ -40,11 +40,12 @@ type quicListener struct {
|
||||
|
||||
onAddressesChangedNotifier
|
||||
|
||||
uri *url.URL
|
||||
cfg config.Wrapper
|
||||
tlsCfg *tls.Config
|
||||
conns chan internalConn
|
||||
factory listenerFactory
|
||||
uri *url.URL
|
||||
cfg config.Wrapper
|
||||
tlsCfg *tls.Config
|
||||
conns chan internalConn
|
||||
factory listenerFactory
|
||||
registry *registry.Registry
|
||||
|
||||
address *url.URL
|
||||
laddr net.Addr
|
||||
@@ -100,8 +101,8 @@ func (t *quicListener) serve(ctx context.Context) error {
|
||||
|
||||
go svc.Serve(ctx)
|
||||
|
||||
registry.Register(t.uri.Scheme, conn)
|
||||
defer registry.Unregister(t.uri.Scheme, conn)
|
||||
t.registry.Register(t.uri.Scheme, conn)
|
||||
defer t.registry.Unregister(t.uri.Scheme, conn)
|
||||
|
||||
listener, err := quic.Listen(conn, t.tlsCfg, quicConfig)
|
||||
if err != nil {
|
||||
@@ -217,13 +218,14 @@ func (f *quicListenerFactory) Valid(config.Configuration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *quicListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service) genericListener {
|
||||
func (f *quicListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service, registry *registry.Registry) genericListener {
|
||||
l := &quicListener{
|
||||
uri: fixupPort(uri, config.DefaultQUICPort),
|
||||
cfg: cfg,
|
||||
tlsCfg: tlsCfg,
|
||||
conns: conns,
|
||||
factory: f,
|
||||
uri: fixupPort(uri, config.DefaultQUICPort),
|
||||
cfg: cfg,
|
||||
tlsCfg: tlsCfg,
|
||||
conns: conns,
|
||||
factory: f,
|
||||
registry: registry,
|
||||
}
|
||||
l.ServiceWithError = svcutil.AsService(l.serve, l.String())
|
||||
l.nat.Store(stun.NATUnknown)
|
||||
|
||||
@@ -36,7 +36,7 @@ func quicNetwork(uri *url.URL) string {
|
||||
}
|
||||
|
||||
type quicTlsConn struct {
|
||||
quic.Session
|
||||
quic.Connection
|
||||
quic.Stream
|
||||
// If we created this connection, we should be the ones closing it.
|
||||
createdConn net.PacketConn
|
||||
@@ -44,7 +44,7 @@ type quicTlsConn struct {
|
||||
|
||||
func (q *quicTlsConn) Close() error {
|
||||
sterr := q.Stream.Close()
|
||||
seerr := q.Session.CloseWithError(0, "closing")
|
||||
seerr := q.Connection.CloseWithError(0, "closing")
|
||||
var pcerr error
|
||||
if q.createdConn != nil {
|
||||
pcerr = q.createdConn.Close()
|
||||
@@ -59,7 +59,7 @@ func (q *quicTlsConn) Close() error {
|
||||
}
|
||||
|
||||
func (q *quicTlsConn) ConnectionState() tls.ConnectionState {
|
||||
return q.Session.ConnectionState().TLS.ConnectionState
|
||||
return q.Connection.ConnectionState().TLS.ConnectionState
|
||||
}
|
||||
|
||||
func packetConnUnspecified(conn interface{}) bool {
|
||||
|
||||
@@ -15,10 +15,6 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
)
|
||||
|
||||
var (
|
||||
Default = New()
|
||||
)
|
||||
|
||||
type Registry struct {
|
||||
mut sync.Mutex
|
||||
available map[string][]interface{}
|
||||
@@ -85,15 +81,3 @@ func (r *Registry) Get(scheme string, preferred func(interface{}) bool) interfac
|
||||
}
|
||||
return best
|
||||
}
|
||||
|
||||
func Register(scheme string, item interface{}) {
|
||||
Default.Register(scheme, item)
|
||||
}
|
||||
|
||||
func Unregister(scheme string, item interface{}) {
|
||||
Default.Unregister(scheme, item)
|
||||
}
|
||||
|
||||
func Get(scheme string, preferred func(interface{}) bool) interface{} {
|
||||
return Default.Get(scheme, preferred)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/connections/registry"
|
||||
"github.com/syncthing/syncthing/lib/dialer"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/relay/client"
|
||||
@@ -68,7 +69,7 @@ func (d *relayDialer) Dial(ctx context.Context, id protocol.DeviceID, uri *url.U
|
||||
|
||||
type relayDialerFactory struct{}
|
||||
|
||||
func (relayDialerFactory) New(opts config.OptionsConfiguration, tlsCfg *tls.Config) genericDialer {
|
||||
func (relayDialerFactory) New(opts config.OptionsConfiguration, tlsCfg *tls.Config, _ *registry.Registry) genericDialer {
|
||||
return &relayDialer{commonDialer{
|
||||
trafficClass: opts.TrafficClass,
|
||||
reconnectInterval: time.Duration(opts.RelayReconnectIntervalM) * time.Minute,
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/connections/registry"
|
||||
"github.com/syncthing/syncthing/lib/dialer"
|
||||
"github.com/syncthing/syncthing/lib/nat"
|
||||
"github.com/syncthing/syncthing/lib/relay/client"
|
||||
@@ -177,7 +178,7 @@ func (t *relayListener) NATType() string {
|
||||
|
||||
type relayListenerFactory struct{}
|
||||
|
||||
func (f *relayListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service) genericListener {
|
||||
func (f *relayListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service, _ *registry.Registry) genericListener {
|
||||
t := &relayListener{
|
||||
uri: uri,
|
||||
cfg: cfg,
|
||||
|
||||
@@ -12,6 +12,7 @@ package connections
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
@@ -22,6 +23,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/connections/registry"
|
||||
"github.com/syncthing/syncthing/lib/discover"
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/nat"
|
||||
@@ -55,6 +57,13 @@ var (
|
||||
errDisabled = fmt.Errorf("%w: disabled by configuration", errUnsupported)
|
||||
errDeprecated = fmt.Errorf("%w: deprecated", errUnsupported)
|
||||
errNotInBuild = fmt.Errorf("%w: disabled at build time", errUnsupported)
|
||||
|
||||
// Various reasons to reject a connection
|
||||
errNetworkNotAllowed = errors.New("network not allowed")
|
||||
errDeviceAlreadyConnected = errors.New("already connected to this device")
|
||||
errDeviceIgnored = errors.New("device is ignored")
|
||||
errConnLimitReached = errors.New("connection limit reached")
|
||||
errDevicePaused = errors.New("device is paused")
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -128,6 +137,14 @@ type ConnectionStatusEntry struct {
|
||||
Error *string `json:"error"`
|
||||
}
|
||||
|
||||
type connWithHello struct {
|
||||
c internalConn
|
||||
hello protocol.Hello
|
||||
err error
|
||||
remoteID protocol.DeviceID
|
||||
remoteCert *x509.Certificate
|
||||
}
|
||||
|
||||
type service struct {
|
||||
*suture.Supervisor
|
||||
connectionStatusHandler
|
||||
@@ -138,11 +155,13 @@ type service struct {
|
||||
tlsCfg *tls.Config
|
||||
discoverer discover.Finder
|
||||
conns chan internalConn
|
||||
hellos chan *connWithHello
|
||||
bepProtocolName string
|
||||
tlsDefaultCommonName string
|
||||
limiter *limiter
|
||||
natService *nat.Service
|
||||
evLogger events.Logger
|
||||
registry *registry.Registry
|
||||
|
||||
dialNow chan struct{}
|
||||
dialNowDevices map[protocol.DeviceID]struct{}
|
||||
@@ -153,7 +172,7 @@ type service struct {
|
||||
listenerTokens map[string]suture.ServiceToken
|
||||
}
|
||||
|
||||
func NewService(cfg config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *tls.Config, discoverer discover.Finder, bepProtocolName string, tlsDefaultCommonName string, evLogger events.Logger) Service {
|
||||
func NewService(cfg config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *tls.Config, discoverer discover.Finder, bepProtocolName string, tlsDefaultCommonName string, evLogger events.Logger, registry *registry.Registry) Service {
|
||||
spec := svcutil.SpecWithInfoLogger(l)
|
||||
service := &service{
|
||||
Supervisor: suture.New("connections.Service", spec),
|
||||
@@ -165,11 +184,13 @@ func NewService(cfg config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *t
|
||||
tlsCfg: tlsCfg,
|
||||
discoverer: discoverer,
|
||||
conns: make(chan internalConn),
|
||||
hellos: make(chan *connWithHello),
|
||||
bepProtocolName: bepProtocolName,
|
||||
tlsDefaultCommonName: tlsDefaultCommonName,
|
||||
limiter: newLimiter(myID, cfg),
|
||||
natService: nat.NewService(myID, cfg),
|
||||
evLogger: evLogger,
|
||||
registry: registry,
|
||||
|
||||
dialNowDevicesMut: sync.NewMutex(),
|
||||
dialNow: make(chan struct{}, 1),
|
||||
@@ -194,7 +215,8 @@ func NewService(cfg config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *t
|
||||
// incoming or outgoing.
|
||||
|
||||
service.Add(svcutil.AsService(service.connect, fmt.Sprintf("%s/connect", service)))
|
||||
service.Add(svcutil.AsService(service.handle, fmt.Sprintf("%s/handle", service)))
|
||||
service.Add(svcutil.AsService(service.handleConns, fmt.Sprintf("%s/handleConns", service)))
|
||||
service.Add(svcutil.AsService(service.handleHellos, fmt.Sprintf("%s/handleHellos", service)))
|
||||
service.Add(service.natService)
|
||||
|
||||
svcutil.OnSupervisorDone(service.Supervisor, func() {
|
||||
@@ -205,9 +227,9 @@ func NewService(cfg config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *t
|
||||
return service
|
||||
}
|
||||
|
||||
func (s *service) handle(ctx context.Context) error {
|
||||
var c internalConn
|
||||
func (s *service) handleConns(ctx context.Context) error {
|
||||
for {
|
||||
var c internalConn
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
@@ -245,8 +267,84 @@ func (s *service) handle(ctx context.Context) error {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := s.connectionCheckEarly(remoteID, c); err != nil {
|
||||
l.Infof("Connection from %s at %s (%s) rejected: %v", remoteID, c.RemoteAddr(), c.Type(), err)
|
||||
c.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
_ = c.SetDeadline(time.Now().Add(20 * time.Second))
|
||||
hello, err := protocol.ExchangeHello(c, s.model.GetHello(remoteID))
|
||||
go func() {
|
||||
hello, err := protocol.ExchangeHello(c, s.model.GetHello(remoteID))
|
||||
select {
|
||||
case s.hellos <- &connWithHello{c, hello, err, remoteID, remoteCert}:
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) connectionCheckEarly(remoteID protocol.DeviceID, c internalConn) error {
|
||||
if s.cfg.IgnoredDevice(remoteID) {
|
||||
return errDeviceIgnored
|
||||
}
|
||||
|
||||
if max := s.cfg.Options().ConnectionLimitMax; max > 0 && s.model.NumConnections() >= max {
|
||||
// We're not allowed to accept any more connections.
|
||||
return errConnLimitReached
|
||||
}
|
||||
|
||||
cfg, ok := s.cfg.Device(remoteID)
|
||||
if !ok {
|
||||
// We do go ahead exchanging hello messages to get information about the device.
|
||||
return nil
|
||||
}
|
||||
|
||||
if cfg.Paused {
|
||||
return errDevicePaused
|
||||
}
|
||||
|
||||
if len(cfg.AllowedNetworks) > 0 && !IsAllowedNetwork(c.RemoteAddr().String(), cfg.AllowedNetworks) {
|
||||
// The connection is not from an allowed network.
|
||||
return errNetworkNotAllowed
|
||||
}
|
||||
|
||||
// Lower priority is better, just like nice etc.
|
||||
if ct, ok := s.model.Connection(remoteID); ok {
|
||||
if ct.Priority() > c.priority || time.Since(ct.Statistics().StartedAt) > minConnectionReplaceAge {
|
||||
l.Debugf("Switching connections %s (existing: %s new: %s)", remoteID, ct, c)
|
||||
} else {
|
||||
// We should not already be connected to the other party. TODO: This
|
||||
// could use some better handling. If the old connection is dead but
|
||||
// hasn't timed out yet we may want to drop *that* connection and keep
|
||||
// this one. But in case we are two devices connecting to each other
|
||||
// in parallel we don't want to do that or we end up with no
|
||||
// connections still established...
|
||||
return errDeviceAlreadyConnected
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) handleHellos(ctx context.Context) error {
|
||||
var c internalConn
|
||||
var hello protocol.Hello
|
||||
var err error
|
||||
var remoteID protocol.DeviceID
|
||||
var remoteCert *x509.Certificate
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case withHello := <-s.hellos:
|
||||
c = withHello.c
|
||||
hello = withHello.hello
|
||||
err = withHello.err
|
||||
remoteID = withHello.remoteID
|
||||
remoteCert = withHello.remoteCert
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if protocol.IsVersionMismatch(err) {
|
||||
// The error will be a relatively user friendly description
|
||||
@@ -279,25 +377,6 @@ func (s *service) handle(ctx context.Context) error {
|
||||
continue
|
||||
}
|
||||
|
||||
// If we have a relay connection, and the new incoming connection is
|
||||
// not a relay connection, we should drop that, and prefer this one.
|
||||
ct, connected := s.model.Connection(remoteID)
|
||||
|
||||
// Lower priority is better, just like nice etc.
|
||||
if connected && (ct.Priority() > c.priority || time.Since(ct.Statistics().StartedAt) > minConnectionReplaceAge) {
|
||||
l.Debugf("Switching connections %s (existing: %s new: %s)", remoteID, ct, c)
|
||||
} else if connected {
|
||||
// We should not already be connected to the other party. TODO: This
|
||||
// could use some better handling. If the old connection is dead but
|
||||
// hasn't timed out yet we may want to drop *that* connection and keep
|
||||
// this one. But in case we are two devices connecting to each other
|
||||
// in parallel we don't want to do that or we end up with no
|
||||
// connections still established...
|
||||
l.Infof("Connected to already connected device %s (existing: %s new: %s)", remoteID, ct, c)
|
||||
c.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
deviceCfg, ok := s.cfg.Device(remoteID)
|
||||
if !ok {
|
||||
l.Infof("Device %s removed from config during connection attempt at %s", remoteID, c)
|
||||
@@ -346,7 +425,6 @@ func (s *service) handle(ctx context.Context) error {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) connect(ctx context.Context) error {
|
||||
// Map of when to earliest dial each given device + address again
|
||||
nextDialAt := make(nextDialRegistry)
|
||||
@@ -581,7 +659,7 @@ func (s *service) resolveDialTargets(ctx context.Context, now time.Time, cfg con
|
||||
continue
|
||||
}
|
||||
|
||||
dialer := dialerFactory.New(s.cfg.Options(), s.tlsCfg)
|
||||
dialer := dialerFactory.New(s.cfg.Options(), s.tlsCfg, s.registry)
|
||||
nextDialAt.set(deviceID, addr, now.Add(dialer.RedialFrequency()))
|
||||
|
||||
// For LAN addresses, increase the priority so that we
|
||||
@@ -681,7 +759,7 @@ func (s *service) createListener(factory listenerFactory, uri *url.URL) bool {
|
||||
|
||||
l.Debugln("Starting listener", uri)
|
||||
|
||||
listener := factory.New(uri, s.cfg, s.tlsCfg, s.conns, s.natService)
|
||||
listener := factory.New(uri, s.cfg, s.tlsCfg, s.conns, s.natService, s.registry)
|
||||
listener.OnAddressesChanged(s.logListenAddressesChangedEvent)
|
||||
|
||||
// Retrying a listener many times in rapid succession is unlikely to help,
|
||||
@@ -882,7 +960,7 @@ func (s *connectionStatusHandler) ConnectionStatus() map[string]ConnectionStatus
|
||||
}
|
||||
|
||||
func (s *connectionStatusHandler) setConnectionStatus(address string, err error) {
|
||||
if errors.Cause(err) == context.Canceled {
|
||||
if errors.Is(err, context.Canceled) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/connections/registry"
|
||||
"github.com/syncthing/syncthing/lib/nat"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/stats"
|
||||
@@ -139,7 +140,7 @@ func (c internalConn) String() string {
|
||||
}
|
||||
|
||||
type dialerFactory interface {
|
||||
New(config.OptionsConfiguration, *tls.Config) genericDialer
|
||||
New(config.OptionsConfiguration, *tls.Config, *registry.Registry) genericDialer
|
||||
Priority() int
|
||||
AlwaysWAN() bool
|
||||
Valid(config.Configuration) error
|
||||
@@ -162,7 +163,7 @@ type genericDialer interface {
|
||||
}
|
||||
|
||||
type listenerFactory interface {
|
||||
New(*url.URL, config.Wrapper, *tls.Config, chan internalConn, *nat.Service) genericListener
|
||||
New(*url.URL, config.Wrapper, *tls.Config, chan internalConn, *nat.Service, *registry.Registry) genericListener
|
||||
Valid(config.Configuration) error
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/connections/registry"
|
||||
"github.com/syncthing/syncthing/lib/dialer"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
)
|
||||
@@ -28,6 +29,7 @@ func init() {
|
||||
|
||||
type tcpDialer struct {
|
||||
commonDialer
|
||||
registry *registry.Registry
|
||||
}
|
||||
|
||||
func (d *tcpDialer) Dial(ctx context.Context, _ protocol.DeviceID, uri *url.URL) (internalConn, error) {
|
||||
@@ -35,7 +37,7 @@ func (d *tcpDialer) Dial(ctx context.Context, _ protocol.DeviceID, uri *url.URL)
|
||||
|
||||
timeoutCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
defer cancel()
|
||||
conn, err := dialer.DialContextReusePort(timeoutCtx, uri.Scheme, uri.Host)
|
||||
conn, err := dialer.DialContextReusePortFunc(d.registry)(timeoutCtx, uri.Scheme, uri.Host)
|
||||
if err != nil {
|
||||
return internalConn{}, err
|
||||
}
|
||||
@@ -62,12 +64,15 @@ func (d *tcpDialer) Dial(ctx context.Context, _ protocol.DeviceID, uri *url.URL)
|
||||
|
||||
type tcpDialerFactory struct{}
|
||||
|
||||
func (tcpDialerFactory) New(opts config.OptionsConfiguration, tlsCfg *tls.Config) genericDialer {
|
||||
return &tcpDialer{commonDialer{
|
||||
trafficClass: opts.TrafficClass,
|
||||
reconnectInterval: time.Duration(opts.ReconnectIntervalS) * time.Second,
|
||||
tlsCfg: tlsCfg,
|
||||
}}
|
||||
func (tcpDialerFactory) New(opts config.OptionsConfiguration, tlsCfg *tls.Config, registry *registry.Registry) genericDialer {
|
||||
return &tcpDialer{
|
||||
commonDialer: commonDialer{
|
||||
trafficClass: opts.TrafficClass,
|
||||
reconnectInterval: time.Duration(opts.ReconnectIntervalS) * time.Second,
|
||||
tlsCfg: tlsCfg,
|
||||
},
|
||||
registry: registry,
|
||||
}
|
||||
}
|
||||
|
||||
func (tcpDialerFactory) Priority() int {
|
||||
|
||||
@@ -32,11 +32,12 @@ type tcpListener struct {
|
||||
svcutil.ServiceWithError
|
||||
onAddressesChangedNotifier
|
||||
|
||||
uri *url.URL
|
||||
cfg config.Wrapper
|
||||
tlsCfg *tls.Config
|
||||
conns chan internalConn
|
||||
factory listenerFactory
|
||||
uri *url.URL
|
||||
cfg config.Wrapper
|
||||
tlsCfg *tls.Config
|
||||
conns chan internalConn
|
||||
factory listenerFactory
|
||||
registry *registry.Registry
|
||||
|
||||
natService *nat.Service
|
||||
mapping *nat.Mapping
|
||||
@@ -69,8 +70,8 @@ func (t *tcpListener) serve(ctx context.Context) error {
|
||||
t.notifyAddressesChanged(t)
|
||||
defer t.clearAddresses(t)
|
||||
|
||||
registry.Register(t.uri.Scheme, tcaddr)
|
||||
defer registry.Unregister(t.uri.Scheme, tcaddr)
|
||||
t.registry.Register(t.uri.Scheme, tcaddr)
|
||||
defer t.registry.Unregister(t.uri.Scheme, tcaddr)
|
||||
|
||||
l.Infof("TCP listener (%v) starting", tcaddr)
|
||||
defer l.Infof("TCP listener (%v) shutting down", tcaddr)
|
||||
@@ -213,7 +214,7 @@ func (t *tcpListener) NATType() string {
|
||||
|
||||
type tcpListenerFactory struct{}
|
||||
|
||||
func (f *tcpListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service) genericListener {
|
||||
func (f *tcpListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service, registry *registry.Registry) genericListener {
|
||||
l := &tcpListener{
|
||||
uri: fixupPort(uri, config.DefaultTCPPort),
|
||||
cfg: cfg,
|
||||
@@ -221,6 +222,7 @@ func (f *tcpListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.C
|
||||
conns: conns,
|
||||
natService: natService,
|
||||
factory: f,
|
||||
registry: registry,
|
||||
}
|
||||
l.ServiceWithError = svcutil.AsService(l.serve, l.String())
|
||||
return l
|
||||
|
||||
@@ -133,23 +133,13 @@ func OpenMemory() Backend {
|
||||
return OpenLevelDBMemory()
|
||||
}
|
||||
|
||||
type errClosed struct{}
|
||||
var (
|
||||
errClosed = errors.New("database is closed")
|
||||
errNotFound = errors.New("key not found")
|
||||
)
|
||||
|
||||
func (*errClosed) Error() string { return "database is closed" }
|
||||
|
||||
type errNotFound struct{}
|
||||
|
||||
func (*errNotFound) Error() string { return "key not found" }
|
||||
|
||||
func IsClosed(err error) bool {
|
||||
e := &errClosed{}
|
||||
return errors.As(err, &e)
|
||||
}
|
||||
|
||||
func IsNotFound(err error) bool {
|
||||
e := &errNotFound{}
|
||||
return errors.As(err, &e)
|
||||
}
|
||||
func IsClosed(err error) bool { return errors.Is(err, errClosed) }
|
||||
func IsNotFound(err error) bool { return errors.Is(err, errNotFound) }
|
||||
|
||||
// releaser manages counting on top of a waitgroup
|
||||
type releaser struct {
|
||||
@@ -183,7 +173,7 @@ func (cg *closeWaitGroup) Add(i int) error {
|
||||
cg.closeMut.RLock()
|
||||
defer cg.closeMut.RUnlock()
|
||||
if cg.closed {
|
||||
return &errClosed{}
|
||||
return errClosed
|
||||
}
|
||||
cg.WaitGroup.Add(i)
|
||||
return nil
|
||||
|
||||
@@ -223,11 +223,11 @@ func (it *leveldbIterator) Error() error {
|
||||
|
||||
// wrapLeveldbErr wraps errors so that the backend package can recognize them
|
||||
func wrapLeveldbErr(err error) error {
|
||||
if err == leveldb.ErrClosed {
|
||||
return &errClosed{}
|
||||
}
|
||||
if err == leveldb.ErrNotFound {
|
||||
return &errNotFound{}
|
||||
switch err {
|
||||
case leveldb.ErrClosed:
|
||||
return errClosed
|
||||
case leveldb.ErrNotFound:
|
||||
return errNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -133,13 +133,13 @@ var (
|
||||
update0to3Folder = "UpdateSchema0to3"
|
||||
invalid = "invalid"
|
||||
slashPrefixed = "/notgood"
|
||||
haveUpdate0to3 map[protocol.DeviceID]fileList
|
||||
haveUpdate0to3 map[protocol.DeviceID][]protocol.FileInfo
|
||||
)
|
||||
|
||||
func init() {
|
||||
remoteDevice0, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
|
||||
remoteDevice1, _ = protocol.DeviceIDFromString("I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU")
|
||||
haveUpdate0to3 = map[protocol.DeviceID]fileList{
|
||||
haveUpdate0to3 = map[protocol.DeviceID][]protocol.FileInfo{
|
||||
protocol.LocalDeviceID: {
|
||||
protocol.FileInfo{Name: "a", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(1)},
|
||||
protocol.FileInfo{Name: slashPrefixed, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(1)},
|
||||
|
||||
@@ -403,8 +403,8 @@ func (s *FileSet) SetIndexID(device protocol.DeviceID, id protocol.IndexID) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *FileSet) MtimeFS(filesystem fs.Filesystem) fs.Filesystem {
|
||||
opStr := fmt.Sprintf("%s MtimeFS()", s.folder)
|
||||
func (s *FileSet) MtimeOption() fs.Option {
|
||||
opStr := fmt.Sprintf("%s MtimeOption()", s.folder)
|
||||
l.Debugf(opStr)
|
||||
prefix, err := s.db.keyer.GenerateMtimesKey(nil, []byte(s.folder))
|
||||
if backend.IsClosed(err) {
|
||||
@@ -413,7 +413,7 @@ func (s *FileSet) MtimeFS(filesystem fs.Filesystem) fs.Filesystem {
|
||||
fatalError(err, opStr, s.db)
|
||||
}
|
||||
kv := NewNamespacedKV(s.db, string(prefix))
|
||||
return fs.NewMtimeFS(filesystem, kv)
|
||||
return fs.NewMtimeOption(kv)
|
||||
}
|
||||
|
||||
func (s *FileSet) ListDevices() []protocol.DeviceID {
|
||||
|
||||
@@ -512,17 +512,3 @@ func (fv FileVersion) copy() FileVersion {
|
||||
n.InvalidDevices = append([][]byte{}, fv.InvalidDevices...)
|
||||
return n
|
||||
}
|
||||
|
||||
type fileList []protocol.FileInfo
|
||||
|
||||
func (fl fileList) Len() int {
|
||||
return len(fl)
|
||||
}
|
||||
|
||||
func (fl fileList) Swap(a, b int) {
|
||||
fl[a], fl[b] = fl[b], fl[a]
|
||||
}
|
||||
|
||||
func (fl fileList) Less(a, b int) bool {
|
||||
return fl[a].Name < fl[b].Name
|
||||
}
|
||||
|
||||
@@ -104,32 +104,34 @@ func DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
// DialContextReusePort tries dialing via proxy if a proxy is configured, and falls back to
|
||||
// a direct connection reusing the port from the connections registry, if no proxy is defined, or connecting via proxy
|
||||
// fails. It also in parallel dials without reusing the port, just in case reusing the port affects routing decisions badly.
|
||||
func DialContextReusePort(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
// If proxy is configured, there is no point trying to reuse listen addresses.
|
||||
if proxy.FromEnvironment() != proxy.Direct {
|
||||
return DialContext(ctx, network, addr)
|
||||
}
|
||||
func DialContextReusePortFunc(registry *registry.Registry) func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
// If proxy is configured, there is no point trying to reuse listen addresses.
|
||||
if proxy.FromEnvironment() != proxy.Direct {
|
||||
return DialContext(ctx, network, addr)
|
||||
}
|
||||
|
||||
localAddrInterface := registry.Get(network, func(addr interface{}) bool {
|
||||
return addr.(*net.TCPAddr).IP.IsUnspecified()
|
||||
})
|
||||
if localAddrInterface == nil {
|
||||
// Nothing listening, nothing to reuse.
|
||||
return DialContext(ctx, network, addr)
|
||||
}
|
||||
localAddrInterface := registry.Get(network, func(addr interface{}) bool {
|
||||
return addr.(*net.TCPAddr).IP.IsUnspecified()
|
||||
})
|
||||
if localAddrInterface == nil {
|
||||
// Nothing listening, nothing to reuse.
|
||||
return DialContext(ctx, network, addr)
|
||||
}
|
||||
|
||||
laddr, ok := localAddrInterface.(*net.TCPAddr)
|
||||
if !ok {
|
||||
return nil, errUnexpectedInterfaceType
|
||||
}
|
||||
laddr, ok := localAddrInterface.(*net.TCPAddr)
|
||||
if !ok {
|
||||
return nil, errUnexpectedInterfaceType
|
||||
}
|
||||
|
||||
// Dial twice, once reusing the listen address, another time not reusing it, just in case reusing the address
|
||||
// influences routing and we fail to reach our destination.
|
||||
dialer := net.Dialer{
|
||||
Control: ReusePortControl,
|
||||
LocalAddr: laddr,
|
||||
// Dial twice, once reusing the listen address, another time not reusing it, just in case reusing the address
|
||||
// influences routing and we fail to reach our destination.
|
||||
dialer := net.Dialer{
|
||||
Control: ReusePortControl,
|
||||
LocalAddr: laddr,
|
||||
}
|
||||
return dialTwicePreferFirst(ctx, dialer.DialContext, (&net.Dialer{}).DialContext, "reuse", "non-reuse", network, addr)
|
||||
}
|
||||
return dialTwicePreferFirst(ctx, dialer.DialContext, (&net.Dialer{}).DialContext, "reuse", "non-reuse", network, addr)
|
||||
}
|
||||
|
||||
type dialFunc func(ctx context.Context, network, address string) (net.Conn, error)
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/connections/registry"
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
)
|
||||
@@ -23,7 +24,7 @@ func setupCache() *manager {
|
||||
cfg.Options.LocalAnnEnabled = false
|
||||
cfg.Options.GlobalAnnEnabled = false
|
||||
|
||||
return NewManager(protocol.LocalDeviceID, config.Wrap("", cfg, protocol.LocalDeviceID, events.NoopLogger), tls.Certificate{}, events.NoopLogger, nil).(*manager)
|
||||
return NewManager(protocol.LocalDeviceID, config.Wrap("", cfg, protocol.LocalDeviceID, events.NoopLogger), tls.Certificate{}, events.NoopLogger, nil, registry.New()).(*manager)
|
||||
}
|
||||
|
||||
func TestCacheUnique(t *testing.T) {
|
||||
|
||||
@@ -14,12 +14,14 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
stdsync "sync"
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/connections/registry"
|
||||
"github.com/syncthing/syncthing/lib/dialer"
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
@@ -44,7 +46,7 @@ type httpClient interface {
|
||||
const (
|
||||
defaultReannounceInterval = 30 * time.Minute
|
||||
announceErrorRetryInterval = 5 * time.Minute
|
||||
requestTimeout = 5 * time.Second
|
||||
requestTimeout = 30 * time.Second
|
||||
maxAddressChangesBetweenAnnouncements = 10
|
||||
)
|
||||
|
||||
@@ -71,7 +73,7 @@ func (e *lookupError) CacheFor() time.Duration {
|
||||
return e.cacheFor
|
||||
}
|
||||
|
||||
func NewGlobal(server string, cert tls.Certificate, addrList AddressLister, evLogger events.Logger) (FinderService, error) {
|
||||
func NewGlobal(server string, cert tls.Certificate, addrList AddressLister, evLogger events.Logger, registry *registry.Registry) (FinderService, error) {
|
||||
server, opts, err := parseOptions(server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -88,10 +90,16 @@ func NewGlobal(server string, cert tls.Certificate, addrList AddressLister, evLo
|
||||
// The http.Client used for announcements. It needs to have our
|
||||
// certificate to prove our identity, and may or may not verify the server
|
||||
// certificate depending on the insecure setting.
|
||||
var dialContext func(ctx context.Context, network, addr string) (net.Conn, error)
|
||||
if registry != nil {
|
||||
dialContext = dialer.DialContextReusePortFunc(registry)
|
||||
} else {
|
||||
dialContext = dialer.DialContext
|
||||
}
|
||||
var announceClient httpClient = &contextClient{&http.Client{
|
||||
Timeout: requestTimeout,
|
||||
Transport: &http.Transport{
|
||||
DialContext: dialer.DialContextReusePort,
|
||||
DialContext: dialContext,
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: opts.insecure,
|
||||
@@ -420,26 +428,18 @@ type contextClient struct {
|
||||
}
|
||||
|
||||
func (c *contextClient) Get(ctx context.Context, url string) (*http.Response, error) {
|
||||
// For <go1.13 compatibility. Use the following commented line once that
|
||||
// isn't required anymore.
|
||||
// req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Cancel = ctx.Done()
|
||||
return c.Client.Do(req)
|
||||
}
|
||||
|
||||
func (c *contextClient) Post(ctx context.Context, url, ctype string, data io.Reader) (*http.Response, error) {
|
||||
// For <go1.13 compatibility. Use the following commented line once that
|
||||
// isn't required anymore.
|
||||
// req, err := http.NewRequestWithContext(ctx, "POST", url, data)
|
||||
req, err := http.NewRequest("POST", url, data)
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", url, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Cancel = ctx.Done()
|
||||
req.Header.Set("Content-Type", ctype)
|
||||
return c.Client.Do(req)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/connections/registry"
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/tlsutil"
|
||||
@@ -56,15 +57,17 @@ func TestGlobalOverHTTP(t *testing.T) {
|
||||
// is only allowed in combination with the "insecure" and "noannounce"
|
||||
// parameters.
|
||||
|
||||
if _, err := NewGlobal("http://192.0.2.42/", tls.Certificate{}, nil, events.NoopLogger); err == nil {
|
||||
registry := registry.New()
|
||||
|
||||
if _, err := NewGlobal("http://192.0.2.42/", tls.Certificate{}, nil, events.NoopLogger, registry); err == nil {
|
||||
t.Fatal("http is not allowed without insecure and noannounce")
|
||||
}
|
||||
|
||||
if _, err := NewGlobal("http://192.0.2.42/?insecure", tls.Certificate{}, nil, events.NoopLogger); err == nil {
|
||||
if _, err := NewGlobal("http://192.0.2.42/?insecure", tls.Certificate{}, nil, events.NoopLogger, registry); err == nil {
|
||||
t.Fatal("http is not allowed without noannounce")
|
||||
}
|
||||
|
||||
if _, err := NewGlobal("http://192.0.2.42/?noannounce", tls.Certificate{}, nil, events.NoopLogger); err == nil {
|
||||
if _, err := NewGlobal("http://192.0.2.42/?noannounce", tls.Certificate{}, nil, events.NoopLogger, registry); err == nil {
|
||||
t.Fatal("http is not allowed without insecure")
|
||||
}
|
||||
|
||||
@@ -185,7 +188,7 @@ func TestGlobalAnnounce(t *testing.T) {
|
||||
go func() { _ = http.Serve(list, mux) }()
|
||||
|
||||
url := "https://" + list.Addr().String() + "?insecure"
|
||||
disco, err := NewGlobal(url, cert, new(fakeAddressLister), events.NoopLogger)
|
||||
disco, err := NewGlobal(url, cert, new(fakeAddressLister), events.NoopLogger, registry.New())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -210,7 +213,7 @@ func TestGlobalAnnounce(t *testing.T) {
|
||||
}
|
||||
|
||||
func testLookup(url string) ([]string, error) {
|
||||
disco, err := NewGlobal(url, tls.Certificate{}, nil, events.NoopLogger)
|
||||
disco, err := NewGlobal(url, tls.Certificate{}, nil, events.NoopLogger, registry.New())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/thejerf/suture/v4"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/connections/registry"
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
@@ -44,12 +45,13 @@ type manager struct {
|
||||
cert tls.Certificate
|
||||
evLogger events.Logger
|
||||
addressLister AddressLister
|
||||
registry *registry.Registry
|
||||
|
||||
finders map[string]cachedFinder
|
||||
mut sync.RWMutex
|
||||
}
|
||||
|
||||
func NewManager(myID protocol.DeviceID, cfg config.Wrapper, cert tls.Certificate, evLogger events.Logger, lister AddressLister) Manager {
|
||||
func NewManager(myID protocol.DeviceID, cfg config.Wrapper, cert tls.Certificate, evLogger events.Logger, lister AddressLister, registry *registry.Registry) Manager {
|
||||
m := &manager{
|
||||
Supervisor: suture.New("discover.Manager", svcutil.SpecWithDebugLogger(l)),
|
||||
myID: myID,
|
||||
@@ -57,6 +59,7 @@ func NewManager(myID protocol.DeviceID, cfg config.Wrapper, cert tls.Certificate
|
||||
cert: cert,
|
||||
evLogger: evLogger,
|
||||
addressLister: lister,
|
||||
registry: registry,
|
||||
|
||||
finders: make(map[string]cachedFinder),
|
||||
mut: sync.NewRWMutex(),
|
||||
@@ -257,7 +260,7 @@ func (m *manager) CommitConfiguration(_, to config.Configuration) (handled bool)
|
||||
if _, ok := m.finders[identity]; ok {
|
||||
continue
|
||||
}
|
||||
gd, err := NewGlobal(srv, m.cert, m.addressLister, m.evLogger)
|
||||
gd, err := NewGlobal(srv, m.cert, m.addressLister, m.evLogger, m.registry)
|
||||
if err != nil {
|
||||
l.Warnln("Global discovery:", err)
|
||||
continue
|
||||
|
||||
@@ -35,6 +35,7 @@ const (
|
||||
PendingDevicesChanged
|
||||
DevicePaused
|
||||
DeviceResumed
|
||||
ClusterConfigReceived
|
||||
LocalChangeDetected
|
||||
RemoteChangeDetected
|
||||
LocalIndexUpdated
|
||||
@@ -118,6 +119,8 @@ func (t EventType) String() string {
|
||||
return "DevicePaused"
|
||||
case DeviceResumed:
|
||||
return "DeviceResumed"
|
||||
case ClusterConfigReceived:
|
||||
return "ClusterConfigReceived"
|
||||
case FolderScanProgress:
|
||||
return "FolderScanProgress"
|
||||
case FolderPaused:
|
||||
@@ -203,6 +206,8 @@ func UnmarshalEventType(s string) EventType {
|
||||
return DevicePaused
|
||||
case "DeviceResumed":
|
||||
return DeviceResumed
|
||||
case "ClusterConfigReceived":
|
||||
return ClusterConfigReceived
|
||||
case "FolderScanProgress":
|
||||
return FolderScanProgress
|
||||
case "FolderPaused":
|
||||
|
||||
@@ -27,12 +27,13 @@ var (
|
||||
|
||||
type OptionJunctionsAsDirs struct{}
|
||||
|
||||
func (o *OptionJunctionsAsDirs) apply(fs Filesystem) {
|
||||
func (o *OptionJunctionsAsDirs) apply(fs Filesystem) Filesystem {
|
||||
if basic, ok := fs.(*BasicFilesystem); !ok {
|
||||
l.Warnln("WithJunctionsAsDirs must only be used with FilesystemTypeBasic")
|
||||
} else {
|
||||
basic.junctionsAsDirs = true
|
||||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
func (o *OptionJunctionsAsDirs) String() string {
|
||||
|
||||
@@ -20,17 +20,13 @@ import (
|
||||
|
||||
func setup(t *testing.T) (*BasicFilesystem, string) {
|
||||
t.Helper()
|
||||
dir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dir := t.TempDir()
|
||||
return newBasicFilesystem(dir), dir
|
||||
}
|
||||
|
||||
func TestChmodFile(t *testing.T) {
|
||||
fs, dir := setup(t)
|
||||
path := filepath.Join(dir, "file")
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
defer os.Chmod(path, 0666)
|
||||
|
||||
@@ -71,7 +67,6 @@ func TestChownFile(t *testing.T) {
|
||||
|
||||
fs, dir := setup(t)
|
||||
path := filepath.Join(dir, "file")
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
defer os.Chmod(path, 0666)
|
||||
|
||||
@@ -108,7 +103,6 @@ func TestChownFile(t *testing.T) {
|
||||
func TestChmodDir(t *testing.T) {
|
||||
fs, dir := setup(t)
|
||||
path := filepath.Join(dir, "dir")
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
mode := os.FileMode(0755)
|
||||
if runtime.GOOS == "windows" {
|
||||
@@ -141,7 +135,6 @@ func TestChmodDir(t *testing.T) {
|
||||
func TestChtimes(t *testing.T) {
|
||||
fs, dir := setup(t)
|
||||
path := filepath.Join(dir, "file")
|
||||
defer os.RemoveAll(dir)
|
||||
fd, err := os.Create(path)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -166,7 +159,6 @@ func TestChtimes(t *testing.T) {
|
||||
func TestCreate(t *testing.T) {
|
||||
fs, dir := setup(t)
|
||||
path := filepath.Join(dir, "file")
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
t.Errorf("exists?")
|
||||
@@ -190,7 +182,6 @@ func TestCreateSymlink(t *testing.T) {
|
||||
|
||||
fs, dir := setup(t)
|
||||
path := filepath.Join(dir, "file")
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
if err := fs.CreateSymlink("blah", "file"); err != nil {
|
||||
t.Error(err)
|
||||
@@ -215,7 +206,6 @@ func TestCreateSymlink(t *testing.T) {
|
||||
|
||||
func TestDirNames(t *testing.T) {
|
||||
fs, dir := setup(t)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
// Case differences
|
||||
testCases := []string{
|
||||
@@ -244,8 +234,7 @@ func TestDirNames(t *testing.T) {
|
||||
|
||||
func TestNames(t *testing.T) {
|
||||
// Tests that all names are without the root directory.
|
||||
fs, dir := setup(t)
|
||||
defer os.RemoveAll(dir)
|
||||
fs, _ := setup(t)
|
||||
|
||||
expected := "file"
|
||||
fd, err := fs.Create(expected)
|
||||
@@ -284,8 +273,7 @@ func TestNames(t *testing.T) {
|
||||
|
||||
func TestGlob(t *testing.T) {
|
||||
// Tests that all names are without the root directory.
|
||||
fs, dir := setup(t)
|
||||
defer os.RemoveAll(dir)
|
||||
fs, _ := setup(t)
|
||||
|
||||
for _, dirToCreate := range []string{
|
||||
filepath.Join("a", "test", "b"),
|
||||
@@ -344,8 +332,7 @@ func TestGlob(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUsage(t *testing.T) {
|
||||
fs, dir := setup(t)
|
||||
defer os.RemoveAll(dir)
|
||||
fs, _ := setup(t)
|
||||
usage, err := fs.Usage(".")
|
||||
if err != nil {
|
||||
if runtime.GOOS == "netbsd" || runtime.GOOS == "openbsd" || runtime.GOOS == "solaris" {
|
||||
@@ -577,18 +564,15 @@ func TestRel(t *testing.T) {
|
||||
|
||||
func TestBasicWalkSkipSymlink(t *testing.T) {
|
||||
_, dir := setup(t)
|
||||
defer os.RemoveAll(dir)
|
||||
testWalkSkipSymlink(t, FilesystemTypeBasic, dir)
|
||||
}
|
||||
|
||||
func TestWalkTraverseDirJunct(t *testing.T) {
|
||||
_, dir := setup(t)
|
||||
defer os.RemoveAll(dir)
|
||||
testWalkTraverseDirJunct(t, FilesystemTypeBasic, dir)
|
||||
}
|
||||
|
||||
func TestWalkInfiniteRecursion(t *testing.T) {
|
||||
_, dir := setup(t)
|
||||
defer os.RemoveAll(dir)
|
||||
testWalkInfiniteRecursion(t, FilesystemTypeBasic, dir)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ package fs
|
||||
import "github.com/syncthing/notify"
|
||||
|
||||
const (
|
||||
subEventMask = notify.Create | notify.FileModified | notify.FileRenameFrom | notify.FileDelete | notify.FileRenameTo
|
||||
subEventMask = notify.Create | notify.FileModified | notify.FileRenameFrom | notify.FileDelete | notify.FileRenameTo | notify.FileNoFollow
|
||||
permEventMask = notify.FileAttrib
|
||||
rmEventMask = notify.FileDelete | notify.FileRenameFrom
|
||||
)
|
||||
|
||||
@@ -18,4 +18,7 @@ const (
|
||||
subEventMask = notify.NoteDelete | notify.NoteWrite | notify.NoteRename | notify.Create | notify.NoteAttrib | notify.NoteExtend
|
||||
permEventMask = 0
|
||||
rmEventMask = notify.NoteDelete | notify.NoteRename
|
||||
|
||||
// WatchKqueue indicates if kqueue is used for filesystem watching
|
||||
WatchKqueue = true
|
||||
)
|
||||
|
||||
13
lib/fs/basicfs_watch_notkqueue.go
Normal file
13
lib/fs/basicfs_watch_notkqueue.go
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright (C) 2022 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
//go:build !dragonfly && !freebsd && !netbsd && !openbsd
|
||||
// +build !dragonfly,!freebsd,!netbsd,!openbsd
|
||||
|
||||
package fs
|
||||
|
||||
// WatchKqueue indicates if kqueue is used for filesystem watching
|
||||
const WatchKqueue = false
|
||||
@@ -49,7 +49,6 @@ func TestResolveWindows83(t *testing.T) {
|
||||
dir = fs.resolveWin83(dir)
|
||||
fs = newBasicFilesystem(dir)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
shortAbs, _ := fs.rooted("LFDATA~1")
|
||||
long := "LFDataTool"
|
||||
@@ -80,7 +79,6 @@ func TestIsWindows83(t *testing.T) {
|
||||
dir = fs.resolveWin83(dir)
|
||||
fs = newBasicFilesystem(dir)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
tempTop, _ := fs.rooted(TempName("baz"))
|
||||
tempBelow, _ := fs.rooted(filepath.Join("foo", "bar", TempName("baz")))
|
||||
|
||||
@@ -123,21 +123,27 @@ func (r *caseFilesystemRegistry) cleaner() {
|
||||
|
||||
var globalCaseFilesystemRegistry = caseFilesystemRegistry{fss: make(map[fskey]*caseFilesystem)}
|
||||
|
||||
// caseFilesystem is a BasicFilesystem with additional checks to make a
|
||||
// potentially case insensitive underlying FS behave like it's case-sensitive.
|
||||
type caseFilesystem struct {
|
||||
Filesystem
|
||||
realCaser
|
||||
}
|
||||
|
||||
// NewCaseFilesystem ensures that the given, potentially case-insensitive filesystem
|
||||
// OptionDetectCaseConflicts ensures that the potentially case-insensitive filesystem
|
||||
// behaves like a case-sensitive filesystem. Meaning that it takes into account
|
||||
// the real casing of a path and returns ErrCaseConflict if the given path differs
|
||||
// from the real path. It is safe to use with any filesystem, i.e. also a
|
||||
// case-sensitive one. However it will add some overhead and thus shouldn't be
|
||||
// used if the filesystem is known to already behave case-sensitively.
|
||||
func NewCaseFilesystem(fs Filesystem) Filesystem {
|
||||
return wrapFilesystem(fs, globalCaseFilesystemRegistry.get)
|
||||
type OptionDetectCaseConflicts struct{}
|
||||
|
||||
func (o *OptionDetectCaseConflicts) apply(fs Filesystem) Filesystem {
|
||||
return globalCaseFilesystemRegistry.get(fs)
|
||||
}
|
||||
|
||||
func (o *OptionDetectCaseConflicts) String() string {
|
||||
return "detectCaseConflicts"
|
||||
}
|
||||
|
||||
// caseFilesystem is a BasicFilesystem with additional checks to make a
|
||||
// potentially case insensitive underlying FS behave like it's case-sensitive.
|
||||
type caseFilesystem struct {
|
||||
Filesystem
|
||||
realCaser
|
||||
}
|
||||
|
||||
func (f *caseFilesystem) Chmod(name string, mode FileMode) error {
|
||||
|
||||
@@ -9,7 +9,6 @@ package fs
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
@@ -28,14 +27,17 @@ func TestRealCase(t *testing.T) {
|
||||
testRealCase(t, newFakeFilesystem(t.Name()+"?insens=true"))
|
||||
})
|
||||
t.Run("actual", func(t *testing.T) {
|
||||
fsys, tmpDir := setup(t)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
fsys, _ := setup(t)
|
||||
testRealCase(t, fsys)
|
||||
})
|
||||
}
|
||||
|
||||
func newCaseFilesystem(fsys Filesystem) *caseFilesystem {
|
||||
return globalCaseFilesystemRegistry.get(fsys).(*caseFilesystem)
|
||||
}
|
||||
|
||||
func testRealCase(t *testing.T, fsys Filesystem) {
|
||||
testFs := NewCaseFilesystem(fsys).(*caseFilesystem)
|
||||
testFs := newCaseFilesystem(fsys)
|
||||
comps := []string{"Foo", "bar", "BAZ", "bAs"}
|
||||
path := filepath.Join(comps...)
|
||||
testFs.MkdirAll(filepath.Join(comps[:len(comps)-1]...), 0777)
|
||||
@@ -79,14 +81,13 @@ func TestRealCaseSensitive(t *testing.T) {
|
||||
testRealCaseSensitive(t, newFakeFilesystem(t.Name()))
|
||||
})
|
||||
t.Run("actual", func(t *testing.T) {
|
||||
fsys, tmpDir := setup(t)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
fsys, _ := setup(t)
|
||||
testRealCaseSensitive(t, fsys)
|
||||
})
|
||||
}
|
||||
|
||||
func testRealCaseSensitive(t *testing.T, fsys Filesystem) {
|
||||
testFs := NewCaseFilesystem(fsys).(*caseFilesystem)
|
||||
testFs := newCaseFilesystem(fsys)
|
||||
|
||||
names := make([]string, 2)
|
||||
names[0] = "foo"
|
||||
@@ -120,8 +121,7 @@ func TestCaseFSStat(t *testing.T) {
|
||||
testCaseFSStat(t, newFakeFilesystem(t.Name()+"?insens=true"))
|
||||
})
|
||||
t.Run("actual", func(t *testing.T) {
|
||||
fsys, tmpDir := setup(t)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
fsys, _ := setup(t)
|
||||
testCaseFSStat(t, fsys)
|
||||
})
|
||||
}
|
||||
@@ -139,7 +139,7 @@ func testCaseFSStat(t *testing.T, fsys Filesystem) {
|
||||
sensitive = false
|
||||
}
|
||||
|
||||
testFs := NewCaseFilesystem(fsys)
|
||||
testFs := newCaseFilesystem(fsys)
|
||||
_, err = testFs.Stat("FOO")
|
||||
if sensitive {
|
||||
if IsNotExist(err) {
|
||||
|
||||
@@ -204,7 +204,6 @@ func TestFakeFSCaseSensitive(t *testing.T) {
|
||||
}
|
||||
|
||||
testDir, sensitive := createTestDir(t)
|
||||
defer removeTestDir(t, testDir)
|
||||
if sensitive {
|
||||
filesystems = append(filesystems, testFS{runtime.GOOS, newBasicFilesystem(testDir)})
|
||||
}
|
||||
@@ -240,7 +239,6 @@ func TestFakeFSCaseInsensitive(t *testing.T) {
|
||||
}
|
||||
|
||||
testDir, sensitive := createTestDir(t)
|
||||
defer removeTestDir(t, testDir)
|
||||
if !sensitive {
|
||||
filesystems = append(filesystems, testFS{runtime.GOOS, newBasicFilesystem(testDir)})
|
||||
}
|
||||
@@ -251,10 +249,7 @@ func TestFakeFSCaseInsensitive(t *testing.T) {
|
||||
func createTestDir(t *testing.T) (string, bool) {
|
||||
t.Helper()
|
||||
|
||||
testDir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("could not create temporary dir for testing: %s", err)
|
||||
}
|
||||
testDir := t.TempDir()
|
||||
|
||||
if fd, err := os.Create(filepath.Join(testDir, ".stfolder")); err != nil {
|
||||
t.Fatalf("could not create .stfolder: %s", err)
|
||||
@@ -273,14 +268,6 @@ func createTestDir(t *testing.T) (string, bool) {
|
||||
return testDir, sensitive
|
||||
}
|
||||
|
||||
func removeTestDir(t *testing.T, testDir string) {
|
||||
t.Helper()
|
||||
|
||||
if err := os.RemoveAll(testDir); err != nil {
|
||||
t.Fatalf("could not remove test directory: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func runTests(t *testing.T, tests []test, filesystems []testFS) {
|
||||
for _, filesystem := range filesystems {
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -202,10 +202,29 @@ var IsPathSeparator = os.IsPathSeparator
|
||||
// representation of those must be part of the returned string.
|
||||
type Option interface {
|
||||
String() string
|
||||
apply(Filesystem)
|
||||
apply(Filesystem) Filesystem
|
||||
}
|
||||
|
||||
func NewFilesystem(fsType FilesystemType, uri string, opts ...Option) Filesystem {
|
||||
var caseOpt Option
|
||||
var mtimeOpt Option
|
||||
i := 0
|
||||
for _, opt := range opts {
|
||||
if caseOpt != nil && mtimeOpt != nil {
|
||||
break
|
||||
}
|
||||
switch opt.(type) {
|
||||
case *OptionDetectCaseConflicts:
|
||||
caseOpt = opt
|
||||
case *optionMtime:
|
||||
mtimeOpt = opt
|
||||
default:
|
||||
opts[i] = opt
|
||||
i++
|
||||
}
|
||||
}
|
||||
opts = opts[:i]
|
||||
|
||||
var fs Filesystem
|
||||
switch fsType {
|
||||
case FilesystemTypeBasic:
|
||||
@@ -221,6 +240,17 @@ func NewFilesystem(fsType FilesystemType, uri string, opts ...Option) Filesystem
|
||||
}
|
||||
}
|
||||
|
||||
// Case handling is the innermost, as any filesystem calls by wrappers should be case-resolved
|
||||
if caseOpt != nil {
|
||||
fs = caseOpt.apply(fs)
|
||||
}
|
||||
|
||||
// mtime handling should happen inside walking, as filesystem calls while
|
||||
// walking should be mtime-resolved too
|
||||
if mtimeOpt != nil {
|
||||
fs = mtimeOpt.apply(fs)
|
||||
}
|
||||
|
||||
if l.ShouldDebug("walkfs") {
|
||||
return NewWalkFilesystem(&logFilesystem{fs})
|
||||
}
|
||||
@@ -289,21 +319,6 @@ func Canonicalize(file string) (string, error) {
|
||||
return file, nil
|
||||
}
|
||||
|
||||
// wrapFilesystem should always be used when wrapping a Filesystem.
|
||||
// It ensures proper wrapping order, which right now means:
|
||||
// `logFilesystem` needs to be the outermost wrapper for caller lookup.
|
||||
func wrapFilesystem(fs Filesystem, wrapFn func(Filesystem) Filesystem) Filesystem {
|
||||
logFs, ok := fs.(*logFilesystem)
|
||||
if ok {
|
||||
fs = logFs.Filesystem
|
||||
}
|
||||
fs = wrapFn(fs)
|
||||
if ok {
|
||||
fs = &logFilesystem{fs}
|
||||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
// unwrapFilesystem removes "wrapping" filesystems to expose the filesystem of the requested wrapperType, if it exists.
|
||||
func unwrapFilesystem(fs Filesystem, wrapperType filesystemWrapperType) (Filesystem, bool) {
|
||||
var ok bool
|
||||
|
||||
@@ -33,20 +33,34 @@ func WithCaseInsensitivity(v bool) MtimeFSOption {
|
||||
}
|
||||
}
|
||||
|
||||
// NewMtimeFS returns a filesystem with nanosecond mtime precision, regardless
|
||||
// of what shenanigans the underlying filesystem gets up to.
|
||||
func NewMtimeFS(fs Filesystem, db database, options ...MtimeFSOption) Filesystem {
|
||||
return wrapFilesystem(fs, func(underlying Filesystem) Filesystem {
|
||||
f := &mtimeFS{
|
||||
Filesystem: underlying,
|
||||
chtimes: underlying.Chtimes, // for mocking it out in the tests
|
||||
db: db,
|
||||
}
|
||||
for _, opt := range options {
|
||||
opt(f)
|
||||
}
|
||||
return f
|
||||
})
|
||||
type optionMtime struct {
|
||||
db database
|
||||
options []MtimeFSOption
|
||||
}
|
||||
|
||||
// NewMtimeOption makes any filesystem provide nanosecond mtime precision,
|
||||
// regardless of what shenanigans the underlying filesystem gets up to.
|
||||
func NewMtimeOption(db database, options ...MtimeFSOption) Option {
|
||||
return &optionMtime{
|
||||
db: db,
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *optionMtime) apply(fs Filesystem) Filesystem {
|
||||
f := &mtimeFS{
|
||||
Filesystem: fs,
|
||||
chtimes: fs.Chtimes, // for mocking it out in the tests
|
||||
db: o.db,
|
||||
}
|
||||
for _, opt := range o.options {
|
||||
opt(f)
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func (_ *optionMtime) String() string {
|
||||
return "mtime"
|
||||
}
|
||||
|
||||
func (f *mtimeFS) Chtimes(name string, atime, mtime time.Time) error {
|
||||
@@ -104,25 +118,6 @@ func (f *mtimeFS) Lstat(name string) (FileInfo, error) {
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (f *mtimeFS) Walk(root string, walkFn WalkFunc) error {
|
||||
return f.Filesystem.Walk(root, func(path string, info FileInfo, err error) error {
|
||||
if info != nil {
|
||||
mtimeMapping, loadErr := f.load(path)
|
||||
if loadErr != nil && err == nil {
|
||||
// The iterator gets to deal with the error
|
||||
err = loadErr
|
||||
}
|
||||
if mtimeMapping.Real == info.ModTime() {
|
||||
info = mtimeFileInfo{
|
||||
FileInfo: info,
|
||||
mtime: mtimeMapping.Virtual,
|
||||
}
|
||||
}
|
||||
}
|
||||
return walkFn(path, info, err)
|
||||
})
|
||||
}
|
||||
|
||||
func (f *mtimeFS) Create(name string) (File, error) {
|
||||
fd, err := f.Filesystem.Create(name)
|
||||
if err != nil {
|
||||
|
||||
@@ -26,7 +26,7 @@ func TestMtimeFS(t *testing.T) {
|
||||
// a random time with nanosecond precision
|
||||
testTime := time.Unix(1234567890, 123456789)
|
||||
|
||||
mtimefs := newMtimeFS(newBasicFilesystem("."), make(mapStore))
|
||||
mtimefs := newMtimeFS(".", make(mapStore))
|
||||
|
||||
// Do one Chtimes call that will go through to the normal filesystem
|
||||
mtimefs.chtimes = os.Chtimes
|
||||
@@ -82,14 +82,10 @@ func TestMtimeFS(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMtimeFSWalk(t *testing.T) {
|
||||
dir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() { _ = os.RemoveAll(dir) }()
|
||||
dir := t.TempDir()
|
||||
|
||||
underlying := NewFilesystem(FilesystemTypeBasic, dir)
|
||||
mtimefs := newMtimeFS(underlying, make(mapStore))
|
||||
mtimefs, walkFs := newMtimeFSWithWalk(dir, make(mapStore))
|
||||
underlying := mtimefs.Filesystem
|
||||
mtimefs.chtimes = failChtimes
|
||||
|
||||
if err := os.WriteFile(filepath.Join(dir, "file"), []byte("hello"), 0644); err != nil {
|
||||
@@ -120,7 +116,7 @@ func TestMtimeFSWalk(t *testing.T) {
|
||||
}
|
||||
|
||||
found := false
|
||||
_ = mtimefs.Walk("", func(path string, info FileInfo, err error) error {
|
||||
_ = walkFs.Walk("", func(path string, info FileInfo, err error) error {
|
||||
if path == "file" {
|
||||
found = true
|
||||
if !info.ModTime().Equal(newTime) {
|
||||
@@ -136,14 +132,10 @@ func TestMtimeFSWalk(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMtimeFSOpen(t *testing.T) {
|
||||
dir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() { _ = os.RemoveAll(dir) }()
|
||||
dir := t.TempDir()
|
||||
|
||||
underlying := NewFilesystem(FilesystemTypeBasic, dir)
|
||||
mtimefs := newMtimeFS(underlying, make(mapStore))
|
||||
mtimefs := newMtimeFS(dir, make(mapStore))
|
||||
underlying := mtimefs.Filesystem
|
||||
mtimefs.chtimes = failChtimes
|
||||
|
||||
if err := os.WriteFile(filepath.Join(dir, "file"), []byte("hello"), 0644); err != nil {
|
||||
@@ -177,6 +169,8 @@ func TestMtimeFSOpen(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
info, err := fd.Stat()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -222,12 +216,12 @@ func TestMtimeFSInsensitive(t *testing.T) {
|
||||
|
||||
// The test should fail with a case sensitive mtimefs
|
||||
t.Run("with case sensitive mtimefs", func(t *testing.T) {
|
||||
theTest(t, newMtimeFS(newBasicFilesystem("."), make(mapStore)), false)
|
||||
theTest(t, newMtimeFS(".", make(mapStore)), false)
|
||||
})
|
||||
|
||||
// And succeed with a case insensitive one.
|
||||
t.Run("with case insensitive mtimefs", func(t *testing.T) {
|
||||
theTest(t, newMtimeFS(newBasicFilesystem("."), make(mapStore), WithCaseInsensitivity(true)), true)
|
||||
theTest(t, newMtimeFS(".", make(mapStore), WithCaseInsensitivity(true)), true)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -261,6 +255,12 @@ func evilChtimes(name string, mtime, atime time.Time) error {
|
||||
return os.Chtimes(name, mtime.Add(300*time.Hour).Truncate(time.Hour), atime.Add(300*time.Hour).Truncate(time.Hour))
|
||||
}
|
||||
|
||||
func newMtimeFS(fs Filesystem, db database, options ...MtimeFSOption) *mtimeFS {
|
||||
return NewMtimeFS(fs, db, options...).(*mtimeFS)
|
||||
func newMtimeFS(path string, db database, options ...MtimeFSOption) *mtimeFS {
|
||||
mtimefs, _ := newMtimeFSWithWalk(path, db, options...)
|
||||
return mtimefs
|
||||
}
|
||||
|
||||
func newMtimeFSWithWalk(path string, db database, options ...MtimeFSOption) (*mtimeFS, *walkFilesystem) {
|
||||
wfs := NewFilesystem(FilesystemTypeBasic, path, NewMtimeOption(db, options...)).(*walkFilesystem)
|
||||
return wfs.Filesystem.(*mtimeFS), wfs
|
||||
}
|
||||
|
||||
@@ -231,10 +231,7 @@ func TestCaseSensitivity(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCaching(t *testing.T) {
|
||||
dir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dir := t.TempDir()
|
||||
|
||||
fs := fs.NewFilesystem(fs.FilesystemTypeBasic, dir)
|
||||
|
||||
@@ -424,10 +421,7 @@ flamingo
|
||||
*.crow
|
||||
`
|
||||
// Caches per file, hence write the patterns to a file.
|
||||
dir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
dir := b.TempDir()
|
||||
|
||||
fs := fs.NewFilesystem(fs.FilesystemTypeBasic, dir)
|
||||
|
||||
@@ -465,10 +459,7 @@ flamingo
|
||||
}
|
||||
|
||||
func TestCacheReload(t *testing.T) {
|
||||
dir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dir := t.TempDir()
|
||||
|
||||
fs := fs.NewFilesystem(fs.FilesystemTypeBasic, dir)
|
||||
|
||||
@@ -988,12 +979,7 @@ func TestIssue4689(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIssue4901(t *testing.T) {
|
||||
dir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer os.RemoveAll(dir)
|
||||
dir := t.TempDir()
|
||||
|
||||
stignore := `
|
||||
#include unicorn-lazor-death
|
||||
@@ -1023,7 +1009,7 @@ func TestIssue4901(t *testing.T) {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
err = pats.Load(".stignore")
|
||||
err := pats.Load(".stignore")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err.Error())
|
||||
}
|
||||
@@ -1200,11 +1186,7 @@ func TestWindowsLineEndings(t *testing.T) {
|
||||
|
||||
lines := "foo\nbar\nbaz\n"
|
||||
|
||||
dir, err := os.MkdirTemp("", "syncthing-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
dir := t.TempDir()
|
||||
|
||||
ffs := fs.NewFilesystem(fs.FilesystemTypeBasic, dir)
|
||||
m := New(ffs)
|
||||
|
||||
@@ -31,7 +31,7 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultFlags = log.Ltime
|
||||
DefaultFlags = log.Ltime | log.Ldate
|
||||
DebugFlags = log.Ltime | log.Ldate | log.Lmicroseconds | log.Lshortfile
|
||||
)
|
||||
|
||||
|
||||
@@ -34,6 +34,9 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/watchaggregator"
|
||||
)
|
||||
|
||||
// Arbitrary limit that triggers a warning on kqueue systems
|
||||
const kqueueItemCountThreshold = 10000
|
||||
|
||||
type folder struct {
|
||||
stateTracker
|
||||
config.FolderConfiguration
|
||||
@@ -81,6 +84,8 @@ type folder struct {
|
||||
|
||||
puller puller
|
||||
versioner versioner.Versioner
|
||||
|
||||
warnedKqueue bool
|
||||
}
|
||||
|
||||
type syncRequest struct {
|
||||
@@ -103,7 +108,7 @@ func newFolder(model *model, fset *db.FileSet, ignores *ignore.Matcher, cfg conf
|
||||
shortID: model.shortID,
|
||||
fset: fset,
|
||||
ignores: ignores,
|
||||
mtimefs: fset.MtimeFS(cfg.Filesystem()),
|
||||
mtimefs: cfg.Filesystem(fset),
|
||||
modTimeWindow: cfg.ModTimeWindow(),
|
||||
done: make(chan struct{}),
|
||||
|
||||
@@ -329,7 +334,7 @@ func (f *folder) getHealthErrorWithoutIgnores() error {
|
||||
dbPath := locations.Get(locations.Database)
|
||||
if usage, err := fs.NewFilesystem(fs.FilesystemTypeBasic, dbPath).Usage("."); err == nil {
|
||||
if err = config.CheckFreeSpace(f.model.cfg.Options().MinHomeDiskFree, usage); err != nil {
|
||||
return errors.Wrapf(err, "insufficient space on disk for database (%v)", dbPath)
|
||||
return fmt.Errorf("insufficient space on disk for database (%v): %w", dbPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,7 +387,6 @@ func (f *folder) pull() (success bool, err error) {
|
||||
l.Debugln("Skipping pull of", f.Description(), "due to folder error:", err)
|
||||
return false, err
|
||||
}
|
||||
f.setError(nil)
|
||||
|
||||
// Send only folder doesn't do any io, it only checks for out-of-sync
|
||||
// items that differ in metadata and updates those.
|
||||
@@ -409,6 +413,7 @@ func (f *folder) pull() (success bool, err error) {
|
||||
l.Debugln("Skipping pull of", f.Description(), "due to folder error:", err)
|
||||
return false, err
|
||||
}
|
||||
f.setError(nil)
|
||||
|
||||
success, err = f.puller.pull()
|
||||
|
||||
@@ -431,10 +436,6 @@ func (f *folder) scanSubdirs(subDirs []string) error {
|
||||
|
||||
err := f.getHealthErrorAndLoadIgnores()
|
||||
if err != nil {
|
||||
// If there is a health error we set it as the folder error. We do not
|
||||
// clear the folder error if there is no health error, as there might be
|
||||
// an *other* folder error (failed to load ignores, for example). Hence
|
||||
// we do not use the CheckHealth() convenience function here.
|
||||
return err
|
||||
}
|
||||
f.setError(nil)
|
||||
@@ -984,10 +985,23 @@ func (f *folder) monitorWatch(ctx context.Context) {
|
||||
warnedOutside := false
|
||||
var lastWatch time.Time
|
||||
pause := time.Minute
|
||||
// Subscribe to folder summaries only on kqueue systems, to warn about potential high resource usage
|
||||
var summarySub events.Subscription
|
||||
var summaryChan <-chan events.Event
|
||||
if fs.WatchKqueue && !f.warnedKqueue {
|
||||
summarySub = f.evLogger.Subscribe(events.FolderSummary)
|
||||
summaryChan = summarySub.C()
|
||||
}
|
||||
defer func() {
|
||||
aggrCancel() // aggrCancel might e re-assigned -> call within closure
|
||||
if summaryChan != nil {
|
||||
summarySub.Unsubscribe()
|
||||
}
|
||||
}()
|
||||
for {
|
||||
select {
|
||||
case <-failTimer.C:
|
||||
eventChan, errChan, err = f.Filesystem().Watch(".", f.ignores, ctx, f.IgnorePerms)
|
||||
eventChan, errChan, err = f.mtimefs.Watch(".", f.ignores, ctx, f.IgnorePerms)
|
||||
// We do this once per minute initially increased to
|
||||
// max one hour in case of repeat failures.
|
||||
f.scanOnWatchErr()
|
||||
@@ -1028,6 +1042,15 @@ func (f *folder) monitorWatch(ctx context.Context) {
|
||||
aggrCancel()
|
||||
errChan = nil
|
||||
aggrCtx, aggrCancel = context.WithCancel(ctx)
|
||||
case ev := <-summaryChan:
|
||||
if data, ok := ev.Data.(FolderSummaryEventData); !ok {
|
||||
f.evLogger.Log(events.Failure, "Unexpected type of folder-summary event in folder.monitorWatch")
|
||||
} else if data.Summary.LocalTotalItems > kqueueItemCountThreshold {
|
||||
f.warnedKqueue = true
|
||||
summarySub.Unsubscribe()
|
||||
summaryChan = nil
|
||||
l.Warnf("Filesystem watching (kqueue) is enabled on %v with a lot of files/directories, and that requires a lot of resources and might slow down your system significantly", f.Description())
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user