File Coverage

File:blib/lib/App/FileSync/I18N/en.pm
Coverage:100.0%

linestmtbrancondsubtimecode
1package App::FileSync::I18N::en;
2
3# The English catalogue: every user-facing string in the distribution, by key.
4# Placeholders are %{name}FMT (any sprintf conversion); see App::FileSync::I18N.
5# Keys are grouped by the module that raises them.
6
7
328
328
328
759
250
4245
use strict;
8
328
328
328
473
230
5503
use warnings;
9
10
328
328
328
732
304
869
use version; our $VERSION = version->declare('0.001.1');
11
12our %MESSAGES = (
13        # ---------------------------------------------------------- i18n itself
14        'i18n.bad_language'  => "Bad language code '%{language}s' (want two or three lower-case letters)",
15        'i18n.bad_catalogue' => "The catalogue for '%{language}s' is not a hash",
16
17        # -------------------------------------------------------- arguments
18        'args.invalid' => '%{routine}s: %{reason}s',
19
20        # ------------------------------------------------------- shared words
21        'word.file'      => { _by => 'count', one => '%{count}d file', other => '%{count}d files' },
22        'word.empty_dir' => { _by => 'count', one => '%{count}d empty dir', other => '%{count}d empty dirs' },
23        'word.snapshot'  => { _by => 'count', one => 'snapshot', other => 'snapshots' },
24
25        # ---------------------------------------------------- path validation
26        'path.missing'            => 'missing path',
27        'path.not_text'           => 'path is not text',
28        'path.empty'              => 'empty path',
29        'path.too_long'           => 'path is too long',
30        'path.absolute'           => 'absolute path',
31        'path.drive'              => 'drive-relative path',
32        'path.backslash'          => 'backslash in path',
33        'path.nul'                => 'NUL in path',
34        'path.control'            => 'control character in path',
35        'path.empty_component'    => 'empty path component',
36        'path.dot_component'      => 'dot path component',
37        'path.parent_component'   => 'parent path component',
38        'path.component_too_long' => 'path component is too long',
39        'path.unsafe'             => "Unsafe path '%{path}s': %{reason}s",
40
41        # ------------------------------------------------------ id validation
42        'id.repo_name' => 'repo name',
43        'id.client_id' => 'client id',
44        'id.missing'   => 'missing %{what}s',
45        'id.not_text'  => '%{what}s is not text',
46        'id.empty'     => 'empty %{what}s',
47        'id.too_long'  => '%{what}s is too long',
48        'id.bad'       => "bad %{what}s '%{value}s'",
49
50        # ------------------------------------------------------- date parsing
51        'when.bad' => "Bad %{option}s '%{value}s' (use YYYY-MM-DD or an epoch)",
52
53        # ------------------------------------------------------- file system
54        'io.read'        => 'Cannot read %{path}s: %{error}s',
55        'io.write'       => 'Cannot write %{path}s: %{error}s',
56        'io.append'      => 'Cannot append to %{path}s: %{error}s',
57        'io.temp'        => 'Cannot create a temporary file in %{path}s: %{error}s',
58        'io.rename'      => 'Cannot move %{from}s to %{to}s: %{error}s',
59        'io.remove'      => 'Cannot remove %{path}s: %{error}s',
60        'io.replace_dir' => 'Cannot replace non-empty directory %{path}s',
61        'io.copy'        => 'Cannot copy %{from}s to %{to}s: %{error}s',
62        'io.mkdir'       => 'Cannot create directory %{path}s: %{error}s',
63        'io.seek'        => 'Cannot seek in %{path}s: %{error}s',
64        'io.utime'       => 'Cannot set the modification time of %{path}s: %{error}s',
65        'io.short'       => 'Unexpected end of %{path}s',
66
67        # ------------------------------------------------------- configuration
68        'config.no_home'    => 'Cannot determine your home directory; set FILESYNC_HOME',
69        'config.parse'      => 'Cannot parse %{path}s: %{error}s',
70        'config.not_object' => '%{path}s is not a JSON object',
71        'config.no_repo'    => "No such repo '%{repo}s' under %{root}s (run filesync-admin repo create)",
72
73        # ------------------------------------------------------------ scanning
74        'scan.unreadable'  => 'cannot read: %{error}s',
75        'scan.cannot_stat' => 'cannot stat: %{error}s',
76        'scan.cannot_list' => 'cannot read directory: %{error}s',
77        'scan.symlink'     => 'symbolic link',
78        'scan.special'     => 'not a regular file',
79
80        # --------------------------------------------------------------- trash
81        'trash.move'        => 'Cannot move %{from}s to %{to}s: %{error}s',
82        'trash.missing'     => 'Trash: %{path}s is not there',
83        'trash.exists'      => 'Trash: refusing to overwrite %{path}s',
84        'trash.cannot_stat' => 'Trash: cannot stat %{path}s: %{error}s',
85        'trash.not_regular' => 'Trash: %{path}s is not a regular file',
86
87        # -------------------------------------------------------------- verify
88        'verify.no_root'      => 'Verify: %{root}s is not a directory',
89        'verify.type_changed' => 'type changed',
90
91        # --------------------------------------------------------------- merge
92        'merge.master'              => 'master',
93        'merge.deleted_changed'     => '%{path}s: deleted on %{client}s but changed on the master; restored from the master',
94        'merge.changed_deleted'     => '%{path}s: changed on %{client}s but deleted on the master; restored to the master',
95        'merge.conflict_copy'       => '%{path}s: changed on both %{client}s and the master; %{kept}s version kept, %{other}s version saved as %{copy}s',
96        'merge.conflict_dir'        => '%{path}s: changed on both %{client}s and the master; %{kept}s version kept, the empty directory on the other side was discarded',
97        'merge.replica_overwritten' => '%{path}s: changed on the replica; overwritten from the master',
98        'merge.replica_removed'     => '%{path}s: removed on the replica; not in the master',
99        'merge.too_many'            => 'refusing to delete %{count}d files (limit is %{max}d); rerun with --force if this is intended',
100        'merge.too_many_percent'    => 'refusing to delete %{count}d of %{known}d known files (limit is %{percent}s%%); rerun with --force if this is intended',
101
102        # --------------------------------------------------------------- delta
103        'delta.bad_count'      => 'Bad signature block count',
104        'delta.bad_length'     => 'Signature is %{length}d bytes, expected %{expected}d',
105        'delta.no_output'      => 'Delta: no output handle',
106        'delta.no_block'       => 'Delta: signature has no block length',
107        'delta.write'          => 'Cannot write the delta: %{error}s',
108        'delta.read'           => 'Cannot read the delta: %{error}s',
109        'delta.bad_record'     => "Bad delta record '%{type}s'",
110        'delta.write_restored' => 'Cannot write the restored file: %{error}s',
111
112        # ------------------------------------------------------------ protocol
113        'protocol.closed'       => 'Protocol: connection is closed',
114        'protocol.write_failed' => 'Protocol: cannot write to the connection: %{error}s',
115        'protocol.malformed'    => 'Protocol: malformed message from the peer: %{error}s',
116        'protocol.not_object'   => 'Protocol: message is not an object',
117        'protocol.bad_length'   => 'Protocol: bad payload length',
118        'protocol.inflate'      => 'Protocol: cannot decompress the payload',
119        'protocol.corrupt'      => 'Protocol: corrupt compressed payload',
120        'protocol.too_large'    => 'Protocol: compressed payload expands beyond the limit',
121        'protocol.negative'     => 'Protocol: negative payload length',
122        'protocol.read_failed'  => 'Protocol: read error: %{error}s',
123        'protocol.eof'          => 'Protocol: connection closed by the peer',
124
125        # --------------------------------------------------------------- store
126        'store.bad_client' => 'Store: %{reason}s',
127        'store.bad_repo'   => 'Store: %{reason}s',
128        'store.symlink'    => 'Refusing to write through symlinked directory %{path}s',
129        'store.no_master'  => 'Master directory is missing: %{path}s',
130
131        'admin.bad_repo'      => 'Invalid repo name: %{reason}s',
132        'admin.bad_client'    => 'Invalid client id: %{reason}s',
133        'admin.bad_role'      => q{Invalid role '%{role}s' (want %{roles}s)},
134        'admin.repo_exists'   => q{Repo '%{repo}s' already exists at %{path}s},
135        'admin.locked'        => q{Another sync session holds the lock for repo '%{repo}s'},
136        'admin.unsafe_path'   => q{Unsafe path '%{path}s': %{reason}s},
137        'admin.no_versions'   => q{No trashed version of '%{path}s' in repo '%{repo}s'},
138        'admin.bad_date'      => q{Bad --date '%{date}s' (want YYYY-MM-DD)},
139        'admin.no_version_on' => q{No version of '%{path}s' in the trash for %{date}s},
140        'admin.not_dir'       => 'Restore target %{path}s is not a directory',
141        'admin.exists'        => 'Refusing to overwrite %{path}s; move it aside first',
142
143        'server.missing'         => 'Server: no %{what}s given',
144        'server.bad_role'        => q{Server: bad role '%{role}s'},
145        'server.bad_id'          => 'Server: %{reason}s',
146        'server.no_connection'   => 'Server: no connection',
147        'server.locked'          => q{Another sync session holds the lock for repo '%{repo}s'},
148        'server.unknown_error'   => 'unknown server error',
149        'server.not_allowed'     => q{Client '%{client}s' is not allowed on repo '%{repo}s'},
150        'server.wrong_role'      => q{Client '%{client}s' is registered as '%{registered}s', not '%{asked}s'},
151        'server.proto'           => 'Unsupported protocol version',
152        'server.pinned'          => q{Session is pinned to %{field}s '%{expected}s' but the client asked for '%{given}s'},
153        'server.unknown'         => q{Unknown command '%{command}s'},
154        'server.manifest_list'   => 'Manifest is not a list',
155        'server.manifest_entry'  => 'Manifest entry is not an object',
156        'server.manifest_path'   => 'Manifest path rejected: %{reason}s',
157        'server.manifest_field'  => q{Bad manifest field '%{field}s' for %{path}s},
158        'server.refused'         => '%{reason}s',
159        'server.op.read'         => 'Read',
160        'server.op.write'        => 'Write',
161        'server.op.delta'        => 'Delta write',
162        'server.op.pull'         => 'Signature upload',
163        'server.op.mkdir'        => 'Directory creation',
164        'server.op.delete'       => 'Deletion',
165        'server.op.ack'          => 'Ack',
166        'server.unplanned'       => q{%{what}s of unplanned path '%{path}s'},
167        'server.not_planned'     => q{%{what}s of '%{path}s' is not in the plan},
168        'server.bad_field'       => q{Bad '%{field}s' for '%{path}s'},
169        'server.conflict_name'   => q{Conflict copy of '%{path}s' must be named '%{expected}s'},
170        'server.no_put'          => q{Data for '%{path}s' without a put},
171        'server.too_large'       => q{Chunk for '%{path}s' is too large},
172        'server.bad_copy'        => q{Delta copy outside '%{path}s'},
173        'server.bad_signature'   => q{Bad signature for '%{path}s'},
174        'server.no_signature'    => q{Delta read for '%{path}s' without a signature},
175        'server.no_delta'        => q{Delta data for '%{path}s' without a delta},
176        'server.bad_ack'         => q{Ack for '%{path}s' does not match its planned action},
177        'server.conflict_unsafe' => 'Unsafe conflict name: %{reason}s',
178        'server.conflict_same'   => q{Conflict name for '%{path}s' is the same as the path},
179        'server.conflict_exists' => 'Conflict copy already exists: %{path}s',
180        'server.conflict_move'   => 'Cannot preserve %{path}s as %{to}s: %{error}s',
181        'server.unfinished'      => 'Session ended before all actions completed: %{paths}s',
182        'server.busy'            => q{Already receiving '%{path}s'},
183        'server.overflow'        => q{Upload of '%{path}s' is larger than announced},
184        'server.hash_mismatch'   => q{Hash mismatch for '%{path}s': expected %{expected}s, got %{got}s},
185        'server.size_mismatch'   => q{Size mismatch for '%{path}s': expected %{expected}s, got %{got}s},
186        'server.cannot_stat'     => 'Cannot stat %{path}s: %{error}s',
187        'server.not_file'        => q{Cannot send a directory for '%{path}s'},
188
189        'forced.program'  => q{unexpected program '%{program}s' in the remote command},
190        'forced.argument' => q{unexpected argument '%{token}s' in the remote command},
191        'forced.no_value' => 'the remote command gives --%{flag}s without a value',
192        'forced.flag'     => 'the remote command may not set --%{flag}s',
193        'forced.proto'    => q{the remote command asks for protocol '%{proto}s'},
194        'forced.pinned'   => q{the remote command asks for %{field}s '%{value}s' but this key is pinned to '%{expected}s'},
195
196        'client.no_config'        => 'Client: no config',
197        'client.bad_name'         => 'Client: %{reason}s',
198        'client.no_repo'          => q{No repo '%{repo}s' in %{path}s},
199        'client.bad_root'         => q{Sync root for '%{repo}s' is not a directory: %{root}s},
200        'client.no_marker'        => 'Sync root %{root}s has no .filesync-root marker (unmounted drive?); refusing to sync',
201        'client.locked'           => q{Another filesync run holds the lock for '%{repo}s'},
202        'client.no_client_id'     => 'No client_id in the client configuration',
203        'client.refused'          => 'Server refused the session: %{reason}s',
204        'client.unknown_reason'   => 'unknown error',
205        'client.skipped'          => '%{path}s: skipped (%{reason}s)',
206        'client.verbose_action'   => '  %{verb}s %{path}s',
207        'client.unknown_action'   => q{Unknown action '%{action}s' for %{path}s},
208        'client.req.plan'         => '%{reason}s',
209        'client.req.end'          => 'Server did not accept the end of the session: %{reason}s',
210        'client.req.manifest'     => 'Server rejected the manifest: %{reason}s',
211        'client.req.delete'       => 'Cannot delete %{path}s on the server: %{reason}s',
212        'client.req.ack_delete'   => 'Server did not accept the deletion of %{path}s: %{reason}s',
213        'client.req.ack_dir'      => 'Server did not accept directory %{path}s: %{reason}s',
214        'client.req.ack'          => 'Server did not accept %{path}s: %{reason}s',
215        'client.req.get'          => 'Cannot read %{path}s from the server: %{reason}s',
216        'client.req.mkdir'        => 'Cannot create directory %{path}s on the server: %{reason}s',
217        'client.req.put'          => 'Server refused %{path}s: %{reason}s',
218        'client.req.chunk'        => 'Server rejected data for %{path}s: %{reason}s',
219        'client.req.store'        => 'Cannot store %{path}s on the server: %{reason}s',
220        'client.req.signature'    => 'Server refused the signature for %{path}s: %{reason}s',
221        'client.req.delta'        => 'Server refused the delta for %{path}s: %{reason}s',
222        'client.req.delta_data'   => 'Server rejected delta data for %{path}s: %{reason}s',
223        'client.hash_mismatch'    => 'Hash mismatch while copying %{path}s: expected %{expected}s, got %{got}s',
224        'client.size_mismatch'    => 'Size mismatch while copying %{path}s: expected %{expected}s, got %{got}s',
225        'client.bad_copy'         => 'Bad copy instruction for %{path}s',
226        'client.bad_op'           => 'Unknown delta instruction for %{path}s',
227        'client.conflict_exists'  => 'Conflict copy already exists: %{path}s',
228        'client.conflict_move'    => 'Cannot preserve %{path}s as %{to}s: %{error}s',
229        'client.unsafe'           => q{Unsafe path '%{path}s': %{reason}s},
230        'client.cannot_stat'      => 'Cannot stat %{path}s: %{error}s',
231        'client.need_server_root' => 'Repo %{repo}s needs a server_root for the local transport',
232        'client.need_server'      => 'Repo %{repo}s needs a server (user@host) for the ssh transport',
233        'client.bad_transport'    => q{Unknown transport '%{transport}s' for repo %{repo}s},
234        'client.record_failed'    => 'cannot record this run in %{path}s: %{error}s',
235        'client.no_versions'      => q{No trashed version of '%{path}s' for repo '%{repo}s' in %{trash}s},
236        'client.not_dir'          => 'Restore target %{path}s is not a directory',
237        'client.exists'           => 'Refusing to overwrite %{path}s; move it aside or use --to DIR',
238        'client.not_replica'      => q{Repo '%{repo}s' is a client, not a replica; only a replica keeps snapshots},
239
240        'transport.missing'   => '%{transport}s transport: no %{what}s given',
241        'transport.bad_value' => q{SSH transport: bad %{field}s '%{value}s'},
242        'transport.bad_id'    => 'SSH transport: %{reason}s',
243
244        'cli.help.client' => <<'USAGE',
245filesync - keep a directory in step with a master copy
246
247    filesync init --repo NAME --root DIR --server USER@HOST [--remote-repo NAME]
248                  [--id ID] [--role client|replica] [--port N] [--identity FILE]
249                  [--accept-host-key] [--known-hosts FILE] [--server-command PATH]
250                  [--snapshot-mode hardlink|copy]
251    filesync init --repo NAME --root DIR --transport local --server-root DIR
252                  [--remote-repo NAME] [--id ID] [--role client|replica]
253    filesync sync   [--repo NAME]... [--dry-run] [--force] [--verbose] [--quiet]
254                    [--json] [--no-prune] [--no-delta]
255    filesync status [--repo NAME] [--json]
256    filesync log    [--repo NAME] [-n N] [--since YYYY-MM-DD|EPOCH]
257                    [--until YYYY-MM-DD|EPOCH] [--exit N]... [--warnings] [--json]
258    filesync settings [--config FILE] [--json]
259    filesync verify [--repo NAME] [--deep] [--json]
260    filesync restore PATH [--repo NAME] [--to DIR] [--list]
261    filesync snapshot [--repo NAME] [--keep N]
262    filesync snapshot list [--repo NAME]
263    filesync snapshot restore DATE [PATH] [--repo NAME] [--to DIR]
264    filesync version
265
266The sync root must contain the .filesync-root marker created by "filesync init".
267Diagnostics go to stderr; settings are read from ~/.conf/app-filesync.json or
268$FILESYNC_SETTINGS (log_level, log_format, log_file, ssh_identity,
269ssh_known_hosts, server_command).  "filesync settings" prints the effective
270values and where each came from.  Per-repo values from "filesync init" win;
271port and host_key_checking exist per repo only and are marked [repo only].
272
273Exit codes: 0 ok, 1 fatal, 2 another run holds the lock, 3 completed with
274warnings, 4 verification found drift.
275USAGE
276        'cli.help.admin' => <<'USAGE',
277filesync-admin --root DIR <command>
278
279    repo create NAME [--trash-days N] [--max-deletes N] [--max-delete-percent N]
280                     [--ignore PATTERN]...
281    repo list
282    repo show NAME
283    client allow ID --repo NAME [--role client|replica]
284    client list --repo NAME
285    client forget ID --repo NAME
286    reindex NAME [--dry-run] [--json]
287    verify NAME [--deep] [--sample N] [--json]
288    restore NAME PATH [--to DIR] [--list] [--date YYYY-MM-DD]
289    log NAME... [-n N] [--client ID] [--since YYYY-MM-DD|EPOCH]
290                  [--until YYYY-MM-DD|EPOCH] [--exit N]... [--warnings] [--json]
291
292Exit codes: 0 ok, 1 fatal, 4 verification found drift.
293USAGE
294
295        'cli.unknown_command'  => q{Unknown command '%{command}s' (try: %{program}s help)},
296        'cli.usage'            => 'Usage: %{usage}s',
297        'cli.unexpected'       => '%{command}s: unexpected arguments: %{args}s',
298        'cli.required'         => '%{command}s: %{what}s is required',
299        'cli.positive'         => '%{command}s: %{option}s must be positive',
300        'cli.exit_range'       => 'log: --exit must be between 0 and %{max}d',
301        'cli.no_repos'         => 'No repos configured; run filesync init first',
302        'cli.no_repo'          => q{No repo '%{repo}s' in the configuration},
303        'cli.need_repo'        => '%{command}s: --repo is required when several repos are configured',
304        'cli.unknown_snapshot' => q{Unknown snapshot command '%{verb}s' (try: filesync help)},
305        'cli.repo_error'       => '%{repo}s: %{error}s',
306        'cli.warning'          => '  warning: %{warning}s',
307        'cli.never'            => 'never',
308        'cli.version'          => 'filesync %{version}s (protocol %{proto}d)',
309
310        'cli.usage.server'           => 'filesync-server [--root DIR] --repo NAME --client ID --role client|replica [--proto 2]',
311        'cli.usage.init'             => 'filesync init --repo NAME --root DIR ...',
312        'cli.usage.sync'             => 'filesync sync [--repo NAME] [--dry-run] [--force]',
313        'cli.usage.status'           => 'filesync status [--repo NAME] [--json]',
314        'cli.usage.log'              => 'filesync log [--repo NAME] [-n N] [--since DATE] [--until DATE] [--exit N] [--warnings] [--json]',
315        'cli.usage.settings'         => 'filesync settings [--config FILE] [--json]',
316        'cli.usage.verify'           => 'filesync verify [--repo NAME] [--deep] [--json]',
317        'cli.usage.restore'          => 'filesync restore PATH [--repo NAME] [--to DIR] [--list]',
318        'cli.usage.snapshot'         => 'filesync snapshot [--repo NAME] [--keep N]',
319        'cli.usage.snapshot_list'    => 'filesync snapshot list [--repo NAME]',
320        'cli.usage.snapshot_restore' => 'filesync snapshot restore DATE [PATH] [--repo NAME] [--to DIR]',
321        'cli.usage.repo_create'      => 'filesync-admin repo create NAME [--trash-days N] ...',
322        'cli.usage.admin_log'        => 'filesync-admin log NAME... [-n N] [--client ID] [--since DATE] [--until DATE] [--exit N] [--warnings] [--json]',
323        'cli.usage.reindex'          => 'filesync-admin reindex NAME [--dry-run] [--json]',
324        'cli.usage.admin_verify'     => 'filesync-admin verify NAME [--deep] [--sample N] [--json]',
325        'cli.usage.admin_restore'    => 'filesync-admin restore NAME PATH [--to DIR] [--list] [--date YYYY-MM-DD]',
326        'cli.usage.client_allow'     => 'filesync-admin client allow ID --repo NAME [--role R]',
327        'cli.usage.client_list'      => 'filesync-admin client list --repo NAME',
328        'cli.usage.client_forget'    => 'filesync-admin client forget ID --repo NAME',
329
330        'cli.server.bad_role' => q{filesync-server: bad role '%{role}s'},
331        'cli.server.proto'    => q{filesync-server: unsupported protocol '%{proto}s'},
332        'cli.server.forced'   => 'filesync-server: %{reason}s',
333        'cli.server.tty'      => 'filesync-server speaks the sync protocol on stdin and is not for interactive use; it is the forced command in authorized_keys',
334
335        'cli.init.bad_id'          => 'init: %{reason}s',
336        'cli.init.bad_role'        => q{init: bad role '%{role}s'},
337        'cli.init.bad_mode'        => q{init: bad snapshot mode '%{mode}s' (want hardlink or copy)},
338        'cli.init.bad_transport'   => q{init: unknown transport '%{transport}s'},
339        'cli.init.need_server_root' => 'init: the local transport needs --server-root',
340        'cli.init.need_server'     => 'init: the ssh transport needs --server',
341        'cli.init.bad_server'      => q{init: bad server '%{server}s' (want user@host or host)},
342        'cli.init.no_known_hosts'  => 'init: --known-hosts does not exist: %{path}s',
343        'cli.init.accept_ssh_only' => 'init: --accept-host-key only applies to the ssh transport',
344        'cli.init.bad_root'        => 'init: cannot use %{root}s as a sync root',
345        'cli.init.done'            => q{Initialised repo '%{repo}s'},
346        'cli.init.client_id'       => '  client id: %{id}s',
347        'cli.init.root'            => '  root:      %{root}s',
348        'cli.init.transport'       => '  transport: %{transport}s',
349        'cli.init.server'          => '  server:    %{server}s',
350        'cli.init.host_key_tofu'   => '  host key:  accept-new (trusted on first use)',
351        'cli.init.host_key_strict' => '  host key:  strict',
352        'cli.init.config'          => '  config:    %{path}s',
353
354        'cli.sync.would'    => '  would %{verb}s %{path}s',
355        'cli.sync.summary'  => '%{repo}s%{dry}s: pulled %{pulled}d, pushed %{pushed}d, deleted %{deleted}d, conflicts %{conflicts}d',
356        'cli.sync.dry_tag'  => ' (dry run)',
357        'cli.sync.transfer' => '  transfer: %{report}s',
358
359        'cli.transfer.report' => 'sent %{sent}s, received %{received}s, %{files}s by delta%{detail}s',
360        'cli.transfer.pulled' => '%{count}d pulled',
361        'cli.transfer.pushed' => '%{count}d pushed',
362        'cli.size.bytes'      => '%{value}d B',
363        'cli.size.scaled'     => '%{value}.1f %{unit}s',
364        'cli.size.exact'      => '%{value}s B',
365
366        'cli.status.repo'      => '%{repo}s: %{root}s',
367        'cli.status.transport' => '  transport: %{transport}s',
368        'cli.status.last_run'  => '  last run:  %{last_run}s',
369        'cli.status.transfer'  => '  transfer:  %{report}s',
370        'cli.status.files'     => '  files:     %{files}d',
371
372        'cli.log.none'      => '%{repo}s: no runs recorded',
373        'cli.log.error'     => '%{repo}s  %{ts}s  exit %{exit}d  %{message}s',
374        'cli.log.run'       => '%{repo}s  %{ts}s  exit %{exit}d  pulled %{pulled}d, pushed %{pushed}d, deleted %{deleted}d, conflicts %{conflicts}d%{skipped}s%{transfer}s%{dry}s',
375        'cli.log.skipped'   => ', skipped %{count}d',
376        'cli.log.dry_tag'   => '  (dry run)',
377        'cli.log.heading'   => '%{repo}s:',
378        'cli.log.no_events' => 'No journal entries for %{repo}s',
379        'cli.log.event'     => '%{indent}s%{ts}s  %{client}-12s %{action}-12s %{detail}s',
380
381        'cli.settings.file'           => 'settings file: %{file}s',
382        'cli.settings.no_file'        => '(none)',
383        'cli.settings.row'            => '  %{key}-16s %{value}-40s %{source}s',
384        'cli.settings.note'           => "An empty ssh_identity or ssh_known_hosts means ssh's own default; an empty server_command means filesync-server.\nIn the repo sections, [repo only] marks port and host_key_checking, which have no process-wide default.",
385        'cli.settings.repos'          => 'repos:',
386        'cli.settings.repo'           => '  %{repo}s (%{transport}s%{server}s)',
387        'cli.settings.local'          => '    the local transport does not use the SSH settings',
388        'cli.settings.repo_row'       => '    %{key}-18s %{value}-38s %{source}s',
389        'cli.settings.stderr'         => '(stderr)',
390        'cli.settings.ssh_default'    => '(ssh default)',
391        'cli.settings.server_default' => 'filesync-server',
392        'cli.source.default'          => '%{label}s',
393        'cli.source.merged'           => 'merged: %{label}s',
394        'cli.source.env'              => 'environment %{label}s',
395        'cli.source.file'             => 'file %{label}s',
396        'cli.repo_source.repo'        => 'repo (%{label}s)',
397        'cli.repo_source.process'     => 'process (%{label}s)',
398        'cli.repo_source.default'     => '%{label}s',
399        'cli.source.repo_only'        => '%{description}s [repo only]',
400
401        'cli.verify.summary'  => '%{repo}s: %{state}s (%{files}s, %{rehashed}d rehashed, %{trusted}d unchanged)',
402        'cli.verify.clean'    => 'clean',
403        'cli.verify.drift'    => 'drift detected',
404        'cli.verify.no_base'  => '  no cached base for this repo (it has not synced yet)',
405        'cli.verify.modified' => '  modified: %{path}s%{reason}s',
406        'cli.verify.missing'  => '  missing:  %{path}s',
407        'cli.verify.extra'    => '  extra:    %{path}s',
408
409        'cli.restore.no_versions'    => q{No trashed versions of '%{path}s'},
410        'cli.restore.no_versions_in' => q{No trashed versions of '%{path}s' in %{repo}s},
411        'cli.restore.version'        => '%{date}-12s %{size}10s  %{mtime}s  %{path}s',
412        'cli.restore.done'           => 'Restored %{path}s to %{to}s',
413        'cli.restore.admin_done'     => 'Restored %{repo}s:%{path}s from %{from}s to %{to}s',
414        'cli.restore.the_trash'      => 'the trash',
415
416        'cli.snapshot.exists'       => '%{repo}s: snapshot %{date}s already exists; left as it was',
417        'cli.snapshot.taken'        => '%{repo}s: snapshot %{date}s taken (%{files}s, %{size}s) in %{path}s',
418        'cli.snapshot.pruned'       => {
419                _by   => 'count',
420                one   => '%{repo}s: pruned %{count}d old snapshot (kept %{kept}d): %{dates}s',
421                other => '%{repo}s: pruned %{count}d old snapshots (kept %{kept}d): %{dates}s',
422        },
423        'cli.snapshot.none'         => 'No snapshots for %{repo}s',
424        'cli.snapshot.header'       => '%{date}-12s %{files}8s %{size}10s  %{path}s',
425        'cli.snapshot.column.date'  => 'DATE',
426        'cli.snapshot.column.files' => 'FILES',
427        'cli.snapshot.column.size'  => 'SIZE',
428        'cli.snapshot.column.path'  => 'PATH',
429        'cli.snapshot.row'          => '%{date}-12s %{files}8d %{size}10s  %{path}s',
430        'cli.snapshot.restored'     => '%{repo}s: restored %{what}s from snapshot %{date}s (%{files}s, %{size}s) to %{to}s',
431        'cli.snapshot.whole_tree'   => 'the whole tree',
432        'cli.snapshot.into_root'    => 'note: a replica mirrors the master again on the next sync; use --to DIR to keep an exported copy',
433
434        'cli.admin.root_value'   => 'filesync-admin: --root needs a value',
435        'cli.admin.unknown_verb' => q{Unknown %{group}s command '%{verb}s'},
436        'cli.admin.empty_name'   => 'log: NAME must not be empty',
437
438        'cli.repo.created.name'   => q{Created repo '%{repo}s'},
439        'cli.repo.created.master' => '  master: %{master}s',
440        'cli.repo.created.config' => '  config: %{config}s',
441        'cli.repo.none'           => 'No repos under %{root}s',
442        'cli.repo.no_clients'     => '(none)',
443        'cli.repo.show'           => "name:    %{name}s\nmaster:  %{master}s\nmeta:    %{meta}s\ntrash:   %{trash_days}s days\nlimits:  %{max_deletes}s files / %{max_delete_percent}s%%\nclients: %{clients}s",
444
445        'cli.reindex.would'   => '%{repo}s: would index %{files}s, %{dirs}s (%{size}s); index unchanged',
446        'cli.reindex.done'    => '%{repo}s: indexed %{files}s, %{dirs}s (%{size}s); master index written',
447        'cli.reindex.skipped' => '  skipped: %{path}s (%{reason}s)',
448
449        'cli.client.allowed' => 'Allowed %{client}s on %{repo}s as %{role}s',
450        'cli.client.none'    => 'No clients registered for %{repo}s',
451        'cli.client.row'     => '%{client}-24s %{role}-8s %{state}s',
452        'cli.client.synced'  => 'has synced',
453        'cli.client.never'   => 'never synced',
454        'cli.client.forgot'  => 'Forgot %{client}s (removed %{path}s)',
455        'cli.client.nothing' => 'No stored state for %{client}s',
456
457        'settings.bad_level' => q{Invalid log_level '%{level}s' (want %{valid}s)},
458
459        'snapshot.no_root'     => 'Snapshot: no sync root given',
460        'snapshot.not_dir'     => 'Snapshot: %{path}s is not a directory',
461        'snapshot.bad_date'    => q{Snapshot: bad date '%{date}s' (want YYYY-MM-DD)},
462        'snapshot.bad_mode'    => q{Snapshot: bad mode '%{mode}s' (want hardlink or copy)},
463        'snapshot.read'        => 'Snapshot: cannot read %{path}s: %{error}s',
464        'snapshot.failed'      => 'Snapshot: cannot create %{path}s: %{error}s',
465        'snapshot.remove'      => 'Snapshot: cannot remove %{path}s (%{error}s)',
466        'snapshot.need_date'   => 'Snapshot: --date is required',
467        'snapshot.none'        => 'Snapshot: no snapshot for %{date}s under %{path}s',
468        'snapshot.need_to'     => 'Snapshot: no destination given',
469        'snapshot.to_not_dir'  => 'Snapshot: destination %{path}s is not a directory',
470        'snapshot.unsafe'      => q{Unsafe snapshot path '%{path}s': %{reason}s},
471        'snapshot.no_path'     => q{Snapshot %{date}s has no path '%{path}s'},
472        'snapshot.cannot_stat' => 'Snapshot: cannot stat %{path}s: %{error}s',
473        'snapshot.not_regular' => 'Snapshot: %{path}s is not a regular file',
474        'snapshot.replace'     => 'Snapshot: cannot replace %{path}s',
475);
476
4771;
478