diff --git a/kirby/config/api/routes/changes.php b/kirby/config/api/routes/changes.php new file mode 100644 index 0000000..2e35754 --- /dev/null +++ b/kirby/config/api/routes/changes.php @@ -0,0 +1,37 @@ + '(:all)/changes/discard', + 'method' => 'POST', + 'action' => function (string $path) { + return Changes::discard( + model: Find::parent($path), + ); + } + ], + [ + 'pattern' => '(:all)/changes/publish', + 'method' => 'POST', + 'action' => function (string $path) { + return Changes::publish( + model: Find::parent($path), + input: App::instance()->request()->get() + ); + } + ], + [ + 'pattern' => '(:all)/changes/save', + 'method' => 'POST', + 'action' => function (string $path) { + return Changes::save( + model: Find::parent($path), + input: App::instance()->request()->get() + ); + } + ], +]; diff --git a/kirby/config/areas/account/buttons.php b/kirby/config/areas/account/buttons.php new file mode 100644 index 0000000..263ef36 --- /dev/null +++ b/kirby/config/areas/account/buttons.php @@ -0,0 +1,13 @@ + function (App $kirby, User $user) { + if ($kirby->user()->is($user) === true) { + return new ViewButton(component: 'k-theme-view-button'); + } + } +]; diff --git a/kirby/config/areas/files/buttons.php b/kirby/config/areas/files/buttons.php new file mode 100644 index 0000000..b2d5028 --- /dev/null +++ b/kirby/config/areas/files/buttons.php @@ -0,0 +1,14 @@ + function (File $file) { + return new OpenButton(link: $file->previewUrl()); + }, + 'file.settings' => function (File $file) { + return new SettingsButton(model: $file); + } +]; diff --git a/kirby/config/areas/languages/buttons.php b/kirby/config/areas/languages/buttons.php new file mode 100644 index 0000000..d0227e4 --- /dev/null +++ b/kirby/config/areas/languages/buttons.php @@ -0,0 +1,21 @@ + fn () => + new LanguageCreateButton(), + 'language.open' => fn (Language $language) => + new OpenButton(link: $language->url()), + 'language.settings' => fn (Language $language) => + new LanguageSettingsButton($language), + 'language.delete' => function (Language $language) { + if ($language->isDeletable() === true) { + return new LanguageDeleteButton($language); + } + } +]; diff --git a/kirby/config/areas/site/buttons.php b/kirby/config/areas/site/buttons.php new file mode 100644 index 0000000..816c441 --- /dev/null +++ b/kirby/config/areas/site/buttons.php @@ -0,0 +1,72 @@ + function (Site $site, string $versionId = 'latest') { + $versionId = $versionId === 'compare' ? 'changes' : $versionId; + $link = $site->previewUrl($versionId); + + if ($link !== null) { + return new OpenButton( + link: $link, + ); + } + }, + 'site.preview' => function (Site $site) { + if ($site->previewUrl() !== null) { + return new PreviewButton( + link: $site->panel()->url(true) . '/preview/changes', + ); + } + }, + 'site.versions' => function (Site $site, string $versionId = 'latest') { + return new VersionsButton( + model: $site, + versionId: $versionId + ); + }, + 'page.open' => function (Page $page, string $versionId = 'latest') { + $versionId = $versionId === 'compare' ? 'changes' : $versionId; + $link = $page->previewUrl($versionId); + + if ($link !== null) { + return new OpenButton( + link: $link, + ); + } + }, + 'page.preview' => function (Page $page) { + if ($page->previewUrl() !== null) { + return new PreviewButton( + link: $page->panel()->url(true) . '/preview/changes', + ); + } + }, + 'page.versions' => function (Page $page, string $versionId = 'latest') { + return new VersionsButton( + model: $page, + versionId: $versionId + ); + }, + 'page.settings' => fn (Page $page) => new SettingsButton(model: $page), + 'page.status' => fn (Page $page) => new PageStatusButton($page), + + // `languages` button needs to be in site area, + // as the languages might be not loaded even in + // multilang mode when the `languages` option is deactivated + // (but content languages to switch between still can exist) + 'languages' => fn (ModelWithContent $model) => + new LanguagesDropdown($model), + + // file buttons + ...require __DIR__ . '/../files/buttons.php' +]; diff --git a/kirby/config/areas/users/buttons.php b/kirby/config/areas/users/buttons.php new file mode 100644 index 0000000..f6fa067 --- /dev/null +++ b/kirby/config/areas/users/buttons.php @@ -0,0 +1,20 @@ + function (User $user, string|null $role = null) { + return new ViewButton( + dialog: 'users/create?role=' . $role, + disabled: $user->kirby()->roles()->canBeCreated()->count() < 1, + icon: 'add', + text: I18n::translate('user.create'), + ); + }, + 'user.settings' => function (User $user) { + return new SettingsButton(model: $user); + } +]; diff --git a/kirby/config/sections/mixins/batch.php b/kirby/config/sections/mixins/batch.php new file mode 100644 index 0000000..25128f2 --- /dev/null +++ b/kirby/config/sections/mixins/batch.php @@ -0,0 +1,45 @@ + [ + /** + * Activates the batch delete option for the section + */ + 'batch' => function (bool $batch = false) { + return $batch; + }, + ], + 'methods' => [ + 'deleteSelected' => function (array $ids): bool { + if ($ids === []) { + return true; + } + + // check if batch deletion is allowed + if ($this->batch() === false) { + throw new PermissionException( + message: 'The section does not support batch actions' + ); + } + + $min = $this->min(); + + // check if the section has enough items after the deletion + if ($this->total() - count($ids) < $min) { + throw new Exception( + message: I18n::template('error.section.' . $this->type() . '.min.' . I18n::form($min), [ + 'min' => $min, + 'section' => $this->headline() + ]) + ); + } + + $this->models()->delete($ids); + return true; + } + ] +]; diff --git a/kirby/i18n/translations/bs.json b/kirby/i18n/translations/bs.json new file mode 100644 index 0000000..5d44fbe --- /dev/null +++ b/kirby/i18n/translations/bs.json @@ -0,0 +1,799 @@ +{ + "account.changeName": "Promijeni svoje ime", + "account.delete": "Obriši svoj račun", + "account.delete.confirm": "Da li stvarno želite obrisati svoj račun? Odmah ćete biti odjavljeni. Vaš račun neće biti moguće oporaviti.", + + "activate": "Aktiviraj", + "add": "Dodaj", + "alpha": "Alpha", + "author": "Autor", + "avatar": "Profilna slika", + "back": "Natrag", + "cancel": "Odustani", + "change": "Promijeni", + "close": "Zatvori", + "changes": "Promjene", + "confirm": "Ok", + "collapse": "Skupi", + "collapse.all": "Skupi sve", + "color": "Boja", + "coordinates": "Koordinate", + "copy": "Kopiraj", + "copy.all": "Kopiraj sve", + "copy.success": "Kopirano", + "copy.success.multiple": "{count} kopirano!", + "copy.url": "Kopiraj URL", + "create": "Kreiraj", + "custom": "Prilagođeno", + + "date": "Datum", + "date.select": "Odaberi datum", + + "day": "Dan", + "days.fri": "Pet", + "days.mon": "Pon", + "days.sat": "Sub", + "days.sun": "Ned", + "days.thu": "Čet", + "days.tue": "Uto", + "days.wed": "Sri", + + "debugging": "Debugiranje", + + "delete": "Obriši", + "delete.all": "Obriši sve", + + "dialog.fields.empty": "Ovaj dijalog nema polja", + "dialog.files.empty": "Nema datoteka za odabir", + "dialog.pages.empty": "Nema stranica za odabir", + "dialog.text.empty": "Ovaj dijalog ne definira nikakav tekst", + "dialog.users.empty": "Nema korisnika za odabir", + + "dimensions": "Dimenzije", + "disable": "Onemogući", + "disabled": "Onemogućeno", + "discard": "Odbaci", + + "drawer.fields.empty": "Ova ladica nema polja", + + "domain": "Domena", + "download": "Download", + "duplicate": "Dupliciraj", + + "edit": "Uredi", + + "email": "Email", + "email.placeholder": "mail@example.com", + + "enter": "Enter", + "entries": "Unosi", + "entry": "Unos", + + "environment": "Okruženje", + + "error": "Greška", + "error.access.code": "Nevažeći kod", + "error.access.login": "Nevažeći login", + "error.access.panel": "Pristup panelu nije dozvoljen", + "error.access.view": "Pristup ovom dijelu panela nije dozvoljen", + + "error.avatar.create.fail": "Profilnu sliku nije moguće spremiti", + "error.avatar.delete.fail": "Profilna slika se ne može obrisati", + "error.avatar.dimensions.invalid": "Nevažeće dimenzije. Promijenite visinu i širinu profilne slike ispod 3000 piksela", + "error.avatar.mime.forbidden": "Profilna slika mora biti u JPEG ili PNG formatu", + + "error.blueprint.notFound": "Blueprint \"{name}\" nije pronađen", + + "error.blocks.max.plural": "Ne smijete dodati više od {max} blokova", + "error.blocks.max.singular": "Ne smijete dodati više od jednog bloka", + "error.blocks.min.plural": "Morate dodati najmanje {min} blokova", + "error.blocks.min.singular": "Morate dodati najmanje jedan blok", + "error.blocks.validation": "Postoji greška kod \"{field}\" polja, u bloku {index}, pri korištenju bloka tipa \"{fieldset}\" ", + + "error.cache.type.invalid": "Nevažeći tip za cache \"{type}\"", + + "error.content.lock.delete": "Ova verzija je zaključana i ne može se obrisati", + "error.content.lock.move": "Izvorna verzija je zaključana i ne može se premjestiti", + "error.content.lock.publish": "Ova verzija je već objavljena", + "error.content.lock.replace": "Ova verzija je zaključana i ne može se zamijeniti", + "error.content.lock.update": "Ova verzija je zaključana i ne može se urediti", + + "error.entries.max.plural": "Ne smijete dodati više od {max} unosa", + "error.entries.max.singular": "Ne smijete dodati više od jednog unosa", + "error.entries.min.plural": "Morate dodati najmanje {min} unosa", + "error.entries.min.singular": "Morate dodati najmanje jedan unos", + "error.entries.supports": "\"{type}\" tip polja nije podržan za polje unosa", + "error.entries.validation": "Postoji greška na \"{field}\" polju u redu {index}", + + "error.email.preset.notFound": "Email preset \"{name}\" nije pronađen", + + "error.field.converter.invalid": "Nevažeći Converter \"{converter}\"", + "error.field.link.options": "Nevažeće opcije: {options}", + "error.field.type.missing": "Polje \"{name}\": Tip polja \"{type}\" ne postoji", + + "error.file.changeName.empty": "Naziv ne smije biti prazan", + "error.file.changeName.permission": "Nemate dozvolu da promijenite naziv datoteke \"{filename}\"", + "error.file.changeTemplate.invalid": "Predložak za datoteku \"{id}\" se ne može promijeniti u \"{template}\" (dozvoljeno: \"{blueprints}\")", + "error.file.changeTemplate.permission": "Nemate dozvolu da promijenite predložak za datoteku \"{id}\"", + + "error.file.delete.multiple": "Nije bilo moguće obrisati sve datoteke. Pokušajte ih obrisati pojedinačno da bi vidjeli specifičnu grešku koja sprječava brisanje. ", + "error.file.duplicate": "Datoteka sa imenom \"{filename}\" već postoji", + "error.file.extension.forbidden": "Ekstenzija \"{extension}\" nije dozvoljena", + "error.file.extension.invalid": "Nevažeća ekstenzija: {extension}", + "error.file.extension.missing": "Ekstenzija za datoteku \"{filename}\" nedostaje", + "error.file.maxheight": "Visina slike ne smije prelaziti {height} piksela", + "error.file.maxsize": "Datoteka je prevelika", + "error.file.maxwidth": "Širina slike ne smije prelaziti {width} piksela", + "error.file.mime.differs": "Uploadana datoteka mora biti istog mime tipa \"{mime}\"", + "error.file.mime.forbidden": "Tip medija \"{mime}\" nije dozvoljen", + "error.file.mime.invalid": "Nevažeći mime tip: {mime}", + "error.file.mime.missing": "Tip medija za \"{filename}\" se ne može očitati", + "error.file.minheight": "Visina slike mora biti najmanje {height} piksela", + "error.file.minsize": "Datoteka je premala", + "error.file.minwidth": "Širina slike mora biti najmanje {height} piksela", + "error.file.name.unique": "Naziv datoteke mora biti jedinstven", + "error.file.name.missing": "Naziv datoteke ne smije biti prazan", + "error.file.notFound": "Datoteka \"{filename}\" nije pronađena", + "error.file.orientation": "Orijentacija slike mora biti \"{orientation}\"", + "error.file.sort.permission": "Nemate dozvolu da promijenite sortiranje od \"{filename}\"", + "error.file.type.forbidden": "Nije dozvoljen upload {type} datoteka", + "error.file.type.invalid": "Nevažeći tip datoteke: {type}", + "error.file.undefined": "Datoteka nije pronađena", + + "error.form.incomplete": "Popravi sve greške na formi...", + "error.form.notSaved": "Forma se ne može spremiti", + + "error.language.code": "Unesi važeći kod za jezik", + "error.language.create.permission": "Nemate dozvolu da kreirate jezik", + "error.language.delete.permission": "Nemate dozvolu da obrišete jezik", + "error.language.duplicate": "Jezik već postoji", + "error.language.name": "Unesi važeći naziv za jezik", + "error.language.notFound": "Jezik nije pronađen", + "error.language.update.permission": "Nemate dozvolu da ažurirate jezik", + + "error.layout.validation.block": "Postoji greška kod \"{field}\" polja, u bloku {blockIndex}, pri korištenju bloka tipa \"{fieldset}\" u rasporedu {layoutIndex}", + "error.layout.validation.settings": "Postoji greška u postavkama rasporeda {index}", + + "error.license.domain": "Domena za licencu nedostaje", + "error.license.email": "Unesite važeću email adresu", + "error.license.format": "Unesite važeću licencu", + "error.license.verification": "Licenca se ne može verificirati", + + "error.login.totp.confirm.invalid": "Nevažeći kod", + "error.login.totp.confirm.missing": "Unesi trenutni kod", + + "error.object.validation": "Postoji greška u \"{label}\" polju:\n{message}", + + "error.offline": "Panel je trenutno offline", + + "error.page.changeSlug.permission": "Nemate dozvolu da promijenite URL nastavak za \"{slug}\"", + "error.page.changeSlug.reserved": "Putanja stranica najvišeg nivoa ne smije počinjati sa \"{path}\"", + "error.page.changeStatus.incomplete": "Stranica sadrži greške i ne može se objaviti", + "error.page.changeStatus.permission": "Status za ovu stranicu se ne može promijeniti", + "error.page.changeStatus.toDraft.invalid": "Stranica \"{slug}\" se ne može pretvoriti u skicu", + "error.page.changeTemplate.invalid": "Predložak za stranicu \"{slug}\" se ne može promijeniti", + "error.page.changeTemplate.permission": "Nemate dozvolu da promijenite predložak za \"{slug}\"", + "error.page.changeTitle.empty": "Naslov ne može biti prazan", + "error.page.changeTitle.permission": "Nemate dozvolu da promijenite naslov za \"{slug}\"", + "error.page.create.permission": "Nemate dozvolu da kreirate \"{slug}\"", + "error.page.delete": "Stranica \"{slug}\" se ne može obrisati", + "error.page.delete.confirm": "Unesite naslov stranice da potvrdite", + "error.page.delete.hasChildren": "Stranica sadrži podstranice i ne može se obrisati", + "error.page.delete.multiple": "Nije bilo moguće obrisati sve stranice. Pokušajte ih obrisati pojedinačno da bi vidjeli specifičnu grešku koja sprječava brisanje. ", + "error.page.delete.permission": "Nemate dozvolu da obrišete \"{slug}\"", + "error.page.draft.duplicate": "Skica stranice sa URL nastavkom \"{slug}\" već postoji", + "error.page.duplicate": "Stranica sa URL nastavkom \"{slug}\" već postoji", + "error.page.duplicate.permission": "Nemate dozvolu da duplicirate \"{slug}\"", + "error.page.move.ancestor": "Stranica se ne može premjestiti u samu sebe", + "error.page.move.directory": "Direktorij stranice se ne može premjestiti", + "error.page.move.duplicate": "Podstranica sa URL nastavkom \"{slug}\" već postoji", + "error.page.move.noSections": "Stranica \"{parent}\" ne može biti roditelj bilo koje podstranice jer ne sadrži sekciju \"pages\" u svom blueprintu", + "error.page.move.notFound": "Premještena stranica se ne može pronaći", + "error.page.move.permission": "Nemate dozvolu da premjestite \"{slug}\"", + "error.page.move.template": "Predložak \"{template}\" nije prihvaćen kao podstranica od \"{parent}\"", + "error.page.notFound": "Stranica \"{slug}\" nije pronađena", + "error.page.num.invalid": "Unesi važeći broj za sortiranje. Brojevi ne smiju biti negativni.", + "error.page.slug.invalid": "Unesi važeći URL prefiks", + "error.page.slug.maxlength": "Dužina URL nastavka mora biti manja od \"{length}\" znakova", + "error.page.sort.permission": "Stranica \"{slug}\" se ne može sortirati", + "error.page.status.invalid": "Odaberi važeći status stranice", + "error.page.undefined": "Stranica nije pronađena", + "error.page.update.permission": "Nemate dozvolu da uredite \"{slug}\"", + + "error.section.files.max.plural": "Nije moguće dodati više od {max} datoteka u \"{section}\" sekciju", + "error.section.files.max.singular": "Nije moguće dodati više od jedne datoteke u \"{section}\" sekciju", + "error.section.files.min.plural": "Sekcija \"{section}\" zahtjeva najmanje {min} datoteka", + "error.section.files.min.singular": "Sekcija \"{section}\" zahtjeva najmanje jednu datoteku", + + "error.section.pages.max.plural": "Nije moguće dodati više od {max} stranica u \"{section}\" sekciju", + "error.section.pages.max.singular": "Nije moguće dodati više od jedne stranice \"{section}\" sekciju", + "error.section.pages.min.plural": "Sekcija \"{section}\" zahtjeva najmanje {min} stranica", + "error.section.pages.min.singular": "Sekcija \"{section}\" zahtjeva najmanje jednu stranicu", + + "error.section.notLoaded": "Sekcija \"{name}\" se nije mogla učitati", + "error.section.type.invalid": "Tip sekcije \"{type}\" nije važeći", + + "error.site.changeTitle.empty": "The title must not be empty", + "error.site.changeTitle.permission": "Nemate dozvolu da promijenite naslov stranice", + "error.site.update.permission": "Nemate dozvolu da uredite stranicu", + + "error.structure.validation": "Postoji greška na \"{field}\" polju u redu {index}", + + "error.template.default.notFound": "Default predložak ne postoji", + + "error.unexpected": "Dogodila se neočekivana greška! Omogućite debug modus za više informacija: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Nemate dozvolu da promijenite email adresu korisnika \"{name}\"", + "error.user.changeLanguage.permission": "Nemate dozvolu da promijenite jezik korisnika \"{name}\"", + "error.user.changeName.permission": "Nemate dozvolu da promijenite ime korisnika \"{name}\"", + "error.user.changePassword.permission": "Nemate dozvolu da promijenite šifru korisnika \"{name}\"", + "error.user.changeRole.lastAdmin": "Uloga zadnjeg administratora se ne može promijeniti", + "error.user.changeRole.permission": "Nemate dozvolu da promijenite ulogu korisnika \"{name}\"", + "error.user.changeRole.toAdmin": "Nemate dozvolu da promijenite ulogu nekog korisnika u administratora", + "error.user.create.permission": "Nemate dozvolu da kreirate ovog korisnika", + "error.user.delete": "Korisnik \"{name}\" se ne može obrisati", + "error.user.delete.lastAdmin": "Zadnji administrator se ne može obrisati", + "error.user.delete.lastUser": "Zadnji korisnik se ne može obrisati", + "error.user.delete.permission": "Nemate dozvolu da obrišete korisnika \"{name}\"", + "error.user.duplicate": "Korisnik sa email adresom \"{email}\" već postoji", + "error.user.email.invalid": "Unesite važeću email adresu", + "error.user.language.invalid": "Unesi važeći jezik", + "error.user.notFound": "Korisnik \"{name}\" nije pronađen", + "error.user.password.excessive": "Unesite važeću šifru. Šifre ne smiju biti duže od 1000 znakova", + "error.user.password.invalid": "Unesi važeću šifru. Šifre moraju sadržavati najmanje 8 znakova.", + "error.user.password.notSame": "Šifre se ne podudaraju", + "error.user.password.undefined": "Korisnik nema šifru", + "error.user.password.wrong": "Kriva šifra", + "error.user.role.invalid": "Uloga je nevažeća", + "error.user.undefined": "Nije moguće pronaći korisnika", + "error.user.update.permission": "Nemate dozvolu da uredite korisnika \"{name}\"", + + "error.validation.accepted": "Potvrdi", + "error.validation.alpha": "Koristi samo znakove u rasponu a-z", + "error.validation.alphanum": "Koristi samo znakove u rasponu a-z ili brojeve 0-9", + "error.validation.anchor": "Unesite ispravan anker linka", + "error.validation.between": "Unesi vrijednost između \"{min}\" i \"{max}\"", + "error.validation.boolean": "Potvrdi ili otkaži", + "error.validation.color": "Unesite važeću boju u {format} formatu", + "error.validation.contains": "Unesi vrijednost koja sadrži \"{needle}\"", + "error.validation.date": "Unesi važeći datum", + "error.validation.date.after": "Unesi datum nakon {date}", + "error.validation.date.before": "Unesi datum prije {date}", + "error.validation.date.between": "Unesi datum između {min} i {max}", + "error.validation.denied": "Otkaži", + "error.validation.different": "Vrijednost ne može biti \"{other}\"", + "error.validation.email": "Unesite važeću email adresu", + "error.validation.endswith": "Vrijednost mora završavati sa \"{end}\"", + "error.validation.filename": "Unesi važeći naziv datoteke", + "error.validation.in": "Unesi jedno od slijedećeg: ({in})", + "error.validation.integer": "Unesi važeći cijeli broj", + "error.validation.ip": "Unesi važeću IP adresu", + "error.validation.less": "Unesi vrijednost manju od {max}", + "error.validation.linkType": "Tip linka nije dozvoljen", + "error.validation.match": "Vrijednost ne odgovara očekivanom uzorku", + "error.validation.max": "Unesi vrijednost jednaku ili manju od {max}", + "error.validation.maxlength": "Unesi kraću vrijednost. (max. {max} znakova)", + "error.validation.maxwords": "Unesi najviše {max} riječ(i)", + "error.validation.min": "Unesi vrijednost jednaku ili veću od {min}", + "error.validation.minlength": "Unesi dužu vrijednost. (min. {min} znakova)", + "error.validation.minwords": "Unesi najmanje {min} riječ(i)", + "error.validation.more": "Unesi veću vrijednost od {min}", + "error.validation.notcontains": "Unesi vrijednost koja NE sadrži \"{needle}\"", + "error.validation.notin": "Nemojte unositi bilo šta od slijedećeg: ({notIn})", + "error.validation.option": "Odaberite važeću opciju", + "error.validation.num": "Odaberite važeći broj", + "error.validation.required": "Unesi nešto", + "error.validation.same": "Unesi \"{other}\"", + "error.validation.size": "Dužina unosa mora biti \"{size}\"", + "error.validation.startswith": "Unos mora počinjati sa \"{start}\"", + "error.validation.tel": "Unesite neformatirani broj telefona", + "error.validation.time": "Unesi važeće vrijeme", + "error.validation.time.after": "Unesite vrijeme poslije {time}", + "error.validation.time.before": "Unesite vrijeme prije {time}", + "error.validation.time.between": "Unesite vrijeme između {min} i {max}", + "error.validation.uuid": "Unesite važeći UUID", + "error.validation.url": "Unesi važeći URL", + + "expand": "Proširi", + "expand.all": "Proširi sve", + + "field.invalid": "Polje je nevažeće", + "field.required": "Polje je obavezno", + "field.blocks.changeType": "Promijena tipa", + "field.blocks.code.name": "Kod", + "field.blocks.code.language": "Jezik", + "field.blocks.code.placeholder": "Vaš kod ...", + "field.blocks.delete.confirm": "Da li stvarno želite obrisati ovaj blok?", + "field.blocks.delete.confirm.all": "Da li stvarno želite obrisati sve blokove?", + "field.blocks.delete.confirm.selected": "Da li stvarno želite obrisati odabrane blokove?", + "field.blocks.empty": "Još nema blokova", + "field.blocks.fieldsets.empty": "Još nema skupova polja", + "field.blocks.fieldsets.label": "Odaberite tip bloka ...", + "field.blocks.fieldsets.paste": "Pritisnite {{ shortcut }} da uvezete rasporede/blokove iz vašeg međuspremnika.Samo oni dozvoljeni u trenutnom polju će biti umetnuti.", + "field.blocks.gallery.name": "Galerija", + "field.blocks.gallery.images.empty": "Još nema slika", + "field.blocks.gallery.images.label": "Slike", + "field.blocks.heading.level": "Nivo", + "field.blocks.heading.name": "Naslov", + "field.blocks.heading.text": "Tekst", + "field.blocks.heading.placeholder": "Naslov ...", + "field.blocks.figure.back.plain": "Obično", + "field.blocks.figure.back.pattern.light": "Uzorak (svijetlo)", + "field.blocks.figure.back.pattern.dark": "Uzorak (tamno)", + "field.blocks.image.alt": "Alternativni tekst", + "field.blocks.image.caption": "Natpis", + "field.blocks.image.crop": "Odreži", + "field.blocks.image.link": "Link", + "field.blocks.image.location": "Lokacija", + "field.blocks.image.location.internal": "Ova web stranica", + "field.blocks.image.location.external": "Eksterni izvor", + "field.blocks.image.name": "Slika", + "field.blocks.image.placeholder": "Odaberi sliku", + "field.blocks.image.ratio": "Omjer", + "field.blocks.image.url": "URL slike", + "field.blocks.line.name": "Linija", + "field.blocks.list.name": "Lista", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Tekst", + "field.blocks.markdown.placeholder": "Markdown ...", + "field.blocks.quote.name": "Citat", + "field.blocks.quote.text.label": "Tekst", + "field.blocks.quote.text.placeholder": "Citat ...", + "field.blocks.quote.citation.label": "Citiranje", + "field.blocks.quote.citation.placeholder": "po ...", + "field.blocks.text.name": "Tekst", + "field.blocks.text.placeholder": "Tekst ...", + "field.blocks.video.autoplay": "Automatski reproduciraj", + "field.blocks.video.caption": "Natpis", + "field.blocks.video.controls": "Kontrole", + "field.blocks.video.location": "Lokacija", + "field.blocks.video.loop": "Ponavljaj", + "field.blocks.video.muted": "Utišano", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Unesi video URL", + "field.blocks.video.poster": "Poster", + "field.blocks.video.preload": "Predučitavanje", + "field.blocks.video.url.label": "Video-URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.entries.delete.confirm.all": "Da li stvarno želite obrisati sve unose?", + "field.entries.empty": "Još nema unosa", + + "field.files.empty": "Niti jedna datoteka još nije odabrana", + "field.files.empty.single": "Datoteka još nije odabrana", + + "field.layout.change": "Promijeni raspored", + "field.layout.delete": "Obriši raspored", + "field.layout.delete.confirm": "Da li stvarno želite obrisati ovaj raspored?", + "field.layout.delete.confirm.all": "Da li stvarno želite obrisati sve rasporede?", + "field.layout.empty": "Još nema redova", + "field.layout.select": "Odaberi raspored", + + "field.object.empty": "Još nema informacija", + + "field.pages.empty": "Niti jedna stranica još nije odabrana", + "field.pages.empty.single": "Stranica još nije odabrana", + + "field.structure.delete.confirm": "Da li stvarno želite obrisati ovaj red?", + "field.structure.delete.confirm.all": "Da li stvarno želite obrisati sve unose?", + "field.structure.empty": "Još nema unosa", + + "field.users.empty": "Niti jedan korisnik još nije odabran", + "field.users.empty.single": "Korisnik još nije odabran", + + "fields.empty": "Još nema polja", + + "file": "Datoteka", + "file.blueprint": "Ovaj fajl još uvijek nema blueprint. Možete definirati postavke u /site/blueprints/files/{blueprint}.yml", + "file.changeTemplate": "Promijeni predložak", + "file.changeTemplate.notice": "Promjena predloška datoteke će ukloniti sadržaj za polja koja se ne podudaraju po tipu. Ako novi predložak definira određena pravila, npr. dimenzije slike, ona će se također nepovratno primijeniti. Koristite s oprezom.", + "file.delete.confirm": "Da li stvarno želite obrisati
{filename}?", + "file.focus.placeholder": "Postavi fokalnu tačku", + "file.focus.reset": "Ukloni fokalnu tačku", + "file.focus.title": "Fokus", + "file.sort": "Promijeni poziciju", + + "files": "Datoteke", + "files.delete.confirm.selected": "Da li stvarno želite da obrišete odabrane datoteke? Ova akcija se ne može poništiti.", + "files.empty": "Još nema datoteka...", + + "filter": "Filter", + + "form.discard": "Odbaci promjene", + "form.discard.confirm": "Da li stvarno želite odbaciti sve promjene?", + "form.locked": "Ovaj sadržaj je vama onemogućen jer ga trenutno uređuje drugi korisnik", + "form.unsaved": "Trenutne promjene još uvijek nisu spremljene", + "form.preview": "Pregledaj izmjene", + "form.preview.draft": "Pregledaj skicu", + + "hide": "Sakrij", + "hour": "Sat", + "hue": "Nijansa", + "import": "Uvoz", + "info": "Info", + "insert": "Umetni", + "insert.after": "Umetni nakon", + "insert.before": "Umetni prije", + "install": "Instaliraj", + + "installation": "Instalacija", + "installation.completed": "Panel je instaliran", + "installation.disabled": "Instaler za panel je onemogućen na javnim serverima po defaultu. Pokreni instaler na lokalnom okruženju ili omogući sa panel.install opcijom.", + "installation.issues.accounts": "Folder /site/accounts ne postoji ili nema dozvolu pisanja", + "installation.issues.content": "Folder /content ne postoji ili nema dozvolu pisanja", + "installation.issues.curl": "Ekstenzija CURL je neophodna", + "installation.issues.headline": "Panel se ne može instalirati", + "installation.issues.mbstring": "Ekstenzija MB String je neophodna", + "installation.issues.media": "Folder /media ne postoji ili nema dozvolu pisanja", + "installation.issues.php": "Obavezno koristite PHP 7+", + "installation.issues.sessions": "Folder /site/sessions ne postoji ili nema dozvolu pisanja", + + "language": "Jezik", + "language.code": "Kod", + "language.convert": "Postavi kao zadani", + "language.convert.confirm": "

Da li stvarno želite konvertirati {name} u zadani jezik? Ova akcija se ne može poništiti.

Ukoliko {name} sadrži dijelove bez prijevoda, neće postojati važeći fallback što može prouzrokovati prazne dijelove na ovoj stranici.

", + "language.create": "Dodaj novi jezik", + "language.default": "Zadani jezik", + "language.delete.confirm": "Da li stvarno želite obrisati jezik {name} including all translations? This cannot be undone!", + "language.deleted": "Jezik je obrisan", + "language.direction": "Smjer čitanja", + "language.direction.ltr": "Sa lijeva na desno", + "language.direction.rtl": "Sa desna na lijevo", + "language.locale": "PHP lokalizacijski string", + "language.locale.warning": "Sistem koristi prilagođenu lokalizaciju. Promijeni postavke u jezičnoj datoteci u /site/languages", + "language.name": "Naziv", + "language.secondary": "Sekundarni jezik", + "language.settings": "Postavke jezika", + "language.updated": "Jezik je izmijenjen", + "language.variables": "Jezične varijable", + "language.variables.empty": "Još nema prijevoda", + + "language.variable.delete.confirm": "Da li stvarno želite da obrišete varijablu za {key}?", + "language.variable.entries": "Values", + "language.variable.entries.help": "Each string will be used for its matching count, e.g. three strings will match in order to counts 0, 1, 2 and more. Use the {count} placeholder to insert the actual count.", + "language.variable.key": "Ključ", + "language.variable.multiple": "Countable?", + "language.variable.multiple.text": "Use different translation strings", + "language.variable.multiple.help": "You can use different values depending on a count you pass along with the language variable, allowing you to create dynamic translations, e.g. singular and plural.", + "language.variable.notFound": "Varijablu nije moguće pronaći", + "language.variable.value": "Vrijednost", + + "languages": "Jezici", + "languages.default": "Zadani jezik", + "languages.empty": "Jezici još nisu definirani", + "languages.secondary": "Sekundarni jezici", + "languages.secondary.empty": "Sekundarni jezici još nisu definirani", + + "license": "Licenca", + "license.activate": "Aktivirajte odmah", + "license.activate.label": "Aktivirajte vašu licencu", + "license.activate.domain": "Vaša licenca će biti aktivirana za {host}.", + "license.activate.local": "Upravo ćete aktivirati svoju Kirby licencu za vašu lokalnu domenu {host}. Ako će ova stranica biti postavljena na javnu domenu, molimo vas da je tamo aktivirate. Ako je {host} domena za koju želite koristiti svoju licencu, molimo vas da nastavite.", + "license.activated": "Aktivirano", + "license.buy": "Kupite licencu", + "license.code": "Kod", + "license.code.help": "Primili ste vašu licencu nakon kupovine putem e-maila. Molimo da je kopirate i zalijepite ovdje.", + "license.code.label": "Unesite vašu licencu", + "license.status.active.info": "Uključuje nove glavne verzije do {date}", + "license.status.active.label": "Važeća licenca", + "license.status.demo.info": "Ovo je demo instalacija", + "license.status.demo.label": "Demo", + "license.status.inactive.info": "Obnovi licencu da bi se ažuriralo na nove glavne verzije", + "license.status.inactive.label": "Nema novih glavnih verzija", + "license.status.legacy.bubble": "Spremni da obnovite vašu licencu?", + "license.status.legacy.info": "Vaša licenca ne pokriva ovu verziju", + "license.status.legacy.label": "Obnovite vašu licencu", + "license.status.missing.bubble": "Spremni da objavite vašu stranicu?", + "license.status.missing.info": "Ne postoji važeća licenca", + "license.status.missing.label": "Aktivirajte vašu licencu", + "license.status.unknown.info": "Status licence je nepoznat", + "license.status.unknown.label": "Nepoznato", + "license.manage": "Upravljanje vašim licencama", + "license.purchased": "Kupljeno", + "license.success": "Hvala što podržavate Kirby", + "license.unregistered.label": "Neregistrovano", + + "link": "Link", + "link.text": "Tekst linka", + + "loading": "Učitavanje", + + "lock.unsaved": "Izmjene nisu spremljene", + "lock.unsaved.empty": "Ne postoje druge izmjene za spremanje", + "lock.unsaved.files": "Nespremljene datoteke", + "lock.unsaved.pages": "Nespremljene stranice", + "lock.unsaved.users": "Nespremljeni računi", + "lock.isLocked": "Izmjene od strane {email}", + "lock.unlock": "Otključaj", + "lock.unlock.submit": "Otključaj i prepiši preko nespremljenih promjena od {email}", + "lock.isUnlocked": "Vaše izmjene su zamijenjene sa izmjenama drugog korisnika. Dostupne su za download, te ih možete spojiti manuelno.", + + "login": "Prijava", + "login.code.label.login": "Kod za prijavu", + "login.code.label.password-reset": "Kod za resetiranje šifre", + "login.code.placeholder.email": "000 000", + "login.code.placeholder.totp": "000000", + "login.code.text.email": "Ako je vaša e-mail adresa registrirana, traženi kod je poslan putem e-maila.", + "login.code.text.totp": "Unesite jednokratni kod iz vaše autentifikacijske aplikacije.", + "login.email.login.body": "Zdravo {user.nameOrEmail},\n\nNedavno ste zatražili kod za prijavu na Panel stranice {site}.\nSljedeći kod za prijavu važiće {timeout} minuta:\n\n{code}\n\nAko niste zatražili kod za prijavu, molimo vas da zanemarite ovaj e-mail ili kontaktirate svog administratora ako imate pitanja.\nIz sigurnosnih razloga, molimo vas da NE prosljeđujete ovaj e-mail.", + "login.email.login.subject": "Vaš kod za prijavu", + "login.email.password-reset.body": "Zdravo {user.nameOrEmail},\n\nNedavno ste zatražili kod za resetiranje šifre za Panel stranice {site}.\nSljedeći kod za resetiranje šifre važiće {timeout} minuta:\n\n{code}\n\nAko niste zatražili kod za resetiranje šifre, molimo vas da zanemarite ovaj e-mail ili kontaktirate svog administratora ako imate pitanja.\nIz sigurnosnih razloga, molimo vas da NE prosljeđujete ovaj e-mail.", + "login.email.password-reset.subject": "Kod za resetiranje šifre", + "login.remember": "Zapamti moju prijavu", + "login.reset": "Resetiraj šifru", + "login.toggleText.code.email": "Prijava putem emaila", + "login.toggleText.code.email-password": "Prijava sa šifrom", + "login.toggleText.password-reset.email": "Zaboravljena šifra?", + "login.toggleText.password-reset.email-password": "← Nazad na login", + "login.totp.enable.option": "Postavite jednokratne kodove", + "login.totp.enable.intro": "Autentifikacijske aplikacije mogu generirati jednokratne kodove koji se koriste kao drugi faktor prilikom prijavljivanja u vaš račun.", + "login.totp.enable.qr.label": "1. Skeniraj ovaj QR kod", + "login.totp.enable.qr.help": "Skeniranje nije moguće? Dodaj ključ za postavljanje {secret} ručno u aplikaciju za autentifikaciju.", + "login.totp.enable.confirm.headline": "2. Potvrdi sa generisanim kodom", + "login.totp.enable.confirm.text": "Vaša aplikacija generira novi jednokratni kod svakih 30 sekundi. Unesite trenutni kod da završite postavljanje:", + "login.totp.enable.confirm.label": "Trenutni kod", + "login.totp.enable.confirm.help": "Nakon ovih postavki, tražićemo od vas jednokratni kod prilikom svakog prijavljivanja.", + "login.totp.enable.success": "Jednokratni kodovi omogućeni", + "login.totp.disable.option": "Onemogući jednokratne kodove", + "login.totp.disable.label": "Unesite vaš password da bi onemogućili jednokratne kodove", + "login.totp.disable.help": "Ubuduće, drugačiji drugi faktor poput koda za prijavu dostavljenog putem e-maila će biti zatražen prilikom slijedeće prijave. Uvijek ponovo možete postaviti jednokratne kodove kasnije.", + "login.totp.disable.admin": "

Ovo će onemogućiti jednokratne kodove za {user}.

Ubuduće, drugačiji drugi faktor poput koda za prijavu dostavljenog putem e-maila će biti zatražen prilikom prijave. {user} može postaviti jednokratne kodove nakon njihove slijedeće prijave.

", + "login.totp.disable.success": "Jednokratni kodovi onemogućeni", + + "logout": "Odjava", + + "merge": "Spoji", + "menu": "Izbornik", + "meridiem": "AM/PM", + "mime": "Tip medija", + "minutes": "Minute", + + "month": "Mjesec", + "months.april": "April", + "months.august": "August", + "months.december": "Decembar", + "months.february": "Feburar", + "months.january": "Januar", + "months.july": "Juli", + "months.june": "Juni", + "months.march": "Mart", + "months.may": "Maj", + "months.november": "Novembar", + "months.october": "Oktobar", + "months.september": "Septembar", + + "more": "Više", + "move": "Pomjeri", + "name": "Ime", + "next": "Dalje", + "night": "Noć", + "no": "ne", + "off": "off", + "on": "on", + "open": "Otvori", + "open.newWindow": "Otvori u novom prozoru", + "option": "Opcija", + "options": "Opcije", + "options.none": "Nema opcija", + "options.all": "Prikaži svih {count} options", + + "orientation": "Orijentacija", + "orientation.landscape": "Pejzaž", + "orientation.portrait": "Portret", + "orientation.square": "Kvadrat", + + "page": "Strana", + "page.blueprint": "Ova stranica još uvijek nema blueprint. Možete definirati postavke u /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Promijeni URL", + "page.changeSlug.fromTitle": "Kreiraj iz naslova", + "page.changeStatus": "Promijeni status", + "page.changeStatus.position": "Odaberi poziciju", + "page.changeStatus.select": "Odaberi novi status", + "page.changeTemplate": "Promijeni predložak", + "page.changeTemplate.notice": "Promjena predloška stranice će ukloniti sadržaj za polja koja se ne podudaraju po tipu. Koristite s oprezom.", + "page.create": "Kreiraj kao {status}", + "page.delete.confirm": "Da li stvarno želite obrisati {title}?", + "page.delete.confirm.subpages": "Ova stranica ima podstranice.
Sve podstranice će također biti obrisane.", + "page.delete.confirm.title": "Napiši naslov stranice kao potvrdu ove akcije", + "page.duplicate.appendix": "Kopiraj", + "page.duplicate.files": "Kopiraj datoteke", + "page.duplicate.pages": "Kopiraj stranice", + "page.move": "Premjesti stranicu", + "page.sort": "Promijeni poziciju", + "page.status": "Status", + "page.status.draft": "Skica", + "page.status.draft.description": "Stranica je u izradi, te je vidljiva jedino prijavljenim urednicima", + "page.status.listed": "Javno", + "page.status.listed.description": "Stranica je javno dostupna", + "page.status.unlisted": "Neizlistano", + "page.status.unlisted.description": "Stranica je dostupna putem direktnog URL-a", + + "pages": "Stranice", + "pages.delete.confirm.selected": "Da li stvarno želite da obrišete odabrane stranice? Ova akcija se ne može poništiti.", + "pages.empty": "Još nema stranica...", + "pages.status.draft": "Skica", + "pages.status.listed": "Javno", + "pages.status.unlisted": "Neizlistano", + + "pagination.page": "Strana", + + "password": "Šifra", + "paste": "Zalijepi", + "paste.after": "Zalijepi nakon", + "paste.success": "{count} zalijepljeno!", + "pixel": "Piksel", + "plugin": "Plugin", + "plugins": "Plugini", + "prev": "Previous", + "preview": "Pregled", + + "publish": "Objavi", + "published": "Javno", + + "remove": "Remove", + "rename": "Preimenuj", + "renew": "Obnovi", + "replace": "Zamijeni", + "replace.with": "Zamijeni sa", + "retry": "Pokušaj ponovo", + "revert": "Revert", + "revert.confirm": "Da li stvarno želite obrisati sve nespremljene promjene?", + + "role": "Uloga", + "role.admin.description": "Administrator ima sva prava", + "role.admin.title": "Administrator", + "role.all": "Sve", + "role.empty": "Za ovu ulogu ne postoje korisnici", + "role.description.placeholder": "Bez opisa", + "role.nobody.description": "Ovo je pomoćna uloga bez ikakvih prava", + "role.nobody.title": "Niko", + + "save": "Spremi", + "saved": "Spremljeno", + "search": "Traži", + "searching": "Traženje", + "search.min": "Unesi {min} znakova za pretraživanje", + "search.all": "Prikaži svih {count} rezultata", + "search.results.none": "Nema rezultata", + + "section.invalid": "Ova sekcija je nevažeća", + "section.required": "Ova sekcija je potrebna", + + "security": "Sigurnost", + "select": "Odaberi", + "server": "Server", + "settings": "Postavke", + "show": "Prikaži", + "site.blueprint": "Stranica još uvijek nema blueprint. Možete definirati postavke u /site/blueprints/site.yml", + "size": "Veličina", + "slug": "URL nastavak", + "sort": "Sortiranje", + "sort.drag": "Prevuci za sortiranje ...", + "split": "Podijeli", + + "stats.empty": "Nema izvještaja", + "status": "Status", + + "system.info.copy": "Kopiraj info", + "system.info.copied": "Sistemske info kopirane", + "system.issues.content": "Čini se da je content folder izložen", + "system.issues.eol.kirby": "Vaša instalirana Kirby verzija je dostigla end-of-life i neće primati daljnja sigurnosna ažuriranja", + "system.issues.eol.plugin": "Vaša instalirana verzija plugina { plugin } je dostigla end-of-life i neće primati daljnja sigurnosna ažuriranja", + "system.issues.eol.php": "Vaša instalirana PHP verzija { release } je dostigla end-of-life i neće primati daljnja sigurnosna ažuriranja", + "system.issues.debug": "Debugiranje se mora isključiti u produkciji", + "system.issues.git": "Čini se da je .git folder izložen", + "system.issues.https": "Preporučujemo HTTPS za sve vaše stranice", + "system.issues.kirby": "Čini se da je kirby folder izložen", + "system.issues.local": "Stranica radi lokalno uz opuštene signurnosne provjere", + "system.issues.site": "Čini se da je site folder izložen", + "system.issues.vue.compiler": "Vue template compiler je omogućen", + "system.issues.vulnerability.kirby": "Vaša instalacija je možda pogođena slijedećim sigurnosnim propustom ({ severity } stepen): { description }", + "system.issues.vulnerability.plugin": "Vaša instalacija je možda pogođena slijedećim sigurnosnim propustom u pluginu {plugin} ({ severity } stepen): { description }", + "system.updateStatus": "Ažuriraj status", + "system.updateStatus.error": "Nije moguće provjeriti za ažuriranja", + "system.updateStatus.not-vulnerable": "Nema poznatih sigurnosnih propusta", + "system.updateStatus.security-update": "Besplatno sigurnosno ažiriranje { version } dostupno", + "system.updateStatus.security-upgrade": "Nadogradnja { version } sa sigurnosnim popravkama dostupna", + "system.updateStatus.unreleased": "Neobjavljena verzija", + "system.updateStatus.up-to-date": "Ažurirano", + "system.updateStatus.update": "Besplatno ažuriranje { version } dostupno", + "system.updateStatus.upgrade": "Nadogradnja { version } dostupna", + + "tel": "Telefon", + "tel.placeholder": "+38761222333", + "template": "Predložak", + + "theme": "Tema", + "theme.light": "Svjetla upaljena", + "theme.dark": "Svjetla ugašena", + "theme.automatic": "Uskladi sa sistemskim postavkama", + + "title": "Naslov", + "today": "Danas", + + "toolbar.button.clear": "Očisti formatiranje", + "toolbar.button.code": "Kod", + "toolbar.button.bold": "Podebljano", + "toolbar.button.email": "Email", + "toolbar.button.headings": "Naslovi", + "toolbar.button.heading.1": "Naslov 1", + "toolbar.button.heading.2": "Naslov 2", + "toolbar.button.heading.3": "Naslov 3", + "toolbar.button.heading.4": "Naslov 4", + "toolbar.button.heading.5": "Naslov 5", + "toolbar.button.heading.6": "Naslov 6", + "toolbar.button.italic": "Kurziv", + "toolbar.button.file": "Datoteka", + "toolbar.button.file.select": "Odaberi datoteku", + "toolbar.button.file.upload": "Uploadaj datoteku", + "toolbar.button.link": "Link", + "toolbar.button.paragraph": "Paragraf", + "toolbar.button.strike": "Precrtano", + "toolbar.button.sub": "Podpis", + "toolbar.button.sup": "Nadpis", + "toolbar.button.ol": "Uređena list", + "toolbar.button.underline": "Podvučeno", + "toolbar.button.ul": "Označena lista", + + "translation.author": "Faris Mujakić", + "translation.direction": "ltr", + "translation.name": "Bosanski", + "translation.locale": "bs_BA", + + "type": "Tip", + + "upload": "Uploadaj", + "upload.error.cantMove": "Uploadana datoteka se ne može premjestiti", + "upload.error.cantWrite": "Greška prilikom pisanja datoteke na disk", + "upload.error.default": "Datoteka se ne može uploadati", + "upload.error.extension": "Upload zaustavljen od strane ekstenzije", + "upload.error.formSize": "Uploadana datoteka premašuje MAX_FILE_SIZE direktivu navedenu u formi", + "upload.error.iniPostSize": "Uploadana datoteka premašuje post_max_size direktivu u php.ini", + "upload.error.iniSize": "Uploadana datoteka premašuje upload_max_filesize direktivu u php.ini", + "upload.error.noFile": "Datoteka nije uploadana", + "upload.error.noFiles": "Datoteke nisu uploadane", + "upload.error.partial": "Datoteka je djelimično uploadana", + "upload.error.tmpDir": "Nedostaje privremeni folder", + "upload.errors": "Greška", + "upload.progress": "Slanje...", + + "url": "Url", + "url.placeholder": "https://example.com", + + "user": "Korisnik", + "user.blueprint": "Možete definirati dodatne sekcije i polja forme za ovu ulogu korisnika u /site/blueprints/users/{role}.yml", + "user.changeEmail": "Promijeni email", + "user.changeLanguage": "Promijeni jezik", + "user.changeName": "Preimenuj ovog korisnika", + "user.changePassword": "Promijeni šifru", + "user.changePassword.current": "Trenutna šifra", + "user.changePassword.new": "Nova šifra", + "user.changePassword.new.confirm": "Potvrdi novu šifru...", + "user.changeRole": "Promijeni ulogu", + "user.changeRole.select": "Odaberi novu ulogu", + "user.create": "Dodaj novog korisnika", + "user.delete": "Obriši ovog korisnika", + "user.delete.confirm": "Da li stvarno želite obrisati
{email}?", + + "users": "Korisnici", + + "version": "Verzija", + "version.changes": "Promijenjena verzija", + "version.compare": "Uporedi verzije", + "version.current": "Trenutna verzija", + "version.latest": "Zadnja verzija", + "versionInformation": "Informacije o verziji", + + "view": "Pregled", + "view.account": "Tvoj račun", + "view.installation": "Instalacija", + "view.languages": "Jezici", + "view.resetPassword": "Resetiraj šifru", + "view.site": "Stranica", + "view.system": "Sistem", + "view.users": "Korisnici", + + "welcome": "Dobrodošli", + "year": "Godina", + "yes": "da" +} diff --git a/kirby/i18n/translations/sr@latin.json b/kirby/i18n/translations/sr@latin.json new file mode 100644 index 0000000..8f27407 --- /dev/null +++ b/kirby/i18n/translations/sr@latin.json @@ -0,0 +1,799 @@ +{ + "account.changeName": "Promenite vaše ime", + "account.delete": "Izbrišite vaš nalog", + "account.delete.confirm": "Da li zaista želite da izbrišete vaš nalog? Bićete odjavljeni odmah, i vaš nalog ne može biti povraćen.", + + "activate": "Aktivirati", + "add": "Dodaj", + "alpha": "Alfa", + "author": "Autor", + "avatar": "Profilna slika", + "back": "Nazad", + "cancel": "Otkažite", + "change": "Promenite", + "close": "Zatvorite", + "changes": "Promene", + "confirm": "Ok", + "collapse": "Skupi", + "collapse.all": "Skupi sve", + "color": "Boja", + "coordinates": "Koordinate", + "copy": "Kopiraj", + "copy.all": "Kopiraj sve", + "copy.success": "Copied", + "copy.success.multiple": "{count} kopirano!", + "copy.url": "Copy URL", + "create": "Kreiraj", + "custom": "Običaj", + + "date": "Datum", + "date.select": "Izaberite datum", + + "day": "Dan", + "days.fri": "Pet", + "days.mon": "Pon", + "days.sat": "Sub", + "days.sun": "Ned", + "days.thu": "Čet", + "days.tue": "Uto", + "days.wed": "Sre", + + "debugging": "Otklanjanje grešaka", + + "delete": "Obriši", + "delete.all": "Obriši sve", + + "dialog.fields.empty": "Ovaj dijalog nema polja", + "dialog.files.empty": "Nema fajlova koji se mogu izabrati", + "dialog.pages.empty": "Nema stranica koje se mogu izabrati", + "dialog.text.empty": "Ovaj dijalog ne definiše nikakav tekst", + "dialog.users.empty": "Nema korisnika koji se mogu izabrati", + + "dimensions": "Dimenzije", + "disable": "Onemogućiti", + "disabled": "Onemogućeno", + "discard": "Odbaci", + + "drawer.fields.empty": "Ova fioka nema polja", + + "domain": "Domen", + "download": "Preuzmi", + "duplicate": "Kopiraj", + + "edit": "Uredi", + + "email": "Email", + "email.placeholder": "mail@example.com", + + "enter": "Uneti", + "entries": "Unosi", + "entry": "Unos", + + "environment": "Okruženje", + + "error": "Greška", + "error.access.code": "Neispravan kod", + "error.access.login": "Neispravna prijava", + "error.access.panel": "Niste ovlašćeni da uđete u administrativni panel", + "error.access.view": "Niste ovlašćeni da pristupite ovom delu panela", + + "error.avatar.create.fail": "Profilna slika nije mogla biti otpremljena", + "error.avatar.delete.fail": "Profilna slika nije mogla biti obrisana", + "error.avatar.dimensions.invalid": "Molimo neka visina i širina Vaše profilne slike budu ispod 3000 piksela", + "error.avatar.mime.forbidden": "Profilna slika mora biti JPEG ili PNG fajl", + + "error.blueprint.notFound": "Blueprint \"{name}\" nije mogao biti učitan", + + "error.blocks.max.plural": "Ne smete da dodajete više od {max} blokova", + "error.blocks.max.singular": "Ne smete da dodate više od jednog bloka", + "error.blocks.min.plural": "Morate dodati najmanje {min} blokova", + "error.blocks.min.singular": "Morate dodati najmanje jedan blok", + "error.blocks.validation": "Postoji greška u \"{field}\" polju u bloku {index} koji koristi \"{fieldset}\" tip bloka ", + + "error.cache.type.invalid": "Neispravan tip keša \"{type}\"", + + "error.content.lock.delete": "The version is locked and cannot be deleted", + "error.content.lock.move": "The source version is locked and cannot be moved", + "error.content.lock.publish": "This version is already published", + "error.content.lock.replace": "The version is locked and cannot be replaced", + "error.content.lock.update": "The version is locked and cannot be updated", + + "error.entries.max.plural": "You must not add more than {max} entries", + "error.entries.max.singular": "You must not add more than one entry", + "error.entries.min.plural": "You must add at least {min} entries", + "error.entries.min.singular": "You must add at least one entry", + "error.entries.supports": "\"{type}\" field type is not supported for the entries field", + "error.entries.validation": "Postoji greška u redu \"{field}\" na ovom polju {index}", + + "error.email.preset.notFound": "Email preset \"{name}\" nije pronađen", + + "error.field.converter.invalid": "Neispravan converter \"{converter}\"", + "error.field.link.options": "Invalid options: {options}", + "error.field.type.missing": "Polje \"{ name }\": Tip polja \"{ type }\" ne postoji", + + "error.file.changeName.empty": "Naziv ne sme biti prazan", + "error.file.changeName.permission": "Niste ovlašćeni da promenite naziv \"{filename}\"", + "error.file.changeTemplate.invalid": "Šablon za datoteku \"{id}\" se ne može promeniti u \"{template}\" (valid: \"{blueprints}\")", + "error.file.changeTemplate.permission": "Nije vam dozvoljeno da menjate šablon za datoteku \"{id}\"", + + "error.file.delete.multiple": "Not all files could be deleted. Try each remaining file individually to see the specific error that prevents deletion.", + "error.file.duplicate": "Fajl sa nazivom \"{filename}\" već postoji", + "error.file.extension.forbidden": "Extension \"{extension}\" nije dozvoljena", + "error.file.extension.invalid": "Nevažeći dodatak: {extension}", + "error.file.extension.missing": "Ekstenzije za \"{filename}\" nedostaju", + "error.file.maxheight": "Visina slike ne sme biti veća od {height} piksela", + "error.file.maxsize": "Datoteka je prevelika", + "error.file.maxwidth": "Širina slike ne sme biti veća od {width} piksela", + "error.file.mime.differs": "Otpremljeni fajl mora biti istog mime tipa \"{mime}\"", + "error.file.mime.forbidden": "Tip medija \"{mime}\" nije dozvoljen", + "error.file.mime.invalid": "Neispravan mime tip: {mime}", + "error.file.mime.missing": "Tip medija za \"{filename}\" nije bilo moguće detektovati", + "error.file.minheight": "Visina slike mora biti najmanje {height} piksela", + "error.file.minsize": "Datoteka je premala", + "error.file.minwidth": "Širina slike mora biti najmanje {width} piksela", + "error.file.name.unique": "Ime datoteke mora biti jedinstveno", + "error.file.name.missing": "Ime fajla ne može biti prazno", + "error.file.notFound": "Fajl \"{filename}\" nije mogao biti pronadjen", + "error.file.orientation": "Orijentacija slike mora biti \"{orientation}\"", + "error.file.sort.permission": "You are not allowed to change the sorting of \"{filename}\"", + "error.file.type.forbidden": "Niste ovlašćeni da otpremate {type} fajlove", + "error.file.type.invalid": "Nevažeći tip datoteke: {type}", + "error.file.undefined": "Fajl nije mogao biti pronadjen", + + "error.form.incomplete": "Molimo popravite sve greške u formularu...", + "error.form.notSaved": "Formular nije mogao biti sačuvan", + + "error.language.code": "Molimo ukucajte validan kod za jezik", + "error.language.create.permission": "You are not allowed to create a language", + "error.language.delete.permission": "You are not allowed to delete the language", + "error.language.duplicate": "Jezik već postoji", + "error.language.name": "Molimo upišite validno ime za jezik", + "error.language.notFound": "Jezik nije mogao biti pronađen", + "error.language.update.permission": "You are not allowed to update the language", + + "error.layout.validation.block": "Postoji greška u \"{field}\" polju u bloku {blockIndex} koji koristi \"{fieldset}\" tip bloka u rasporedu {layoutIndex}", + "error.layout.validation.settings": "Došlo je do greške u {index} podešavanjima ", + + "error.license.domain": "Nedostaje domen za licencu", + "error.license.email": "Molimo unesite ispravnu email adresu", + "error.license.format": "Molimo vas unesite važeći kod licence", + "error.license.verification": "Licenca nije mogla biti verifikovana", + + "error.login.totp.confirm.invalid": "Neispravan kod", + "error.login.totp.confirm.missing": "Molimo vas unesite trenutni kod", + + "error.object.validation": "Postoji greška u \"{label}\" polju: {message}", + + "error.offline": "Panel je trenutno van mreže", + + "error.page.changeSlug.permission": "Nije Vam dozvoljeno da promenite URL appendix za \"{slug}\"", + "error.page.changeSlug.reserved": "Putanja stranica najvišeg nivoa ne sme da počinje sa \"{path}\"", + "error.page.changeStatus.incomplete": "Ova stranica ima greške i ne može biti objavljena", + "error.page.changeStatus.permission": "Status ove stranice ne može biti promenjen", + "error.page.changeStatus.toDraft.invalid": "Stranica \"{slug}\" ne može biti prebačena u draft", + "error.page.changeTemplate.invalid": "Template za stranicu \"{slug}\" ne može biti promenjen", + "error.page.changeTemplate.permission": "Nije Vam dozvoljeno da promenite template za \"{slug}\"", + "error.page.changeTitle.empty": "Naslov ne može biti prazan", + "error.page.changeTitle.permission": "Nije Vam dozvoljeno da pormenite naslov za \"{slug}\"", + "error.page.create.permission": "Nije Vam dozvoljeno da kreirate \"{slug}\"", + "error.page.delete": "Stranica \"{slug}\" ne može biti obrisana", + "error.page.delete.confirm": "Molimo ukucajte naslov stranice da potvrdite", + "error.page.delete.hasChildren": "Stranica ima podstranice i ne može biti obrisana", + "error.page.delete.multiple": "Not all pages could be deleted. Try each remaining page individually to see the specific error that prevents deletion.", + "error.page.delete.permission": "Nemate ovlašćenja da obrišete \"{slug}\"", + "error.page.draft.duplicate": "Draft stranice sa URL appendix \"{slug}\" već postoji", + "error.page.duplicate": "Stranica sa URL appendix-om \"{slug}\" već postoji", + "error.page.duplicate.permission": "Nije vam dozvoljeno da kopirate \"{slug}\"", + "error.page.move.ancestor": "Stranica se ne može premestiti u sebe", + "error.page.move.directory": "Direktorijum stranice ne može da se premesti", + "error.page.move.duplicate": "Podstranica sa dodatkom URL \"{slug}\" već postoji", + "error.page.move.noSections": "The page \"{parent}\" cannot be a parent of any page because it lacks any pages sections in its blueprint", + "error.page.move.notFound": "Premeštena stranica nije pronađena", + "error.page.move.permission": "Nije vam dozvoljeno da se krećete \"{slug}\"", + "error.page.move.template": "Šablon \"{template}\" nije prihvaćen kao podstranica \"{parent}\"", + "error.page.notFound": "Stranica \"{slug}\" ne može biti pronadjena", + "error.page.num.invalid": "Molimo ukucajte ispravan broj za sortiranje. Brojevi ne mogu biti negativni. ", + "error.page.slug.invalid": "Molimo vas unesite važeći URL dodatak", + "error.page.slug.maxlength": "Dužina poluge mora biti manja od \"{length}\" karaktera ", + "error.page.sort.permission": "Stranica \"{slug}\" ne može biti sortirana", + "error.page.status.invalid": "Molimo podesite ispravan status stranice", + "error.page.undefined": "Stranica ne može biti pronađena", + "error.page.update.permission": "Nije Vam dozvoljeno da ažurirate \"{slug}\"", + + "error.section.files.max.plural": "Ne možete dodati više od {max} fajlova u \"{section}\" sekciju", + "error.section.files.max.singular": "Ne možete dodati više od jednog fajla u \"{section}\" sekciju", + "error.section.files.min.plural": "\"{section}\" sekcija zahteva najmanje {min} fajlova", + "error.section.files.min.singular": "\"{section}\" sekcija zahteva najmanje jedan fajl", + + "error.section.pages.max.plural": "Ne možete dodati više od {max} stranica u \"{section}\" sekciju", + "error.section.pages.max.singular": "Ne možete dodati više od jedne stranice u \"{section}\" sekciju", + "error.section.pages.min.plural": "\"{section}\" sekcija zahteva najmanje {min} stranica", + "error.section.pages.min.singular": "\"{section}\" sekcija zahteva najmanje jednu stranicu", + + "error.section.notLoaded": "Sekcija \"{name}\" nije mogla biti učitana", + "error.section.type.invalid": "Tip sekcije \"{type}\" nije ispravan", + + "error.site.changeTitle.empty": "Naslov ne može biti prazan", + "error.site.changeTitle.permission": "Nije Vam dozvoljeno da promenite naziv sajta", + "error.site.update.permission": "Nije Vam dozvoljeno da ažurirate sajt", + + "error.structure.validation": "Postoji greška u redu \"{field}\" na ovom polju {index}", + + "error.template.default.notFound": "Podrazumevani template ne postoji", + + "error.unexpected": "Došlo je do neočekivane greške! Omogućite režim za otklanjanje grešaka za više informacija: https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "Nije Vam dozvoljeno da promenite email za korisnika \"{name}\"", + "error.user.changeLanguage.permission": "Nije Vam dozvoljeno da promenite jezik za korisnika \"{name}\"", + "error.user.changeName.permission": "Nije Vam dozvoljeno da promenite ima za korisnika \"{name}\"", + "error.user.changePassword.permission": "Nije Vam dozvoljeno da promenite lozinku za korisnika \"{name}\"", + "error.user.changeRole.lastAdmin": "Rolu poslednjeg admina nije moguće promeniti", + "error.user.changeRole.permission": "Nije Vam dozvoljeno da promenite rolu korisnika \"{name}\"", + "error.user.changeRole.toAdmin": "Nije vam dozvoljeno da unapredite nekoga u ulogu administratora", + "error.user.create.permission": "Nije Vam dozvoljeno da kreirate ovog korisnika", + "error.user.delete": "Korisnik \"{name}\" ne može biti obrisan", + "error.user.delete.lastAdmin": "Poslednji admin ne može biti obrisan", + "error.user.delete.lastUser": "Poslednji korisnik ne može biti obrisan", + "error.user.delete.permission": "Nije Vam dozvoljeno da obrišete korisnika \"{name}\"", + "error.user.duplicate": "Korisnik sa email adresom \"{email}\" već postoji", + "error.user.email.invalid": "Molimo unesite ispravnu email adresu", + "error.user.language.invalid": "Molimo unesite ispravan jezik", + "error.user.notFound": "Korisnik \"{name}\" ne može biti pronadjen", + "error.user.password.excessive": "Molimo vas, unesite ispravnu šifru. Šifra ne sme biti duža od 1000 karaktera.", + "error.user.password.invalid": "Molimo unesite ispravnu lozinku. Lozinke moraju biti barem 8 karaktera dugačke. ", + "error.user.password.notSame": "Lozinke se ne poklapaju", + "error.user.password.undefined": "Ovaj korisnik nema lozinku", + "error.user.password.wrong": "Pogrešna lozinka", + "error.user.role.invalid": "Molimo unesite ispravnu rolu", + "error.user.undefined": "Korisnik nije mogao biti pronadjen", + "error.user.update.permission": "Nije Vam dozvoljeno da ažurirate korisnika \"{name}\"", + + "error.validation.accepted": "Molimo potvrdite", + "error.validation.alpha": "Molimo unesite karaktere izmedju a-z", + "error.validation.alphanum": "Molimo unesite samo karaktere izmedju a-z ili brojeve 0-9", + "error.validation.anchor": "Molimo vas unesite ispravan link", + "error.validation.between": "Molimo unesite vrednost izmedju \"{min}\" i \"{max}\"", + "error.validation.boolean": "Molimo potvrdite ili odbijte", + "error.validation.color": "Molimo vas unesite važeću boju u {format} format", + "error.validation.contains": "Molimo unesite vrednost koja sadrži \"{needle}\"", + "error.validation.date": "Molimo unesite ispravan datum", + "error.validation.date.after": "Molimo upišite natum nakon {date}", + "error.validation.date.before": "Molimo upišite datum pre {date}", + "error.validation.date.between": "Molimo dodajte datum između {min} i {max}", + "error.validation.denied": "Molimo odbijte", + "error.validation.different": "Vrednost ne može biti \"{other}\"", + "error.validation.email": "Molimo unesite ispravnu email adresu", + "error.validation.endswith": "Vrednost se mora završiti sa \"{end}\"", + "error.validation.filename": "Molimo unesite ispravno ime fajla", + "error.validation.in": "Molimo unesite nešto od sledećeg: ({in})", + "error.validation.integer": "Molimo unesite ispravan ceo broj", + "error.validation.ip": "Molimo unesite ispravnu IP adresu", + "error.validation.less": "Molimo unesite vrednost manju od {max}", + "error.validation.linkType": "Tip veze nije dozvoljen", + "error.validation.match": "Vrednost se ne uklapa u očekivani šablon", + "error.validation.max": "Molimo unesite vrednost jednsaku ili manju od {max}", + "error.validation.maxlength": "Molimo unestite kražu vrednost. (maks. {max} karaktera)", + "error.validation.maxwords": "Molimo unesite ne više od {max} reč(i)", + "error.validation.min": "Molimo unesite vrednost jednaku ili veću od {min}", + "error.validation.minlength": "Molimo unesite dužu vrednost. (min. {min} karaktera)", + "error.validation.minwords": "Molimo unesite minimun {min} reč(i)", + "error.validation.more": "Molimo vas unesite vrednost veću od {min}", + "error.validation.notcontains": "Molimo vas unesite vrednost koja ne sadrži \"{needle}\"", + "error.validation.notin": "Molimo vas nemojte unositi ništa od sledećeg: ({notIn})", + "error.validation.option": "Molimo izaberite važeću opciju", + "error.validation.num": "Molimo Vas da unesete važeći broj", + "error.validation.required": "Molimo vas unesite nešto", + "error.validation.same": "Molimo vas unesite \"{other}\"", + "error.validation.size": "Veličina vrednosti mora biti \"{size}\"", + "error.validation.startswith": "Vrednost mora početi sa \"{start}\"", + "error.validation.tel": "Molimo vas unesite neformatirani broj telefona", + "error.validation.time": "Molimo vas unesite važeće vreme", + "error.validation.time.after": "Molimo vas unesite vreme posle {time}", + "error.validation.time.before": "Molimo vas unesite vreme pre {time}", + "error.validation.time.between": "Molimo vas unesite vreme između {min} i {max}", + "error.validation.uuid": "Molimo vas unesite važeći UUID", + "error.validation.url": "Molimo vas da unesete važeći URL", + + "expand": "Proširite", + "expand.all": "Proširite sve", + + "field.invalid": "Polje je nevažeće", + "field.required": "Polje je obavezno", + "field.blocks.changeType": "Promenite tip", + "field.blocks.code.name": "Kod", + "field.blocks.code.language": "Jezik", + "field.blocks.code.placeholder": "Vaš kod…", + "field.blocks.delete.confirm": "Da li zaista želite da izbrišete ovaj blok?", + "field.blocks.delete.confirm.all": "Da li zaista želite da izbrišete sve blokove?", + "field.blocks.delete.confirm.selected": "Da li zaista želite da izbrišete izabrane blokove?", + "field.blocks.empty": "Još nema blokova", + "field.blocks.fieldsets.empty": "Još nema skupova polja", + "field.blocks.fieldsets.label": "Molimo izaberite tip bloka ...", + "field.blocks.fieldsets.paste": "Pritisnite{{ shortcut }} da biste uvezli rasporede/blokove iz međuspremnika. Biće umetnuti samo oni koji su dozvoljeni u trenutnom polju.", + "field.blocks.gallery.name": "Galerija", + "field.blocks.gallery.images.empty": "Još nema slika", + "field.blocks.gallery.images.label": "Slike", + "field.blocks.heading.level": "Nivo", + "field.blocks.heading.name": "Naslov", + "field.blocks.heading.text": "Tekst", + "field.blocks.heading.placeholder": "Naslov ...", + "field.blocks.figure.back.plain": "Plain", + "field.blocks.figure.back.pattern.light": "Pattern (light)", + "field.blocks.figure.back.pattern.dark": "Pattern (dark)", + "field.blocks.image.alt": "Alternativni tekst", + "field.blocks.image.caption": "Natpis", + "field.blocks.image.crop": "Isecite", + "field.blocks.image.link": "Link", + "field.blocks.image.location": "Lokacija", + "field.blocks.image.location.internal": "Ova veb lokacija\n \n \n​", + "field.blocks.image.location.external": "Eksterni izvor", + "field.blocks.image.name": "Slika", + "field.blocks.image.placeholder": "Odaberi sliku", + "field.blocks.image.ratio": "Odnos", + "field.blocks.image.url": "URL slike", + "field.blocks.line.name": "Linija", + "field.blocks.list.name": "Lista", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "Tekst", + "field.blocks.markdown.placeholder": "Markdown …", + "field.blocks.quote.name": "Citat", + "field.blocks.quote.text.label": "Tekst", + "field.blocks.quote.text.placeholder": "Citat ...", + "field.blocks.quote.citation.label": "Citat", + "field.blocks.quote.citation.placeholder": "od …", + "field.blocks.text.name": "Tekst", + "field.blocks.text.placeholder": "Tekst ...", + "field.blocks.video.autoplay": "Autoplay", + "field.blocks.video.caption": "Natpis", + "field.blocks.video.controls": "Controls", + "field.blocks.video.location": "Lokacija", + "field.blocks.video.loop": "Loop", + "field.blocks.video.muted": "Muted", + "field.blocks.video.name": "Video", + "field.blocks.video.placeholder": "Unesite URL video snimka", + "field.blocks.video.poster": "Poster", + "field.blocks.video.preload": "Preload", + "field.blocks.video.url.label": "Video-URL", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.entries.delete.confirm.all": "Da li zaista želite da izbrišete sve unose?", + "field.entries.empty": "Još nema unosa", + + "field.files.empty": "Još nijedna datoteka nije izabrana", + "field.files.empty.single": "No file selected yet", + + "field.layout.change": "Promenite izgled", + "field.layout.delete": "Brisanje rasporeda", + "field.layout.delete.confirm": "Da li zaista želite da obrišete ovaj raspored", + "field.layout.delete.confirm.all": "Da li zaista želite da izbrišete sve rasporede?", + "field.layout.empty": "Još nema redova", + "field.layout.select": "Izaberite raspored", + + "field.object.empty": "Još nema informacija", + + "field.pages.empty": "Još nijedna stranica nije izabrana", + "field.pages.empty.single": "No page selected yet", + + "field.structure.delete.confirm": "Da li zaista želite da izbrišete ovaj red?", + "field.structure.delete.confirm.all": "Da li zaista želite da izbrišete sve unose?", + "field.structure.empty": "Još nema unosa", + + "field.users.empty": "Još nije izabran nijedan korisnik", + "field.users.empty.single": "No user selected yet", + + "fields.empty": "Još uvek nema polja", + + "file": "Datoteka", + "file.blueprint": "Ova datoteka još uvek nema nacrt. Možete definisati podešavanje u /site/blueprints/files/{blueprint}.yml", + "file.changeTemplate": "Promenite šablon", + "file.changeTemplate.notice": "Promena šablona datoteke će ukloniti sadržaj za polja koja se ne podudaraju po tipu. Ako novi šablon definiše određena pravila, npr. dimenzije slike, one će se takođe nepovratno primenjivati. Koristite sa oprezom.", + "file.delete.confirm": "Da li zaista želite da izbrišete
{filename}?", + "file.focus.placeholder": "Postavite fokusnu tačku", + "file.focus.reset": "Uklonite fokusnu tačku", + "file.focus.title": "Fokusirajte", + "file.sort": "Promena pozicije", + + "files": "Fajlovi", + "files.delete.confirm.selected": "Do you really want to delete the selected files? This action cannot be undone.", + "files.empty": "Još nema fajlova", + + "filter": "Filter", + + "form.discard": "Discard changes", + "form.discard.confirm": "Do you really want to discard all your changes?", + "form.locked": "This content is disabled for you as it is currently edited by another user", + "form.unsaved": "The current changes have not yet been saved", + "form.preview": "Preview changes", + "form.preview.draft": "Preview draft", + + "hide": "Sakriti", + "hour": "Čas", + "hue": "Nijansa", + "import": "Uvoz", + "info": "Info", + "insert": "Ubaci", + "insert.after": "Ubaciti posle", + "insert.before": "Ubaciti pre", + "install": "Instaliraj", + + "installation": "Instalacija", + "installation.completed": "Panel je instaliran", + "installation.disabled": "Instalater panela je podrazumevano onemogućen na javnim serverima. Molimo vas pokrenite instalater na lokalnoj mašini ili ga omogućite pomoću panel.install opcije", + "installation.issues.accounts": "Fascikla /site/accounts ne postoji ili u nju nije moguće pisati", + "installation.issues.content": "Fascikla /content ne postoji ili u nju nije moguće pisati", + "installation.issues.curl": "Proširenje CURL je potrebno", + "installation.issues.headline": "Panel se ne može instalirati", + "installation.issues.mbstring": "Proširenje MB String je potrebno", + "installation.issues.media": "Fascikla /media ne postoji ili u nju nije moguće pisati", + "installation.issues.php": "Obavezno koristite PHP 8+", + "installation.issues.sessions": "Fascikla /site/sessions ne postoji ili u nju nije moguće pisati", + + "language": "Jezik", + "language.code": "Kod", + "language.convert": "Postavi kao podrazumevano", + "language.convert.confirm": "

Da li zaista želite da konvertujete {name} na podrazumevani jezik? Ovo se ne može poništiti.

Ako{name} ima neprevedenog sadržaja, više neće postojati važeći rezervni deo i delovi vašeg sajta mogu biti prazni.

", + "language.create": "Dodajte novi jezik", + "language.default": "Podrazumevani jezik", + "language.delete.confirm": "Da li zaista želite da izbrišete jezik {name} uključujući sve prevode? Ovo se ne može poništiti!", + "language.deleted": "Jezik je obrisan", + "language.direction": "Smer čitanja", + "language.direction.ltr": "S leva nadesno", + "language.direction.rtl": "S desna nalevo", + "language.locale": "PHP locale string", + "language.locale.warning": "Koristite prilagođeni lokal. Molimo vas izmenite ga u jezičkoj datoteci u /site/languages", + "language.name": "Ime", + "language.secondary": "Sekundarni jezik", + "language.settings": "Podešavanja jezika", + "language.updated": "Jezik je ažuriran", + "language.variables": "Jezičke varijable", + "language.variables.empty": "Još uvek nema prevoda", + + "language.variable.delete.confirm": "Da li zaista želite da izbrišete promenljivu za {key}?", + "language.variable.entries": "Values", + "language.variable.entries.help": "Each string will be used for its matching count, e.g. three strings will match in order to counts 0, 1, 2 and more. Use the {count} placeholder to insert the actual count.", + "language.variable.key": "Ključ", + "language.variable.multiple": "Countable?", + "language.variable.multiple.text": "Use different translation strings", + "language.variable.multiple.help": "You can use different values depending on a count you pass along with the language variable, allowing you to create dynamic translations, e.g. singular and plural.", + "language.variable.notFound": "Promenljiva nije pronađena\n \n \n ", + "language.variable.value": "Vrednost", + + "languages": "Jezici", + "languages.default": "Podrazumevani jezik", + "languages.empty": "Još nema jezika", + "languages.secondary": "Sekundarni jezik", + "languages.secondary.empty": "Još nema sekundarnog jezika", + + "license": "Licenca", + "license.activate": "Aktivirajte ga sada", + "license.activate.label": "Molimo vas aktivirajte svoju licencu", + "license.activate.domain": "Vaša licenca će biti aktivirana za {host}.", + "license.activate.local": "Upravo ćete aktivirati svoju Kirby licencu za vaš lokalni domen {host}.Ako će ovaj sajt biti postavljen na javnom domenu, molimo vas aktivirajte ga tamo. Ako je {host} domen za koji želite da koristite svoju licencu, molimo vas nastavite.", + "license.activated": "Aktiviran", + "license.buy": "Kupite licencu", + "license.code": "Kod", + "license.code.help": "Nakon kupovine dobili ste svoju šifru licence putem email. Molimo vas da je kopirate i nalepite ovde.", + "license.code.label": "Molimo vas unesite šifru licence", + "license.status.active.info": "Uključuje nove glavne verzije do {date}", + "license.status.active.label": "Validna licenca", + "license.status.demo.info": "Ovo je demo instalacija", + "license.status.demo.label": "Demo", + "license.status.inactive.info": "Obnovite licencu da biste ažurirali na nove glavne verzije", + "license.status.inactive.label": "Nema novih glavnih verzija", + "license.status.legacy.bubble": "Da li ste spremni da obnovite svoju licencu?", + "license.status.legacy.info": "Vaša licenca ne pokriva ovu verziju", + "license.status.legacy.label": "Molimo vas obnovite vašu licencu", + "license.status.missing.bubble": "Da li ste spremni da pokrenete svoj sajt?", + "license.status.missing.info": "Nema važeće licence", + "license.status.missing.label": "Molimo vas aktivirajte svoju licencu", + "license.status.unknown.info": "The license status is unknown", + "license.status.unknown.label": "Unknown", + "license.manage": "Upravljajte svojom licencom", + "license.purchased": "Kupljeno", + "license.success": "Hvala vam što podržavate Kirby", + "license.unregistered.label": "Neregistrovan", + + "link": "Link", + "link.text": "Tekst veze", + + "loading": "Učitavanje", + + "lock.unsaved": "Nesačuvane promene", + "lock.unsaved.empty": "There are no unsaved changes", + "lock.unsaved.files": "Unsaved files", + "lock.unsaved.pages": "Unsaved pages", + "lock.unsaved.users": "Unsaved accounts", + "lock.isLocked": "Nesačuvane promene {email}", + "lock.unlock": "Otključati", + "lock.unlock.submit": "Otključajte i zamenite nesačuvane promene {email}", + "lock.isUnlocked": "Otključao ga je drugi korisnik", + + "login": "Prijavi se", + "login.code.label.login": "Kod za prijavu", + "login.code.label.password-reset": "Kod za resetovanje lozinke", + "login.code.placeholder.email": "000 000", + "login.code.placeholder.totp": "000000", + "login.code.text.email": "Ako je vaša adresa e-pošte registrovana, traženi kod je poslat putem e-pošte.", + "login.code.text.totp": "Molimo vas unesite jednokratni kod iz vaše aplikacije za autentifikaciju.", + "login.email.login.body": "Zdravo {user.nameOrEmail},\n\nNedavno ste zatražili kod za prijavu na panel {site}.\nSledeći kod za prijavu će biti važećii {timeout} minuta:\n\n{code}\n\nAko niste zahtevali kod za prijavu, zanemarite ovu e-poštu ili kontaktirajte svog administratora ako imate pitanja.\nIz bezbednosnih razloga, NEMOJTE prosleđivati ovu e-poštu.", + "login.email.login.subject": "Vaš kod za prijavu", + "login.email.password-reset.body": "Zdravo {user.nameOrEmail},\n\nNedavno ste zatražili kod za resetovanje lozinke za panel {site}.\nSledeći kod za resetovanje lozinke će biti važeći {timeout} minuta:\n\n{code}\n\nAko niste zahtevali kod za resetovanje lozinke, zanemarite ovu e-poštu ili kontaktirajte svog administratora ako imate pitanja.\nIz bezbednosnih razloga, NEMOJTE prosleđivati ovu e-poštu.", + "login.email.password-reset.subject": "Vaš kod za resetovanje lozinke", + "login.remember": "Ostavi me prijavljenog", + "login.reset": "Resetujte šifru", + "login.toggleText.code.email": "Prijavite se putem e-pošte", + "login.toggleText.code.email-password": "Prijavite se sa lozinkom", + "login.toggleText.password-reset.email": "Zaboravili ste lozinku?", + "login.toggleText.password-reset.email-password": "← Nazad na prijavu", + "login.totp.enable.option": "Podesite jednokratne kodove", + "login.totp.enable.intro": "Aplikacije autentifikacije mogu da generišu jednokratne kodove koji se koriste kao drugi faktor prilikom prijavljivanja na nalog.", + "login.totp.enable.qr.label": "1. Skenirajte ovaj QR kod", + "login.totp.enable.qr.help": "Ne možete da skenirate? Dodajte ključ za podešavanje{secret} manuelno u aplikaciji za autentifikaciju.", + "login.totp.enable.confirm.headline": "2. Potvrdite generisanim kodom", + "login.totp.enable.confirm.text": "Vaša aplikacija generiše novi jednokratni kod svakih 30 sekundi. Unesite trenutni kod da biste završili podešavanje:", + "login.totp.enable.confirm.label": "Trenutni kod", + "login.totp.enable.confirm.help": "Nakon ovog podešavanja, svaki put kada se prijavite tražićemo od vas jednokratni kod.", + "login.totp.enable.success": "Jednokratni kodovi su omogućeni", + "login.totp.disable.option": "Onemogućite jednokratne kodove", + "login.totp.disable.label": "Unesite lozinku da biste onemogućili jednokratne kodove", + "login.totp.disable.help": "U budućnosti, drugi faktor kao što je kod za prijavu poslat putem e-pošte biće zahtevan kada se prijavite. Jednokratne kodove uvek možete ponovo da podesite kasnije.", + "login.totp.disable.admin": "

Ovo će onemogućiti jednokratne kodove za{user}.

U budućnosti, drugi faktor kao što je kod za prijavu poslat putem e-pošte biće zahtevan kada se prijave. {user} može ponovo da podesi jednokratne kodove nakon sledećeg prijavljivanja", + "login.totp.disable.success": "Jednokratni kodovi su onemogućeni", + + "logout": "Odjavi se", + + "merge": "Spojite", + "menu": "Meni", + "meridiem": "AM/PM", + "mime": "Vrsta medija", + "minutes": "Minuti", + + "month": "Mesec", + "months.april": "April", + "months.august": "Avgust", + "months.december": "Decembar", + "months.february": "Februar", + "months.january": "Januar", + "months.july": "Jul", + "months.june": "Jun", + "months.march": "Mart", + "months.may": "Maj", + "months.november": "Novembar", + "months.october": "Oktobar", + "months.september": "Septembar", + + "more": "Više", + "move": "Pomerite", + "name": "Ime", + "next": "Sledeći", + "night": "Noć", + "no": "ne", + "off": "Isključeno", + "on": "Uključeno", + "open": "Otvorite", + "open.newWindow": "Otvorite u novom prozoru", + "option": "Opcija", + "options": "Opcije", + "options.none": "Nema opcija", + "options.all": "Prikaži sve {count} opcije", + + "orientation": "Orijentacija", + "orientation.landscape": "Predeo", + "orientation.portrait": "Portret", + "orientation.square": "Kvadrat", + + "page": "Stranica", + "page.blueprint": "Ova stranica još uvek nema blueprint. Možete definisati podešavanje u /site/blueprints/pages/{blueprint}.yml", + "page.changeSlug": "Promeni URL", + "page.changeSlug.fromTitle": "Napravi od naslova", + "page.changeStatus": "Promenite status", + "page.changeStatus.position": "Molimo izaberite poziciju", + "page.changeStatus.select": "Odaberite novi status", + "page.changeTemplate": "Promenite šablon", + "page.changeTemplate.notice": "Promena šablona stranice će ukloniti sadržaj za polja koja se ne podudaraju po tipu. Koristite sa oprezom.", + "page.create": "Kreirajte kao {status}", + "page.delete.confirm": "Da li zaista želite da izbrišete {title}?", + "page.delete.confirm.subpages": "Ova stranica ima podstranice.
Sve podstranice će takođe biti izbrisane.", + "page.delete.confirm.title": "Unesite naslov stranice da biste potvrdili", + "page.duplicate.appendix": "Kopiraj", + "page.duplicate.files": "Kopirajte fajlove", + "page.duplicate.pages": "Kopirajte stranice", + "page.move": "Premestite stranicu", + "page.sort": "Promena pozicije", + "page.status": "Status", + "page.status.draft": "Nacrt", + "page.status.draft.description": "Stranica je u radnom režimu i vidljiva je samo prijavljenim urednicima ili putem tajne veze", + "page.status.listed": "Javno", + "page.status.listed.description": "Stranica je javna za svakoga", + "page.status.unlisted": "Nenavedeno", + "page.status.unlisted.description": "Stranica je dostupna samo preko URL-a", + + "pages": "Stranice", + "pages.delete.confirm.selected": "Do you really want to delete the selected pages? This action cannot be undone.", + "pages.empty": "Još nema stranica", + "pages.status.draft": "Nacrti", + "pages.status.listed": "Objavljeno", + "pages.status.unlisted": "Neizlistano", + + "pagination.page": "Stranica", + + "password": "Lozinka", + "paste": "Zalepite", + "paste.after": "Zalepite posle", + "paste.success": "{count} zalepljen!", + "pixel": "Piksel", + "plugin": "Dodatak", + "plugins": "Dodaci", + "prev": "Prethodna", + "preview": "Pregled", + + "publish": "Publish", + "published": "Objavljeno", + + "remove": "Ukloniti", + "rename": "Preimenovati", + "renew": "Obnovite", + "replace": "Zameniti", + "replace.with": "Zamenite sa", + "retry": "Probajte ponovo", + "revert": "Vratiti se", + "revert.confirm": "Da li zaista želite da izbrišete sve nesačuvane promene?", + + "role": "Uloga", + "role.admin.description": "Administrator ima sva prava", + "role.admin.title": "Administrator", + "role.all": "Sve", + "role.empty": "Nema korisnika sa ovom ulogom", + "role.description.placeholder": "Nema opisa", + "role.nobody.description": "Ovo je rezervna uloga bez ikakvih dozvola", + "role.nobody.title": "Niko", + + "save": "Sačuvaj", + "saved": "Saved", + "search": "Pretraga", + "searching": "Searching", + "search.min": "Unesite {min} karakter za pretragu", + "search.all": "Prikaži sve {count} rezultate ", + "search.results.none": "Nema rezultata", + + "section.invalid": "Odeljak je nevažeći", + "section.required": "Odeljak je obavezan", + + "security": "Bezbednost", + "select": "Izaberite", + "server": "Server", + "settings": "Podešavanja", + "show": "Prikaži", + "site.blueprint": "Sajt još nema plan. Možete definisati podešavanje u /site/blueprints/site.yml", + "size": "Veličina", + "slug": "URL dodatak", + "sort": "Vrsta", + "sort.drag": "Prevucite da biste sortirali…", + "split": "Razdeliti", + + "stats.empty": "Nema izveštaja", + "status": "Status", + + "system.info.copy": "Copy info", + "system.info.copied": "System info copied", + "system.issues.content": "Čini se da je fascikla sa sadržajem izložena", + "system.issues.eol.kirby": "Vaša instalirana Kirby verzija je stigla do kraja svog životnog veka i neće dobijati dalja bezbednosna ažuriranja", + "system.issues.eol.plugin": "Vaša instalirana verzija { plugin } dodatka je stigla do kraja svog životnog veka i neće dobijati dalja bezbednosna ažuriranja", + "system.issues.eol.php": "Vaše instalirano PHP izdanje { release } je dostiglo kraj svog životnog veka i neće dobijati dalja bezbednosna ažuriranja", + "system.issues.debug": "Otklanjanje grešaka mora biti isključeno u proizvodnji", + "system.issues.git": "Čini se da je .git fascikla izložena", + "system.issues.https": "Preporučujemo HTTPS za sve vaše sajtove", + "system.issues.kirby": "Čini se da je Kirby fascikla izložena", + "system.issues.local": "The site is running locally with relaxed security checks", + "system.issues.site": "Čini se da je fascikla sajta izložena", + "system.issues.vue.compiler": "The Vue template compiler is enabled", + "system.issues.vulnerability.kirby": "Na vašu instalaciju može uticati sledeća ranjivost ({ severity } severity): { description }", + "system.issues.vulnerability.plugin": "Na vašu instalaciju može uticati sledeća ranjivost u { plugin } dodatku ({ severity } severity): { description }", + "system.updateStatus": "Ažuriraj status", + "system.updateStatus.error": "Provera ažuriranja nije uspela", + "system.updateStatus.not-vulnerable": "Nema poznatih ranjivosti", + "system.updateStatus.security-update": "Dostupna besplatna bezbednosna { version } nadogradnja", + "system.updateStatus.security-upgrade": "Nadogradnja { version } sa dostupnim bezbednosnim ispravkama", + "system.updateStatus.unreleased": "Neobjavljena verzija", + "system.updateStatus.up-to-date": "Do datuma", + "system.updateStatus.update": "Dostupno besplatno { version } ažuriranje", + "system.updateStatus.upgrade": "Nadogradnja je { version } dostupna", + + "tel": "Telefon", + "tel.placeholder": "+49123456789", + "template": "Šablon", + + "theme": "Theme", + "theme.light": "Lights on", + "theme.dark": "Lights off", + "theme.automatic": "Match system default", + + "title": "Naslov", + "today": "Danas", + + "toolbar.button.clear": "Očisti formatiranje", + "toolbar.button.code": "Kod", + "toolbar.button.bold": "Bold", + "toolbar.button.email": "Email", + "toolbar.button.headings": "Zaglavlje", + "toolbar.button.heading.1": "Zaglavlje 1", + "toolbar.button.heading.2": "Zaglavlje 2", + "toolbar.button.heading.3": "Zaglavlje 3", + "toolbar.button.heading.4": "Zaglavlje 4", + "toolbar.button.heading.5": "Zaglavlje 5", + "toolbar.button.heading.6": "Zaglavlje 6", + "toolbar.button.italic": "Italic", + "toolbar.button.file": "Datoteka", + "toolbar.button.file.select": "Izaberite datoteku", + "toolbar.button.file.upload": "Otpremite datoteku", + "toolbar.button.link": "Link", + "toolbar.button.paragraph": "Paragraf", + "toolbar.button.strike": "Precrtano", + "toolbar.button.sub": "Subscript", + "toolbar.button.sup": "Superscript", + "toolbar.button.ol": "Naručena lista", + "toolbar.button.underline": "Podvući", + "toolbar.button.ul": "Bullet list", + + "translation.author": "Branko Matić", + "translation.direction": "ltr", + "translation.name": "Srpski", + "translation.locale": "sr_RS@latin", + + "type": "Tip", + + "upload": "Otpremi", + "upload.error.cantMove": "Otpremljena datoteka nije mogla da se premesti", + "upload.error.cantWrite": "Neuspešno prebacivanje datoteka na disk", + "upload.error.default": "Nije moguće otpremiti datoteku", + "upload.error.extension": "Otpremanje datoteke je zaustavljeno ekstenzijom", + "upload.error.formSize": "Otpremljena datoteka premašuje MAX_FILE_SIZE direktivu koja je navedena u obrascu", + "upload.error.iniPostSize": "Otpremljena datoteka premašuje post_max_size direktivu u php.ini", + "upload.error.iniSize": "Otpremljena datoteka premašuje upload_max_filesize direktivu u php.ini", + "upload.error.noFile": "Nijedna datoteka nije otpremljena", + "upload.error.noFiles": "Nijedna datoteka nije otpremljena", + "upload.error.partial": "Otpremljena datoteka je samo delimično otpremljena", + "upload.error.tmpDir": "Nedostaje privremena fascikla", + "upload.errors": "Greška", + "upload.progress": "Otpremanje…", + + "url": "Url", + "url.placeholder": "https://example.com", + + "user": "Korisnik", + "user.blueprint": "Možete definisati dodatne odeljke i polja obrasca za ovu korisničku ulogu usite/blueprints/users/{blueprint}.yml", + "user.changeEmail": "Promenite E-mail", + "user.changeLanguage": "Promenite jezik", + "user.changeName": "Preimenujte ovog korisnika", + "user.changePassword": "Promenite lozinku", + "user.changePassword.current": "Your current password", + "user.changePassword.new": "Nova lozinka", + "user.changePassword.new.confirm": "Potvrdite novu lozinku…", + "user.changeRole": "Promenite ulogu", + "user.changeRole.select": "Izaberite novu ulogu", + "user.create": "Dodajte novog korisnika", + "user.delete": "Izbrišite ovog korisnika", + "user.delete.confirm": "Da li zaista želite da izbrišete
{email}?", + + "users": "Korisnici", + + "version": "Verzija", + "version.changes": "Changed version", + "version.compare": "Compare versions", + "version.current": "Trenutna verzija", + "version.latest": "Najnovija verzija", + "versionInformation": "Informacije o verziji", + + "view": "View", + "view.account": "Tvoj nalog", + "view.installation": "Instalacija", + "view.languages": "Jezici", + "view.resetPassword": "Resetujte šifru", + "view.site": "Sajt", + "view.system": "Sistem", + "view.users": "Korisnici", + + "welcome": "Dobrodošli", + "year": "Godina", + "yes": "Da" +} diff --git a/kirby/i18n/translations/zh_TW.json b/kirby/i18n/translations/zh_TW.json new file mode 100644 index 0000000..675c501 --- /dev/null +++ b/kirby/i18n/translations/zh_TW.json @@ -0,0 +1,799 @@ +{ + "account.changeName": "變更帳號名稱", + "account.delete": "刪除帳號", + "account.delete.confirm": "你確定要刪除這個帳號嗎?", + + "activate": "啟用", + "add": "\u65b0\u589e", + "alpha": "字母順序", + "author": "作者", + "avatar": "\u4f7f\u7528\u8005\u7167\u7247", + "back": "返回", + "cancel": "\u53d6\u6d88", + "change": "\u8b8a\u66f4", + "close": "\u95dc\u9589", + "changes": "變更", + "confirm": "儲存", + "collapse": "收合", + "collapse.all": "全部收合", + "color": "顏色", + "coordinates": "座標", + "copy": "Copy", + "copy.all": "全部複製", + "copy.success": "複製成功", + "copy.success.multiple": "{count} 資料已複製", + "copy.url": "複製網址", + "create": "建立", + "custom": "自訂", + + "date": "日期", + "date.select": "選擇日期", + + "day": "日", + "days.fri": "\u4e94", + "days.mon": "\u4e00", + "days.sat": "\u516d", + "days.sun": "\u65e5", + "days.thu": "\u56db", + "days.tue": "\u4e8c", + "days.wed": "\u4e09", + + "debugging": "除錯中", + + "delete": "\u522a\u9664", + "delete.all": "全部刪除", + + "dialog.fields.empty": "沒有可用的欄位", + "dialog.files.empty": "沒有可用的檔案", + "dialog.pages.empty": "沒有可用的頁面", + "dialog.text.empty": "沒有可用的文字", + "dialog.users.empty": "沒有可用的使用者", + + "dimensions": "尺寸", + "disable": "停用", + "disabled": "已停用", + "discard": "\u653e\u68c4", + + "drawer.fields.empty": "沒有欄位可顯示", + + "domain": "網域", + "download": "下載", + "duplicate": "建立副本", + + "edit": "\u7de8\u8f2f", + + "email": "電子郵件", + "email.placeholder": "mail@example.com", + + "enter": "輸入", + "entries": "資料項目", + "entry": "進入", + + "environment": "環境", + + "error": "錯誤", + "error.access.code": "無效的存取碼", + "error.access.login": "請先登入", + "error.access.panel": "你沒有進入控制台的權限", + "error.access.view": "你沒有瀏覽這個項目的權限", + + "error.avatar.create.fail": "無法建立使用者照片", + "error.avatar.delete.fail": "\u7121\u6cd5\u522a\u9664\u4f7f\u7528\u8005\u7167\u7247", + "error.avatar.dimensions.invalid": "請將個人檔案圖片的寬度和高度控製在 3000 畫素以下", + "error.avatar.mime.forbidden": "\u88ab\u7981\u6b62\u7684 mime \u985e\u578b", + + "error.blueprint.notFound": "無法載入藍圖「{name}」", + + "error.blocks.max.plural": "最多只能加入 {max} 個區塊", + "error.blocks.max.singular": "最多只能加入 1 個區塊", + "error.blocks.min.plural": "至少需要 {min} 個區塊", + "error.blocks.min.singular": "至少需要 1 個區塊", + "error.blocks.validation": "使用「{fieldset}」區塊類型的區塊 {index} 中的「{field}」欄位出錯", + + "error.cache.type.invalid": "無效快取類型 \"{type}\"", + + "error.content.lock.delete": "內容鎖定中,無法刪除", + "error.content.lock.move": "內容鎖定中,無法移動", + "error.content.lock.publish": "內容鎖定中,無法發佈", + "error.content.lock.replace": "內容鎖定中,無法替換", + "error.content.lock.update": "內容鎖定中,無法更新", + + "error.entries.max.plural": "最多只能加入 {max} 筆資料", + "error.entries.max.singular": "最多只能加入 1 筆資料", + "error.entries.min.plural": "至少需要 {min} 筆資料", + "error.entries.min.singular": "至少需要 1 筆資料", + "error.entries.supports": "「{type}」欄位類型不支援指定的資料類型", + "error.entries.validation": "行 {index} 中的「{field}」欄位出錯。", + + "error.email.preset.notFound": "找不到電子信箱預設設定「{name}」", + + "error.field.converter.invalid": "欄位轉換無效「{converter}」", + "error.field.link.options": "連結欄位的選項格式錯誤:「{options}」", + "error.field.type.missing": "欄位「{ name }」:欄位類型「{ type }」不存在", + + "error.file.changeName.empty": "請輸入新的檔名", + "error.file.changeName.permission": "你沒有變更「{filename}」檔名的權限", + "error.file.changeTemplate.invalid": "檔案「{id}」的樣板無法變更為「{template}」(有效:「{blueprints}」)。", + "error.file.changeTemplate.permission": "你沒有變更「{id}」樣板的權限", + + "error.file.delete.multiple": "刪除多個檔案時發生錯誤", + "error.file.duplicate": "檔案「{filename}」重複", + "error.file.extension.forbidden": "\u88ab\u7981\u6b62\u7684\u526f\u6a94\u540d", + "error.file.extension.invalid": "無效的副檔名:{extension}", + "error.file.extension.missing": "檔案「{filename}」沒有副檔名", + "error.file.maxheight": "檔案高度不能超過 {max} 像素", + "error.file.maxsize": "檔案太大", + "error.file.maxwidth": "檔案寬度不能超過 {max} 像素", + "error.file.mime.differs": "上傳的檔案必須是相同的 mime 類型「{mime}」", + "error.file.mime.forbidden": "不允許使用媒體類型「{mime}」。", + "error.file.mime.invalid": "無效的 MIME 類型:「{mime}」", + "error.file.mime.missing": "無法偵測「{filename}」檔案的媒體類型", + "error.file.minheight": "檔案高度不能小於 {min} 像素", + "error.file.minsize": "檔案太小", + "error.file.minwidth": "檔案寬度不能小於 {min} 像素", + "error.file.name.unique": "檔名已經存在", + "error.file.name.missing": "請輸入檔名", + "error.file.notFound": "\u627e\u4e0d\u5230\u6a94\u6848", + "error.file.orientation": "影像的方向必須是「{orientation}」", + "error.file.sort.permission": "你沒有變更「{filename}」排序的權限", + "error.file.type.forbidden": "此「{type}」的檔案不允許上傳", + "error.file.type.invalid": "無效的檔案類型:{filename}", + "error.file.undefined": "\u627e\u4e0d\u5230\u6a94\u6848", + + "error.form.incomplete": "表單尚未填寫完成", + "error.form.notSaved": "表單無法儲存,請檢查是否有錯誤", + + "error.language.code": "語言代碼無效", + "error.language.create.permission": "你沒有新增語言的權限", + "error.language.delete.permission": "你沒有刪除語言的權限", + "error.language.duplicate": "語言已經存在", + "error.language.name": "語言名稱無效", + "error.language.notFound": "找不到語言", + "error.language.update.permission": "你沒有變更語言設定的權限", + + "error.layout.validation.block": "在版面組態第 {layoutIndex} 區塊中,使用「{fieldset}」區塊類型的第 {blockIndex} 區塊內,欄位「{field}」發生錯誤", + "error.layout.validation.settings": "第 {index} 個版面組態的設定有誤", + + "error.license.domain": "授權的網域名稱無效或不符", + "error.license.email": "Please enter a valid email address", + "error.license.format": "授權碼格式錯誤", + "error.license.verification": "授權驗證失敗", + + "error.login.totp.confirm.invalid": "驗證碼無效,請重新確認", + "error.login.totp.confirm.missing": "請輸入驗證碼", + + "error.object.validation": "欄位「{label}」有錯誤:\n{message}", + + "error.offline": "系統目前離線,請稍後再試", + + "error.page.changeSlug.permission": "\u7121\u6cd5\u66f4\u6539\u9801\u9762 URL", + "error.page.changeSlug.reserved": "頂層頁面的路徑不得以「{path}」作為開頭", + "error.page.changeStatus.incomplete": "請填寫所有必要欄位後再變更狀態", + "error.page.changeStatus.permission": "你沒有變更頁面狀態的權限", + "error.page.changeStatus.toDraft.invalid": "頁面「{slug}」無法轉換為草稿狀態", + "error.page.changeTemplate.invalid": "頁面「{slug}」的樣板無法變更", + "error.page.changeTemplate.permission": "你沒有變更「{slug}」樣板的權限", + "error.page.changeTitle.empty": "請輸入頁面標題", + "error.page.changeTitle.permission": "你沒有變更「{slug}」標題的權限", + "error.page.create.permission": "你沒有建立「{slug}」標題的權限", + "error.page.delete": "無法刪除頁面「{slug}」", + "error.page.delete.confirm": "你確定要刪除這個頁面嗎?", + "error.page.delete.hasChildren": "此頁面下有子頁面,請先刪除子頁面", + "error.page.delete.multiple": "刪除多個頁面時發生錯誤", + "error.page.delete.permission": "你沒有刪除「{slug}」的權限", + "error.page.draft.duplicate": "已經有草稿頁面使用「{slug}」作為網址附加碼", + "error.page.duplicate": "已有使用網址附加碼「{slug}」的頁面存在", + "error.page.duplicate.permission": "你沒有複製「{slug}」的權限", + "error.page.move.ancestor": "無法移動到其子孫頁面下", + "error.page.move.directory": "移動頁面失敗,資料夾錯誤", + "error.page.move.duplicate": "已有使用網址附加碼「{slug}」的子頁面存在", + "error.page.move.noSections": "頁面「{parent}」因藍圖中未包含任何頁面區段,無法成為其他頁面的上層頁面", + "error.page.move.notFound": "找不到要移動的頁面", + "error.page.move.permission": "你沒有移動「{slug}」的權限", + "error.page.move.template": "樣板「{template}」不被允許作為「{parent}」的子頁面", + "error.page.notFound": "\u627e\u4e0d\u5230\u9801\u9762", + "error.page.num.invalid": "頁面排序編號無效", + "error.page.slug.invalid": "頁面網址無效,只能使用小寫英數、連字號與底線", + "error.page.slug.maxlength": "網址附加碼長度必須少於 {length} 個字元", + "error.page.sort.permission": "頁面「{slug}」無法進行排序", + "error.page.status.invalid": "頁面狀態無效", + "error.page.undefined": "\u627e\u4e0d\u5230\u9801\u9762", + "error.page.update.permission": "你沒有更新「{slug}」的權限", + + "error.section.files.max.plural": "「{section}」區段中最多只能加入 {max} 個檔案", + "error.section.files.max.singular": "「{section}」區段中最多只能加入 1 個檔案", + "error.section.files.min.plural": "「{section}」區段中至少需要 {min} 個檔案", + "error.section.files.min.singular": "「{section}」區段中至少需要 1 個檔案", + + "error.section.pages.max.plural": "「{section}」區段中最多只能加入 {max} 個頁面", + "error.section.pages.max.singular": "「{section}」區段中最多只能加入 1 個頁面", + "error.section.pages.min.plural": "「{section}」區段中至少需要 {min} 個頁面", + "error.section.pages.min.singular": "「{section}」區段中至少需要 1 個頁面", + + "error.section.notLoaded": "無法載入「{name}」區段", + "error.section.type.invalid": "區段類型「{type}」無效", + + "error.site.changeTitle.empty": "網站標題不得為空", + "error.site.changeTitle.permission": "你沒有變更網站標題的權限", + "error.site.update.permission": "你沒有變更網站設定的權限", + + "error.structure.validation": "第 {index} 列的「{field}」欄位發生錯誤", + + "error.template.default.notFound": "找不到預設樣板", + + "error.unexpected": "發生未預期的錯誤!如需更多資訊,請啟用除錯模式:https://getkirby.com/docs/reference/system/options/debug", + + "error.user.changeEmail.permission": "你沒有變更使用者「{name}」電子郵件的權限", + "error.user.changeLanguage.permission": "你沒有變更使用者「{name}」語言的權限", + "error.user.changeName.permission": "你沒有變更使用者「{name}」名稱的權限", + "error.user.changePassword.permission": "你沒有變更使用者「{name}」密碼的權限", + "error.user.changeRole.lastAdmin": "無法取消最後一位管理員的權限", + "error.user.changeRole.permission": "你沒有變更使用者「{name}」角色的權限", + "error.user.changeRole.toAdmin": "你無法將自己升級為管理員", + "error.user.create.permission": "你沒有新增使用者的權限", + "error.user.delete": "\u8a72\u4f7f\u7528\u8005\u4e0d\u53ef\u88ab\u522a\u9664", + "error.user.delete.lastAdmin": "\u4f60\u7121\u6cd5\u522a\u9664\u6700\u5f8c\u7684\u7ba1\u7406\u8005", + "error.user.delete.lastUser": "無法刪除最後一位使用者", + "error.user.delete.permission": "\u4f60\u7121\u6cd5\u4fee\u6539\u6b64\u4f7f\u7528\u8005", + "error.user.duplicate": "已有使用者使用電子郵件位址「{email}」", + "error.user.email.invalid": "Please enter a valid email address", + "error.user.language.invalid": "無效的語言代碼", + "error.user.notFound": "\u627e\u4e0d\u5230\u4f7f\u7528\u8005", + "error.user.password.excessive": "請輸入有效的密碼。密碼長度不得超過 1000 個字元。", + "error.user.password.invalid": "請輸入有效的密碼。密碼長度至少需為 8 個字元。", + "error.user.password.notSame": "\u8acb\u78ba\u8a8d\u5bc6\u78bc\u7121\u8aa4", + "error.user.password.undefined": "請輸入密碼", + "error.user.password.wrong": "密碼錯誤", + "error.user.role.invalid": "權限設定無效", + "error.user.undefined": "找不到使用者", + "error.user.update.permission": "你沒有更新使用者「{name}」的權限", + + "error.validation.accepted": "請勾選此選項", + "error.validation.alpha": "只能包含英文字母", + "error.validation.alphanum": "僅能輸入 a-z 的英文字母或數字 0-9", + "error.validation.anchor": "無效的錨點格式", + "error.validation.between": "必須介於 {min} 到 {max} 之間", + "error.validation.boolean": "請選擇是或否", + "error.validation.color": "請輸入有效的顏色,格式需為 {format}", + "error.validation.contains": "必須包含「{value}」", + "error.validation.date": "無效的日期格式", + "error.validation.date.after": "日期必須晚於 {date}", + "error.validation.date.before": "日期必須早於 {date}", + "error.validation.date.between": "日期必須介於 {min} 到 {max} 之間", + "error.validation.denied": "不允許的值", + "error.validation.different": "此欄位必須與 {other} 不同", + "error.validation.email": "Please enter a valid email address", + "error.validation.endswith": "必須以「{value}」結尾", + "error.validation.filename": "無效的檔名", + "error.validation.in": "請輸入以下其中一項:({in})", + "error.validation.integer": "請輸入整數", + "error.validation.ip": "請輸入有效的 IP 位址", + "error.validation.less": "數值必須小於 {max}", + "error.validation.linkType": "無效的連結類型", + "error.validation.match": "格式不正確", + "error.validation.max": "數值不得超過 {max}", + "error.validation.maxlength": "請輸入較短的內容(最多 {max} 個字元)", + "error.validation.maxwords": "請輸入不超過 {max} 個詞語 (words)", + "error.validation.min": "數值不得小於 {min}", + "error.validation.minlength": "請輸入較長的內容(至少 {min} 個字元)", + "error.validation.minwords": "請輸入至少 {min} 個詞語(words)", + "error.validation.more": "數值必須大於 {min}", + "error.validation.notcontains": "不得包含「{value}」", + "error.validation.notin": "請不要輸入以下任一項:({notIn})", + "error.validation.option": "請選擇有效的選項", + "error.validation.num": "請輸入數字", + "error.validation.required": "此欄位為必填", + "error.validation.same": "此欄位必須與 {other} 相同", + "error.validation.size": "大小必須為 {size}", + "error.validation.startswith": "必須以「{value}」開頭", + "error.validation.tel": "請輸入有效的電話號碼", + "error.validation.time": "無效的時間格式", + "error.validation.time.after": "時間必須晚於 {time}", + "error.validation.time.before": "時間必須早於 {time}", + "error.validation.time.between": "時間必須介於 {min} 到 {max} 之間", + "error.validation.uuid": "請輸入有效的 UUID", + "error.validation.url": "請輸入有效的網址", + + "expand": "展開", + "expand.all": "全部展開", + + "field.invalid": "欄位無效", + "field.required": "此欄位為必填", + "field.blocks.changeType": "變更區塊類型", + "field.blocks.code.name": "程式碼", + "field.blocks.code.language": "慣用語言", + "field.blocks.code.placeholder": "輸入程式碼…", + "field.blocks.delete.confirm": "你確定要刪除這個區塊嗎?", + "field.blocks.delete.confirm.all": "你確定要刪除所有區塊嗎?", + "field.blocks.delete.confirm.selected": "你確定要刪除已選取的區塊嗎?", + "field.blocks.empty": "尚未加入任何區塊", + "field.blocks.fieldsets.empty": "沒有可用的區塊類型", + "field.blocks.fieldsets.label": "新增區塊", + "field.blocks.fieldsets.paste": "按下 {{shortcut}} 可從剪貼簿匯入版面/區塊,僅會插入目前欄位允許的區塊類型。", + "field.blocks.gallery.name": "圖集", + "field.blocks.gallery.images.empty": "尚未加入圖片", + "field.blocks.gallery.images.label": "圖片", + "field.blocks.heading.level": "標題層級", + "field.blocks.heading.name": "標題", + "field.blocks.heading.text": "標題文字", + "field.blocks.heading.placeholder": "輸入標題…", + "field.blocks.figure.back.plain": "純色背景", + "field.blocks.figure.back.pattern.light": "圖樣(亮色)", + "field.blocks.figure.back.pattern.dark": "圖樣(暗色)", + "field.blocks.image.alt": "替代文字", + "field.blocks.image.caption": "圖片說明", + "field.blocks.image.crop": "裁切", + "field.blocks.image.link": "連結", + "field.blocks.image.location": "圖片位置", + "field.blocks.image.location.internal": "內部上傳", + "field.blocks.image.location.external": "外部連結", + "field.blocks.image.name": "圖片", + "field.blocks.image.placeholder": "拖曳或點擊以選擇圖片", + "field.blocks.image.ratio": "顯示比例", + "field.blocks.image.url": "圖片網址", + "field.blocks.line.name": "分隔線", + "field.blocks.list.name": "清單", + "field.blocks.markdown.name": "Markdown", + "field.blocks.markdown.label": "內容", + "field.blocks.markdown.placeholder": "輸入 Markdown 內容…", + "field.blocks.quote.name": "引言", + "field.blocks.quote.text.label": "引言內容", + "field.blocks.quote.text.placeholder": "輸入引言文字…", + "field.blocks.quote.citation.label": "出處", + "field.blocks.quote.citation.placeholder": "輸入引用來源…", + "field.blocks.text.name": "段落", + "field.blocks.text.placeholder": "輸入段落內容…", + "field.blocks.video.autoplay": "自動播放", + "field.blocks.video.caption": "影片說明", + "field.blocks.video.controls": "顯示控制列", + "field.blocks.video.location": "影片位置", + "field.blocks.video.loop": "重複播放", + "field.blocks.video.muted": "靜音", + "field.blocks.video.name": "影片", + "field.blocks.video.placeholder": "貼上影片網址或拖曳影片", + "field.blocks.video.poster": "預覽縮圖", + "field.blocks.video.preload": "預先載入", + "field.blocks.video.url.label": "影片網址", + "field.blocks.video.url.placeholder": "https://youtube.com/?v=", + + "field.entries.delete.confirm.all": "你確定要刪除所有資料嗎?", + "field.entries.empty": "還沒有資料", + + "field.files.empty": "沒有選取任何檔案", + "field.files.empty.single": "尚未選取檔案", + + "field.layout.change": "變更版面配置", + "field.layout.delete": "刪除版面", + "field.layout.delete.confirm": "你確定要刪除這個版面嗎?", + "field.layout.delete.confirm.all": "你確定要刪除所有版面嗎?", + "field.layout.empty": "尚未設定任何版面", + "field.layout.select": "選擇版面", + + "field.object.empty": "尚未填寫內容", + + "field.pages.empty": "沒有選取任何頁面", + "field.pages.empty.single": "尚未選取頁面", + + "field.structure.delete.confirm": "\u4f60\u771f\u7684\u8981\u522a\u9664\u6b64\u7b46\u8cc7\u6599\u55ce\uff1f", + "field.structure.delete.confirm.all": "你確定要刪除所有資料嗎?", + "field.structure.empty": "尚未加入任何資料", + + "field.users.empty": "沒有選取任何使用者", + "field.users.empty.single": "尚未選取使用者", + + "fields.empty": "此頁面沒有設定欄位", + + "file": "檔案", + "file.blueprint": "此檔案尚未設定藍圖。你可以在 /site/blueprints/files/{blueprint}.yml 中定義設定內容", + "file.changeTemplate": "變更樣板", + "file.changeTemplate.notice": "變更樣板可能會導致資料遺失", + "file.delete.confirm": "\u78ba\u8a8d\u522a\u9664\u6a94\u6848\uff1f", + "file.focus.placeholder": "選取聚焦區域", + "file.focus.reset": "重設焦點", + "file.focus.title": "圖片焦點", + "file.sort": "變更檔案順序", + + "files": "附加檔案", + "files.delete.confirm.selected": "你確定要刪除已選取的檔案嗎?", + "files.empty": "此處沒有檔案", + + "filter": "篩選", + + "form.discard": "放棄變更", + "form.discard.confirm": "你確定要放棄未儲存的變更嗎?", + "form.locked": "此表單已鎖定,無法編輯", + "form.unsaved": "尚有未儲存的變更", + "form.preview": "預覽內容", + "form.preview.draft": "預覽草稿", + + "hide": "隱藏", + "hour": "時", + "hue": "色相", + "import": "匯入", + "info": "資訊", + "insert": "\u63d2\u5165", + "insert.after": "插入在後", + "insert.before": "插入在前", + "install": "安裝", + + "installation": "安裝", + "installation.completed": "安裝完成", + "installation.disabled": "安裝功能已停用", + "installation.issues.accounts": "\u60a8\u6c92\u6709\u300c\/site\/accounts\u300d\u8cc7\u6599\u593e\u7684\u4fee\u6539\u6b0a\u9650", + "installation.issues.content": "\u60a8\u6c92\u6709\u300c\/content\u300d\u8cc7\u6599\u593e\u7684\u4fee\u6539\u6b0a\u9650", + "installation.issues.curl": "伺服器未啟用 cURL,可能會導致某些功能無法使用", + "installation.issues.headline": "請先解決下列安裝問題:", + "installation.issues.mbstring": "PHP 尚未啟用 mbstring 擴充套件", + "installation.issues.media": "無法建立 /media 資料夾或寫入權限不足", + "installation.issues.php": "請確保使用 PHP 8 以上版本", + "installation.issues.sessions": "PHP sessions 未正確啟用,請檢查伺服器設定", + + "language": "\u6163\u7528\u8a9e\u8a00", + "language.code": "語言代碼", + "language.convert": "轉換語言", + "language.convert.confirm": "你確定要將所有內容轉換為此語言嗎?你確定要將「{name}」轉換為預設語言嗎?此操作無法還原。\n如果「{name}」中有未翻譯的內容,將不會有可用的預設語言做為備援,可能會導致網站部份內容為空。", + "language.create": "新增語言", + "language.default": "預設語言", + "language.delete.confirm": "你確定要刪除語言「{name}」及其所有翻譯內容嗎?此操作無法還原!", + "language.deleted": "語言已刪除", + "language.direction": "書寫方向", + "language.direction.ltr": "由左至右", + "language.direction.rtl": "由右至左", + "language.locale": "PHP 語系字串", + "language.locale.warning": "請確認區域設定符合 PHP 認可的格式", + "language.name": "語言名稱", + "language.secondary": "次要語言", + "language.settings": "語言設定", + "language.updated": "語言已更新", + "language.variables": "語言變數", + "language.variables.empty": "尚未設定語言變數", + + "language.variable.delete.confirm": "你確定要刪除「{key}」這個變數嗎?", + "language.variable.entries": "Values", + "language.variable.entries.help": "Each string will be used for its matching count, e.g. three strings will match in order to counts 0, 1, 2 and more. Use the {count} placeholder to insert the actual count.", + "language.variable.key": "變數名稱", + "language.variable.multiple": "Countable?", + "language.variable.multiple.text": "Use different translation strings", + "language.variable.multiple.help": "You can use different values depending on a count you pass along with the language variable, allowing you to create dynamic translations, e.g. singular and plural.", + "language.variable.notFound": "找不到指定的語言變數", + "language.variable.value": "變數內容", + + "languages": "語言清單", + "languages.default": "預設語言", + "languages.empty": "尚未設定語言", + "languages.secondary": "次要語言清單", + "languages.secondary.empty": "尚未設定次要語言", + + "license": "Kirby \u6191\u8b49", + "license.activate": "啟用授權", + "license.activate.label": "輸入您的授權碼以啟用 Kirby", + "license.activate.domain": "你的授權將會啟用於 {host}", + "license.activate.local": "你即將為本機網域 {host} 啟用你的 Kirby 授權。\n如果這個網站將部署到公開網域,請改為在公開網域上啟用授權。\n如果 {host} 就是你要使用授權的網域,請繼續操作。", + "license.activated": "授權已啟用", + "license.buy": "購買授權", + "license.code": "授權碼", + "license.code.help": "您可以在購買確認信中找到授權碼", + "license.code.label": "輸入授權碼", + "license.status.active.info": "包含至 {date} 前的新主要版本", + "license.status.active.label": "已啟用", + "license.status.demo.info": "此為試用版安裝,僅供開發或測試使用", + "license.status.demo.label": "試用中", + "license.status.inactive.info": "此網站尚未啟用授權", + "license.status.inactive.label": "未啟用", + "license.status.legacy.bubble": "舊版授權", + "license.status.legacy.info": "此授權使用的是舊版授權機制", + "license.status.legacy.label": "舊版授權", + "license.status.missing.bubble": "缺少授權", + "license.status.missing.info": "請輸入有效授權碼以使用 Kirby", + "license.status.missing.label": "未授權", + "license.status.unknown.info": "無法確認授權狀態,請檢查您的網路連線", + "license.status.unknown.label": "未知狀態", + "license.manage": "管理授權", + "license.purchased": "您已購買授權", + "license.success": "授權啟用成功", + "license.unregistered.label": "未註冊", + + "link": "\u9023\u7d50", + "link.text": "\u9023\u7d50\u6587\u5b57", + + "loading": "載入中…", + + "lock.unsaved": "有尚未儲存的變更", + "lock.unsaved.empty": "所有變更已儲存", + "lock.unsaved.files": "有檔案變更尚未儲存", + "lock.unsaved.pages": "有頁面變更尚未儲存", + "lock.unsaved.users": "有使用者變更尚未儲存", + "lock.isLocked": "{email} 尚未儲存的變更", + "lock.unlock": "解除鎖定", + "lock.unlock.submit": "解鎖並覆蓋 {email} 尚未儲存的變更", + "lock.isUnlocked": "目前已解除鎖定", + + "login": "登入", + "login.code.label.login": "使用一次性登入碼登入", + "login.code.label.password-reset": "重設密碼的安全碼", + "login.code.placeholder.email": "000 000", + "login.code.placeholder.totp": "000000", + "login.code.text.email": "我們已寄送一組登入連結至你的電子信箱", + "login.code.text.totp": "請輸入兩步驟驗證碼", + "login.email.login.body": "嗨 {user.nameOrEmail},\n\n你最近請求了 {site} 控製臺的登入驗證碼。\n以下驗證碼在 {timeout} 分鐘內有效:\n\n{code}\n\n如果你並未請求此驗證碼,請忽略此封信;如有疑問,請聯絡你的管理員。\n為了安全起見,請不要轉寄此封電子郵件。", + "login.email.login.subject": "您的 Kirby 登入連結", + "login.email.password-reset.body": "嗨 {user.nameOrEmail},\n\n你最近請求了 {site} 控製臺的密碼重設驗證碼。\n以下驗證碼在 {timeout} 分鐘內有效:\n\n{code}\n\n如果你並未請求此驗證碼,請忽略此封信;如有疑問,請聯絡你的管理員。\n為了安全起見,請不要轉寄此封電子郵件。", + "login.email.password-reset.subject": "您的 Kirby 密碼重設連結", + "login.remember": "記住我", + "login.reset": "重設密碼", + "login.toggleText.code.email": "使用電子信箱登入", + "login.toggleText.code.email-password": "使用電子信箱與密碼登入", + "login.toggleText.password-reset.email": "忘記密碼?使用電子信箱重設", + "login.toggleText.password-reset.email-password": "返回使用密碼登入", + "login.totp.enable.option": "設定一次性驗證碼", + "login.totp.enable.intro": "增加帳號安全性,需使用驗證器應用程式", + "login.totp.enable.qr.label": "1. 掃描這個 QR 碼", + "login.totp.enable.qr.help": "無法掃描嗎?請將設定金鑰 {secret} 手動加入你的驗證器 App。", + "login.totp.enable.confirm.headline": "2. 使用產生的驗證碼進行確認", + "login.totp.enable.confirm.text": "你的 App 每 30 秒會產生一組新的一次性驗證碼。請輸入目前的驗證碼以完成設定:", + "login.totp.enable.confirm.label": "驗證碼", + "login.totp.enable.confirm.help": "來自驗證器 App 的 6 位數碼", + "login.totp.enable.success": "已成功啟用兩步驟驗證", + "login.totp.disable.option": "停用兩步驟驗證", + "login.totp.disable.label": "停用驗證", + "login.totp.disable.help": "您的帳號將不再需要驗證器登入", + "login.totp.disable.admin": "這將會停用 {user} 的一次性驗證碼。\n未來他們登入時,系統會改為要求其他第二驗證方式,例如透過電子郵件傳送的登入碼。\n{user} 可於下次登入後重新設定一次性驗證碼。", + "login.totp.disable.success": "已成功停用兩步驟驗證", + + "logout": "登出", + + "merge": "合併", + "menu": "選單", + "meridiem": "上午/下午", + "mime": "MIME 類型", + "minutes": "分鐘", + + "month": "月", + "months.april": "\u56db\u6708", + "months.august": "\u516b\u6708", + "months.december": "\u5341\u4e8c\u6708", + "months.february": "二月", + "months.january": "\u4e00\u6708", + "months.july": "\u4e03\u6708", + "months.june": "\u516d\u6708", + "months.march": "\u4e09\u6708", + "months.may": "\u4e94\u6708", + "months.november": "\u5341\u4e00\u6708", + "months.october": "\u5341\u6708", + "months.september": "\u4e5d\u6708", + + "more": "更多", + "move": "移動", + "name": "名稱", + "next": "下一步", + "night": "夜間", + "no": "否", + "off": "關閉", + "on": "開啟", + "open": "開啟", + "open.newWindow": "在新視窗開啟", + "option": "選項", + "options": "多選項", + "options.none": "無可用選項", + "options.all": "顯示全部 {count} 個選項", + + "orientation": "方向", + "orientation.landscape": "橫向", + "orientation.portrait": "直向", + "orientation.square": "正方形", + + "page": "頁", + "page.blueprint": "此頁面尚未設定藍圖。你可以在 /site/blueprints/pages/{blueprint}.yml 中定義設定內容。", + "page.changeSlug": "\u66f4\u6539\u9801\u9762\u7db2\u5740", + "page.changeSlug.fromTitle": "\u5f9e\u9801\u9762\u6a19\u984c\u8f38\u5165", + "page.changeStatus": "變更狀態", + "page.changeStatus.position": "頁面位置", + "page.changeStatus.select": "選擇狀態", + "page.changeTemplate": "變更樣板", + "page.changeTemplate.notice": "變更樣板可能會導致部分資料遺失,請小心操作", + "page.create": "建立為 {status}", + "page.delete.confirm": "\u78ba\u8a8d\u522a\u9664\u6b64\u9801\u9762\uff1f", + "page.delete.confirm.subpages": "此頁面下仍有子頁面,是否一併刪除?", + "page.delete.confirm.title": "請輸入頁面標題以確認", + "page.duplicate.appendix": "Copy", + "page.duplicate.files": "複製檔案", + "page.duplicate.pages": "複製子頁面", + "page.move": "移動頁面", + "page.sort": "排序頁面", + "page.status": "頁面狀態", + "page.status.draft": "草稿", + "page.status.draft.description": "該頁面處於草稿模式,僅對已登入的編輯者或透過秘密連結可見", + "page.status.listed": "已列出", + "page.status.listed.description": "該頁面對所有人公開", + "page.status.unlisted": "未列出", + "page.status.unlisted.description": "該頁面僅能透過網址存取", + + "pages": "頁面", + "pages.delete.confirm.selected": "你確定要刪除所有選取的頁面嗎?", + "pages.empty": "目前沒有任何頁面", + "pages.status.draft": "草稿", + "pages.status.listed": "已列出", + "pages.status.unlisted": "未列出", + + "pagination.page": "頁", + + "password": "\u5bc6\u78bc", + "paste": "貼上", + "paste.after": "貼在後方", + "paste.success": "已貼上 {count} 個項目!", + "pixel": "像素", + "plugin": "外掛", + "plugins": "外掛列表", + "prev": "上一步", + "preview": "預覽", + + "publish": "發佈", + "published": "已發佈", + + "remove": "移除", + "rename": "重新命名", + "renew": "重新啟用", + "replace": "\u66f4\u63db", + "replace.with": "取代為…", + "retry": "\u91cd\u8a66", + "revert": "\u653e\u68c4", + "revert.confirm": "你確定要還原變更嗎?", + + "role": "\u6b0a\u9650", + "role.admin.description": "具有所有權限,可管理使用者與網站設定", + "role.admin.title": "管理員", + "role.all": "所有角色", + "role.empty": "尚未設定角色", + "role.description.placeholder": "角色描述…", + "role.nobody.description": "無法登入後台的訪客角色", + "role.nobody.title": "訪客", + + "save": "\u5132\u5b58", + "saved": "已儲存", + "search": "搜尋", + "searching": "搜尋中…", + "search.min": "請至少輸入 {min} 個字元", + "search.all": "顯示全部 {count} 筆結果", + "search.results.none": "找不到符合的結果", + + "section.invalid": "區段無效", + "section.required": "此區段為必填", + + "security": "安全性", + "select": "選取", + "server": "伺服器", + "settings": "設定", + "show": "顯示", + "site.blueprint": "網站藍圖", + "size": "大小", + "slug": "\u9801\u9762\u7db2\u5740", + "sort": "排序", + "sort.drag": "拖曳以排序", + "split": "分割", + + "stats.empty": "目前沒有統計資料", + "status": "狀態", + + "system.info.copy": "複製系統資訊", + "system.info.copied": "系統資訊已複製", + "system.issues.content": "無法寫入 /content 資料夾", + "system.issues.eol.kirby": "你正在使用已終止維護的 Kirby 版本", + "system.issues.eol.plugin": "你安裝的 {plugin} 外掛已達到生命週期終點,將不再收到安全性更新。", + "system.issues.eol.php": "你安裝的 PHP 版本 {release} 已達生命週期終點,將不再收到安全性更新。", + "system.issues.debug": "目前系統處於除錯模式", + "system.issues.git": "專案資料夾中未偵測到 Git 儲存庫", + "system.issues.https": "網站未透過 HTTPS 保護", + "system.issues.kirby": "Kirby 核心檔案可能已變更,請重新安裝", + "system.issues.local": "網站可能仍在本機開發環境中運行", + "system.issues.site": "找不到 site/config.php 或檔案設定錯誤", + "system.issues.vue.compiler": "Vue 樣板編譯器已啟用", + "system.issues.vulnerability.kirby": "你的安裝可能受到以下漏洞影響(嚴重性:{severity}):{description}", + "system.issues.vulnerability.plugin": "你的安裝可能受到 {plugin} 外掛中以下漏洞影響(嚴重性:{severity}):{description}", + "system.updateStatus": "更新狀態", + "system.updateStatus.error": "無法檢查更新狀態", + "system.updateStatus.not-vulnerable": "目前版本無安全漏洞", + "system.updateStatus.security-update": "有免費的安全性更新版本 {version} 可供下載", + "system.updateStatus.security-upgrade": "有包含安全修正的版本 {version} 可供升級", + "system.updateStatus.unreleased": "目前為尚未正式發佈的版本", + "system.updateStatus.up-to-date": "已是最新版本", + "system.updateStatus.update": "有免費更新版本 {version} 可供下載", + "system.updateStatus.upgrade": "可升級至版本 {version}", + + "tel": "電話", + "tel.placeholder": "+49123456789", + "template": "頁面樣板", + + "theme": "主題", + "theme.light": "亮色主題", + "theme.dark": "暗色主題", + "theme.automatic": "配合系統預設", + + "title": "頁面標題", + "today": "今天", + + "toolbar.button.clear": "清除格式", + "toolbar.button.code": "程式碼", + "toolbar.button.bold": "\u7c97\u9ad4", + "toolbar.button.email": "電子郵件", + "toolbar.button.headings": "標題", + "toolbar.button.heading.1": "標題 1", + "toolbar.button.heading.2": "標題 2", + "toolbar.button.heading.3": "標題 3", + "toolbar.button.heading.4": "標題 4", + "toolbar.button.heading.5": "標題 5", + "toolbar.button.heading.6": "標題 6", + "toolbar.button.italic": "\u659c\u9ad4", + "toolbar.button.file": "檔案", + "toolbar.button.file.select": "選擇檔案", + "toolbar.button.file.upload": "上傳檔案", + "toolbar.button.link": "\u9023\u7d50", + "toolbar.button.paragraph": "段落", + "toolbar.button.strike": "刪除線", + "toolbar.button.sub": "下標", + "toolbar.button.sup": "上標", + "toolbar.button.ol": "有序清單", + "toolbar.button.underline": "底線", + "toolbar.button.ul": "無序清單", + + "translation.author": "翻譯者", + "translation.direction": "ltr", + "translation.name": "正體中文", + "translation.locale": "zh_TW", + + "type": "類型", + + "upload": "上傳", + "upload.error.cantMove": "檔案無法移動到目標位置", + "upload.error.cantWrite": "檔案無法寫入磁碟", + "upload.error.default": "上傳時發生未知錯誤", + "upload.error.extension": "副檔名不被允許", + "upload.error.formSize": "檔案超出表單限制的大小", + "upload.error.iniPostSize": "檔案超出 PHP 設定中的最大值", + "upload.error.iniSize": "檔案大小超過上傳限制", + "upload.error.noFile": "沒有選擇任何檔案", + "upload.error.noFiles": "找不到任何可上傳的檔案", + "upload.error.partial": "檔案僅部分上傳", + "upload.error.tmpDir": "找不到暫存資料夾", + "upload.errors": "上傳錯誤", + "upload.progress": "上傳進度", + + "url": "網址", + "url.placeholder": "例如:https://example.com", + + "user": "使用者", + "user.blueprint": "你可以在 /site/blueprints/users/{blueprint}.yml 中為此使用者角色定義額外的區段與表單欄位。", + "user.changeEmail": "變更電子信箱", + "user.changeLanguage": "變更語言", + "user.changeName": "變更名稱", + "user.changePassword": "變更密碼", + "user.changePassword.current": "目前密碼", + "user.changePassword.new": "更改密碼", + "user.changePassword.new.confirm": "確認新密碼", + "user.changeRole": "變更角色", + "user.changeRole.select": "選擇新角色", + "user.create": "新增使用者", + "user.delete": "刪除使用者", + "user.delete.confirm": "你確定要刪除「{email}」嗎?", + + "users": "使用者", + + "version": "版本", + "version.changes": "版本變更紀錄", + "version.compare": "比較版本", + "version.current": "目前版本", + "version.latest": "最新版本", + "versionInformation": "版本資訊", + + "view": "檢視", + "view.account": "\u60a8\u7684\u5e33\u865f", + "view.installation": "\u5b89\u88dd", + "view.languages": "語言管理", + "view.resetPassword": "重設密碼", + "view.site": "網站設定", + "view.system": "系統資訊", + "view.users": "\u4f7f\u7528\u8005", + + "welcome": "歡迎使用 Kirby", + "year": "年", + "yes": "是" +} diff --git a/kirby/panel/dist/js/sortable.esm.min.js b/kirby/panel/dist/js/sortable.esm.min.js new file mode 100644 index 0000000..63fd425 --- /dev/null +++ b/kirby/panel/dist/js/sortable.esm.min.js @@ -0,0 +1,7 @@ +/**! + * Sortable 1.15.6 + * @author RubaXa + * @author owenm + * @license MIT + */ +function t(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);e&&(o=o.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,o)}return n}function e(e){for(var n=1;n=0||(i[n]=t[n]);return i}(t,e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(i[n]=t[n])}return i}function a(t){if("undefined"!=typeof window&&window.navigator)return!!navigator.userAgent.match(t)}var l=a(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i),s=a(/Edge/i),c=a(/firefox/i),u=a(/safari/i)&&!a(/chrome/i)&&!a(/android/i),d=a(/iP(ad|od|hone)/i),h=a(/chrome/i)&&a(/android/i),f={capture:!1,passive:!1};function p(t,e,n){t.addEventListener(e,n,!l&&f)}function g(t,e,n){t.removeEventListener(e,n,!l&&f)}function v(t,e){if(e){if(">"===e[0]&&(e=e.substring(1)),t)try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(n){return!1}return!1}}function m(t){return t.host&&t!==document&&t.host.nodeType?t.host:t.parentNode}function b(t,e,n,o){if(t){n=n||document;do{if(null!=e&&(">"===e[0]?t.parentNode===n&&v(t,e):v(t,e))||o&&t===n)return t;if(t===n)break}while(t=m(t))}return null}var y,w=/\s+/g;function E(t,e,n){if(t&&e)if(t.classList)t.classList[n?"add":"remove"](e);else{var o=(" "+t.className+" ").replace(w," ").replace(" "+e+" "," ");t.className=(o+(n?" "+e:"")).replace(w," ")}}function D(t,e,n){var o=t&&t.style;if(o){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];e in o||-1!==e.indexOf("webkit")||(e="-webkit-"+e),o[e]=n+("string"==typeof n?"":"px")}}function _(t,e){var n="";if("string"==typeof t)n=t;else do{var o=D(t,"transform");o&&"none"!==o&&(n=o+" "+n)}while(!e&&(t=t.parentNode));var i=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix||window.MSCSSMatrix;return i&&new i(n)}function S(t,e,n){if(t){var o=t.getElementsByTagName(e),i=0,r=o.length;if(n)for(;i=C(o)[n]))return o;if(o===T())break;o=P(o,!1)}return!1}function O(t,e,n,o){for(var i=0,r=0,a=t.children;r2&&void 0!==arguments[2]?arguments[2]:{},i=o.evt,a=r(o,W);L.pluginEvent.bind(Yt)(t,n,e({dragEl:U,parentEl:V,ghostEl:q,rootEl:Z,nextEl:K,lastDownEl:Q,cloneEl:$,cloneHidden:J,dragStarted:ht,putSortable:rt,activeSortable:Yt.active,originalEvent:i,oldIndex:tt,oldDraggableIndex:nt,newIndex:et,newDraggableIndex:ot,hideGhostForTarget:Pt,unhideGhostForTarget:It,cloneNowHidden:function(){J=!0},cloneNowShown:function(){J=!1},dispatchSortableEvent:function(t){G({sortable:n,name:t,originalEvent:i})}},a))};function G(t){!function(t){var n=t.sortable,o=t.rootEl,i=t.name,r=t.targetEl,a=t.cloneEl,c=t.toEl,u=t.fromEl,d=t.oldIndex,h=t.newIndex,f=t.oldDraggableIndex,p=t.newDraggableIndex,g=t.originalEvent,v=t.putSortable,m=t.extraEventProperties;if(n=n||o&&o[B]){var b,y=n.options,w="on"+i.charAt(0).toUpperCase()+i.substr(1);!window.CustomEvent||l||s?(b=document.createEvent("Event")).initEvent(i,!0,!0):b=new CustomEvent(i,{bubbles:!0,cancelable:!0}),b.to=c||o,b.from=u||o,b.item=r||o,b.clone=a,b.oldIndex=d,b.newIndex=h,b.oldDraggableIndex=f,b.newDraggableIndex=p,b.originalEvent=g,b.pullMode=v?v.lastPutMode:void 0;var E=e(e({},m),L.getEventProperties(i,n));for(var D in E)b[D]=E[D];o&&o.dispatchEvent(b),y[w]&&y[w].call(n,b)}}(e({putSortable:rt,cloneEl:$,targetEl:U,rootEl:Z,oldIndex:tt,oldDraggableIndex:nt,newIndex:et,newDraggableIndex:ot},t))}var U,V,q,Z,K,Q,$,J,tt,et,nt,ot,it,rt,at,lt,st,ct,ut,dt,ht,ft,pt,gt,vt,mt=!1,bt=!1,yt=[],wt=!1,Et=!1,Dt=[],_t=!1,St=[],Tt="undefined"!=typeof document,Ct=d,xt=s||l?"cssFloat":"float",Ot=Tt&&!h&&!d&&"draggable"in document.createElement("div"),Mt=function(){if(Tt){if(l)return!1;var t=document.createElement("x");return t.style.cssText="pointer-events:auto","auto"===t.style.pointerEvents}}(),Nt=function(t,e){var n=D(t),o=parseInt(n.width)-parseInt(n.paddingLeft)-parseInt(n.paddingRight)-parseInt(n.borderLeftWidth)-parseInt(n.borderRightWidth),i=O(t,0,e),r=O(t,1,e),a=i&&D(i),l=r&&D(r),s=a&&parseInt(a.marginLeft)+parseInt(a.marginRight)+C(i).width,c=l&&parseInt(l.marginLeft)+parseInt(l.marginRight)+C(r).width;if("flex"===n.display)return"column"===n.flexDirection||"column-reverse"===n.flexDirection?"vertical":"horizontal";if("grid"===n.display)return n.gridTemplateColumns.split(" ").length<=1?"vertical":"horizontal";if(i&&a.float&&"none"!==a.float){var u="left"===a.float?"left":"right";return!r||"both"!==l.clear&&l.clear!==u?"horizontal":"vertical"}return i&&("block"===a.display||"flex"===a.display||"table"===a.display||"grid"===a.display||s>=o&&"none"===n[xt]||r&&"none"===n[xt]&&s+c>o)?"vertical":"horizontal"},At=function(t){function e(t,n){return function(o,i,r,a){var l=o.options.group.name&&i.options.group.name&&o.options.group.name===i.options.group.name;if(null==t&&(n||l))return!0;if(null==t||!1===t)return!1;if(n&&"clone"===t)return t;if("function"==typeof t)return e(t(o,i,r,a),n)(o,i,r,a);var s=(n?o:i).options.group.name;return!0===t||"string"==typeof t&&t===s||t.join&&t.indexOf(s)>-1}}var o={},i=t.group;i&&"object"==n(i)||(i={name:i}),o.name=i.name,o.checkPull=e(i.pull,!0),o.checkPut=e(i.put),o.revertClone=i.revertClone,t.group=o},Pt=function(){!Mt&&q&&D(q,"display","none")},It=function(){!Mt&&q&&D(q,"display","")};Tt&&!h&&document.addEventListener("click",function(t){if(bt)return t.preventDefault(),t.stopPropagation&&t.stopPropagation(),t.stopImmediatePropagation&&t.stopImmediatePropagation(),bt=!1,!1},!0);var kt=function(t){if(U){t=t.touches?t.touches[0]:t;var e=(i=t.clientX,r=t.clientY,yt.some(function(t){var e=t[B].options.emptyInsertThreshold;if(e&&!M(t)){var n=C(t),o=i>=n.left-e&&i<=n.right+e,l=r>=n.top-e&&r<=n.bottom+e;return o&&l?a=t:void 0}}),a);if(e){var n={};for(var o in t)t.hasOwnProperty(o)&&(n[o]=t[o]);n.target=n.rootEl=e,n.preventDefault=void 0,n.stopPropagation=void 0,e[B]._onDragOver(n)}}var i,r,a},Xt=function(t){U&&U.parentNode[B]._isOutsideThisEl(t.target)};function Yt(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(t));this.el=t,this.options=e=i({},e),t[B]=this;var n={group:null,sort:!0,disabled:!1,store:null,handle:null,draggable:/^[uo]l$/i.test(t.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return Nt(t,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(t,e){t.setData("Text",e.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:(Number.parseInt?Number:window).parseInt(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==Yt.supportPointer&&"PointerEvent"in window&&(!u||d),emptyInsertThreshold:5};for(var o in L.initializePlugins(this,t,n),n)!(o in e)&&(e[o]=n[o]);for(var r in At(e),this)"_"===r.charAt(0)&&"function"==typeof this[r]&&(this[r]=this[r].bind(this));this.nativeDraggable=!e.forceFallback&&Ot,this.nativeDraggable&&(this.options.touchStartThreshold=1),e.supportPointer?p(t,"pointerdown",this._onTapStart):(p(t,"mousedown",this._onTapStart),p(t,"touchstart",this._onTapStart)),this.nativeDraggable&&(p(t,"dragover",this),p(t,"dragenter",this)),yt.push(this.el),e.store&&e.store.get&&this.sort(e.store.get(this)||[]),i(this,F())}function Rt(t,e,n,o,i,r,a,c){var u,d,h=t[B],f=h.options.onMove;return!window.CustomEvent||l||s?(u=document.createEvent("Event")).initEvent("move",!0,!0):u=new CustomEvent("move",{bubbles:!0,cancelable:!0}),u.to=e,u.from=t,u.dragged=n,u.draggedRect=o,u.related=i||e,u.relatedRect=r||C(e),u.willInsertAfter=c,u.originalEvent=a,t.dispatchEvent(u),f&&(d=f.call(h,u,a)),d}function Bt(t){t.draggable=!1}function Ft(){_t=!1}function jt(t){for(var e=t.tagName+t.className+t.src+t.href+t.textContent,n=e.length,o=0;n--;)o+=e.charCodeAt(n);return o.toString(36)}function Ht(t){return setTimeout(t,0)}function Lt(t){return clearTimeout(t)}Yt.prototype={constructor:Yt,_isOutsideThisEl:function(t){this.el.contains(t)||t===this.el||(ft=null)},_getDirection:function(t,e){return"function"==typeof this.options.direction?this.options.direction.call(this,t,e,U):this.options.direction},_onTapStart:function(t){if(t.cancelable){var e=this,n=this.el,o=this.options,i=o.preventOnFilter,r=t.type,a=t.touches&&t.touches[0]||t.pointerType&&"touch"===t.pointerType&&t,l=(a||t).target,s=t.target.shadowRoot&&(t.path&&t.path[0]||t.composedPath&&t.composedPath()[0])||l,c=o.filter;if(function(t){St.length=0;var e=t.getElementsByTagName("input"),n=e.length;for(;n--;){var o=e[n];o.checked&&St.push(o)}}(n),!U&&!(/mousedown|pointerdown/.test(r)&&0!==t.button||o.disabled)&&!s.isContentEditable&&(this.nativeDraggable||!u||!l||"SELECT"!==l.tagName.toUpperCase())&&!((l=b(l,o.draggable,n,!1))&&l.animated||Q===l)){if(tt=N(l),nt=N(l,o.draggable),"function"==typeof c){if(c.call(this,t,l,this))return G({sortable:e,rootEl:s,name:"filter",targetEl:l,toEl:n,fromEl:n}),z("filter",e,{evt:t}),void(i&&t.preventDefault())}else if(c&&(c=c.split(",").some(function(o){if(o=b(s,o.trim(),n,!1))return G({sortable:e,rootEl:o,name:"filter",targetEl:l,fromEl:n,toEl:n}),z("filter",e,{evt:t}),!0})))return void(i&&t.preventDefault());o.handle&&!b(s,o.handle,n,!1)||this._prepareDragStart(t,a,l)}}},_prepareDragStart:function(t,e,n){var o,i=this,r=i.el,a=i.options,u=r.ownerDocument;if(n&&!U&&n.parentNode===r){var d=C(n);if(Z=r,V=(U=n).parentNode,K=U.nextSibling,Q=n,it=a.group,Yt.dragged=U,at={target:U,clientX:(e||t).clientX,clientY:(e||t).clientY},ut=at.clientX-d.left,dt=at.clientY-d.top,this._lastX=(e||t).clientX,this._lastY=(e||t).clientY,U.style["will-change"]="all",o=function(){z("delayEnded",i,{evt:t}),Yt.eventCanceled?i._onDrop():(i._disableDelayedDragEvents(),!c&&i.nativeDraggable&&(U.draggable=!0),i._triggerDragStart(t,e),G({sortable:i,name:"choose",originalEvent:t}),E(U,a.chosenClass,!0))},a.ignore.split(",").forEach(function(t){S(U,t.trim(),Bt)}),p(u,"dragover",kt),p(u,"mousemove",kt),p(u,"touchmove",kt),a.supportPointer?(p(u,"pointerup",i._onDrop),!this.nativeDraggable&&p(u,"pointercancel",i._onDrop)):(p(u,"mouseup",i._onDrop),p(u,"touchend",i._onDrop),p(u,"touchcancel",i._onDrop)),c&&this.nativeDraggable&&(this.options.touchStartThreshold=4,U.draggable=!0),z("delayStart",this,{evt:t}),!a.delay||a.delayOnTouchOnly&&!e||this.nativeDraggable&&(s||l))o();else{if(Yt.eventCanceled)return void this._onDrop();a.supportPointer?(p(u,"pointerup",i._disableDelayedDrag),p(u,"pointercancel",i._disableDelayedDrag)):(p(u,"mouseup",i._disableDelayedDrag),p(u,"touchend",i._disableDelayedDrag),p(u,"touchcancel",i._disableDelayedDrag)),p(u,"mousemove",i._delayedDragTouchMoveHandler),p(u,"touchmove",i._delayedDragTouchMoveHandler),a.supportPointer&&p(u,"pointermove",i._delayedDragTouchMoveHandler),i._dragStartTimer=setTimeout(o,a.delay)}}},_delayedDragTouchMoveHandler:function(t){var e=t.touches?t.touches[0]:t;Math.max(Math.abs(e.clientX-this._lastX),Math.abs(e.clientY-this._lastY))>=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){U&&Bt(U),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var t=this.el.ownerDocument;g(t,"mouseup",this._disableDelayedDrag),g(t,"touchend",this._disableDelayedDrag),g(t,"touchcancel",this._disableDelayedDrag),g(t,"pointerup",this._disableDelayedDrag),g(t,"pointercancel",this._disableDelayedDrag),g(t,"mousemove",this._delayedDragTouchMoveHandler),g(t,"touchmove",this._delayedDragTouchMoveHandler),g(t,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(t,e){e=e||"touch"==t.pointerType&&t,!this.nativeDraggable||e?this.options.supportPointer?p(document,"pointermove",this._onTouchMove):p(document,e?"touchmove":"mousemove",this._onTouchMove):(p(U,"dragend",this),p(Z,"dragstart",this._onDragStart));try{document.selection?Ht(function(){document.selection.empty()}):window.getSelection().removeAllRanges()}catch(n){}},_dragStarted:function(t,e){if(mt=!1,Z&&U){z("dragStarted",this,{evt:e}),this.nativeDraggable&&p(document,"dragover",Xt);var n=this.options;!t&&E(U,n.dragClass,!1),E(U,n.ghostClass,!0),Yt.active=this,t&&this._appendGhost(),G({sortable:this,name:"start",originalEvent:e})}else this._nulling()},_emulateDragOver:function(){if(lt){this._lastX=lt.clientX,this._lastY=lt.clientY,Pt();for(var t=document.elementFromPoint(lt.clientX,lt.clientY),e=t;t&&t.shadowRoot&&(t=t.shadowRoot.elementFromPoint(lt.clientX,lt.clientY))!==e;)e=t;if(U.parentNode[B]._isOutsideThisEl(t),e)do{if(e[B]){if(e[B]._onDragOver({clientX:lt.clientX,clientY:lt.clientY,target:t,rootEl:e})&&!this.options.dragoverBubble)break}t=e}while(e=m(e));It()}},_onTouchMove:function(t){if(at){var e=this.options,n=e.fallbackTolerance,o=e.fallbackOffset,i=t.touches?t.touches[0]:t,r=q&&_(q,!0),a=q&&r&&r.a,l=q&&r&&r.d,s=Ct&&vt&&A(vt),c=(i.clientX-at.clientX+o.x)/(a||1)+(s?s[0]-Dt[0]:0)/(a||1),u=(i.clientY-at.clientY+o.y)/(l||1)+(s?s[1]-Dt[1]:0)/(l||1);if(!Yt.active&&!mt){if(n&&Math.max(Math.abs(i.clientX-this._lastX),Math.abs(i.clientY-this._lastY))i.right+r||t.clientY>o.bottom&&t.clientX>o.left:t.clientY>i.bottom+r||t.clientX>o.right&&t.clientY>o.top}(t,r,this)&&!v.animated){if(v===U)return W(!1);if(v&&a===t.target&&(l=v),l&&(o=C(l)),!1!==Rt(Z,a,U,n,l,o,t,!!l))return L(),v&&v.nextSibling?a.insertBefore(U,v.nextSibling):a.appendChild(U),V=a,Q(),W(!0)}else if(v&&function(t,e,n){var o=C(O(n.el,0,n.options,!0)),i=R(n.el,n.options,q),r=10;return e?t.clientXu+c*r/2:sd-gt)return-pt}else if(s>u+c*(1-i)/2&&sd-c*r/2))return s>u+c/2?1:-1;return 0}(t,l,o,r,T?1:s.swapThreshold,null==s.invertedSwapThreshold?s.swapThreshold:s.invertedSwapThreshold,Et,ft===l),0!==y){var k=N(U);do{k-=y,_=V.children[k]}while(_&&("none"===D(_,"display")||_===q))}if(0===y||_===l)return W(!1);ft=l,pt=y;var Y=l.nextElementSibling,F=!1,j=Rt(Z,a,U,n,l,o,t,F=1===y);if(!1!==j)return 1!==j&&-1!==j||(F=1===j),_t=!0,setTimeout(Ft,30),L(),F&&!Y?a.appendChild(U):l.parentNode.insertBefore(U,F?Y:l),P&&X(P,0,I-P.scrollTop),V=U.parentNode,void 0===w||Et||(gt=Math.abs(w-C(l)[A])),Q(),W(!0)}if(a.contains(U))return W(!1)}return!1}function H(s,c){z(s,p,e({evt:t,isOwner:d,axis:r?"vertical":"horizontal",revert:i,dragRect:n,targetRect:o,canSort:h,fromSortable:f,target:l,completed:W,onMove:function(e,o){return Rt(Z,a,U,n,e,C(e),t,o)},changed:Q},c))}function L(){H("dragOverAnimationCapture"),p.captureAnimationState(),p!==f&&f.captureAnimationState()}function W(e){return H("dragOverCompleted",{insertion:e}),e&&(d?u._hideClone():u._showClone(p),p!==f&&(E(U,rt?rt.options.ghostClass:u.options.ghostClass,!1),E(U,s.ghostClass,!0)),rt!==p&&p!==Yt.active?rt=p:p===Yt.active&&rt&&(rt=null),f===p&&(p._ignoreWhileAnimating=l),p.animateAll(function(){H("dragOverAnimationComplete"),p._ignoreWhileAnimating=null}),p!==f&&(f.animateAll(),f._ignoreWhileAnimating=null)),(l===U&&!U.animated||l===a&&!l.animated)&&(ft=null),s.dragoverBubble||t.rootEl||l===document||(U.parentNode[B]._isOutsideThisEl(t.target),!e&&kt(t)),!s.dragoverBubble&&t.stopPropagation&&t.stopPropagation(),g=!0}function Q(){et=N(U),ot=N(U,s.draggable),G({sortable:p,name:"change",toEl:a,newIndex:et,newDraggableIndex:ot,originalEvent:t})}},_ignoreWhileAnimating:null,_offMoveEvents:function(){g(document,"mousemove",this._onTouchMove),g(document,"touchmove",this._onTouchMove),g(document,"pointermove",this._onTouchMove),g(document,"dragover",kt),g(document,"mousemove",kt),g(document,"touchmove",kt)},_offUpEvents:function(){var t=this.el.ownerDocument;g(t,"mouseup",this._onDrop),g(t,"touchend",this._onDrop),g(t,"pointerup",this._onDrop),g(t,"pointercancel",this._onDrop),g(t,"touchcancel",this._onDrop),g(document,"selectstart",this)},_onDrop:function(t){var e=this.el,n=this.options;et=N(U),ot=N(U,n.draggable),z("drop",this,{evt:t}),V=U&&U.parentNode,et=N(U),ot=N(U,n.draggable),Yt.eventCanceled||(mt=!1,Et=!1,wt=!1,clearInterval(this._loopId),clearTimeout(this._dragStartTimer),Lt(this.cloneId),Lt(this._dragStartId),this.nativeDraggable&&(g(document,"drop",this),g(e,"dragstart",this._onDragStart)),this._offMoveEvents(),this._offUpEvents(),u&&D(document.body,"user-select",""),D(U,"transform",""),t&&(ht&&(t.cancelable&&t.preventDefault(),!n.dropBubble&&t.stopPropagation()),q&&q.parentNode&&q.parentNode.removeChild(q),(Z===V||rt&&"clone"!==rt.lastPutMode)&&$&&$.parentNode&&$.parentNode.removeChild($),U&&(this.nativeDraggable&&g(U,"dragend",this),Bt(U),U.style["will-change"]="",ht&&!mt&&E(U,rt?rt.options.ghostClass:this.options.ghostClass,!1),E(U,this.options.chosenClass,!1),G({sortable:this,name:"unchoose",toEl:V,newIndex:null,newDraggableIndex:null,originalEvent:t}),Z!==V?(et>=0&&(G({rootEl:V,name:"add",toEl:V,fromEl:Z,originalEvent:t}),G({sortable:this,name:"remove",toEl:V,originalEvent:t}),G({rootEl:V,name:"sort",toEl:V,fromEl:Z,originalEvent:t}),G({sortable:this,name:"sort",toEl:V,originalEvent:t})),rt&&rt.save()):et!==tt&&et>=0&&(G({sortable:this,name:"update",toEl:V,originalEvent:t}),G({sortable:this,name:"sort",toEl:V,originalEvent:t})),Yt.active&&(null!=et&&-1!==et||(et=tt,ot=nt),G({sortable:this,name:"end",toEl:V,originalEvent:t}),this.save())))),this._nulling()},_nulling:function(){z("nulling",this),Z=U=V=q=K=$=Q=J=at=lt=ht=et=ot=tt=nt=ft=pt=rt=it=Yt.dragged=Yt.ghost=Yt.clone=Yt.active=null,St.forEach(function(t){t.checked=!0}),St.length=st=ct=0},handleEvent:function(t){switch(t.type){case"drop":case"dragend":this._onDrop(t);break;case"dragenter":case"dragover":U&&(this._onDragOver(t),function(t){t.dataTransfer&&(t.dataTransfer.dropEffect="move");t.cancelable&&t.preventDefault()}(t));break;case"selectstart":t.preventDefault()}},toArray:function(){for(var t,e=[],n=this.el.children,o=0,i=n.length,r=this.options;o= 0 && Math.floor(n) === n && isFinite(val); +} +function isPromise(val) { + return (isDef(val) && + typeof val.then === 'function' && + typeof val.catch === 'function'); +} +/** + * Convert a value to a string that is actually rendered. + */ +function toString(val) { + return val == null + ? '' + : Array.isArray(val) || (isPlainObject(val) && val.toString === _toString) + ? JSON.stringify(val, replacer, 2) + : String(val); +} +function replacer(_key, val) { + // avoid circular deps from v3 + if (val && val.__v_isRef) { + return val.value; + } + return val; +} +/** + * Convert an input value to a number for persistence. + * If the conversion fails, return original string. + */ +function toNumber(val) { + const n = parseFloat(val); + return isNaN(n) ? val : n; +} +/** + * Make a map and return a function for checking if a key + * is in that map. + */ +function makeMap(str, expectsLowerCase) { + const map = Object.create(null); + const list = str.split(','); + for (let i = 0; i < list.length; i++) { + map[list[i]] = true; + } + return expectsLowerCase ? val => map[val.toLowerCase()] : val => map[val]; +} +/** + * Check if a tag is a built-in tag. + */ +const isBuiltInTag = makeMap('slot,component', true); +/** + * Check if an attribute is a reserved attribute. + */ +const isReservedAttribute = makeMap('key,ref,slot,slot-scope,is'); +/** + * Remove an item from an array. + */ +function remove$2(arr, item) { + const len = arr.length; + if (len) { + // fast path for the only / last item + if (item === arr[len - 1]) { + arr.length = len - 1; + return; + } + const index = arr.indexOf(item); + if (index > -1) { + return arr.splice(index, 1); + } + } +} +/** + * Check whether an object has the property. + */ +const hasOwnProperty = Object.prototype.hasOwnProperty; +function hasOwn(obj, key) { + return hasOwnProperty.call(obj, key); +} +/** + * Create a cached version of a pure function. + */ +function cached(fn) { + const cache = Object.create(null); + return function cachedFn(str) { + const hit = cache[str]; + return hit || (cache[str] = fn(str)); + }; +} +/** + * Camelize a hyphen-delimited string. + */ +const camelizeRE = /-(\w)/g; +const camelize = cached((str) => { + return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : '')); +}); +/** + * Capitalize a string. + */ +const capitalize = cached((str) => { + return str.charAt(0).toUpperCase() + str.slice(1); +}); +/** + * Hyphenate a camelCase string. + */ +const hyphenateRE = /\B([A-Z])/g; +const hyphenate = cached((str) => { + return str.replace(hyphenateRE, '-$1').toLowerCase(); +}); +/** + * Simple bind polyfill for environments that do not support it, + * e.g., PhantomJS 1.x. Technically, we don't need this anymore + * since native bind is now performant enough in most browsers. + * But removing it would mean breaking code that was able to run in + * PhantomJS 1.x, so this must be kept for backward compatibility. + */ +/* istanbul ignore next */ +function polyfillBind(fn, ctx) { + function boundFn(a) { + const l = arguments.length; + return l + ? l > 1 + ? fn.apply(ctx, arguments) + : fn.call(ctx, a) + : fn.call(ctx); + } + boundFn._length = fn.length; + return boundFn; +} +function nativeBind(fn, ctx) { + return fn.bind(ctx); +} +// @ts-expect-error bind cannot be `undefined` +const bind$1 = Function.prototype.bind ? nativeBind : polyfillBind; +/** + * Convert an Array-like object to a real Array. + */ +function toArray(list, start) { + start = start || 0; + let i = list.length - start; + const ret = new Array(i); + while (i--) { + ret[i] = list[i + start]; + } + return ret; +} +/** + * Mix properties into target object. + */ +function extend(to, _from) { + for (const key in _from) { + to[key] = _from[key]; + } + return to; +} +/** + * Merge an Array of Objects into a single Object. + */ +function toObject(arr) { + const res = {}; + for (let i = 0; i < arr.length; i++) { + if (arr[i]) { + extend(res, arr[i]); + } + } + return res; +} +/* eslint-disable no-unused-vars */ +/** + * Perform no operation. + * Stubbing args to make Flow happy without leaving useless transpiled code + * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/). + */ +function noop(a, b, c) { } +/** + * Always return false. + */ +const no = (a, b, c) => false; +/* eslint-enable no-unused-vars */ +/** + * Return the same value. + */ +const identity = (_) => _; +/** + * Generate a string containing static keys from compiler modules. + */ +function genStaticKeys$1(modules) { + return modules + .reduce((keys, m) => keys.concat(m.staticKeys || []), []) + .join(','); +} +/** + * Check if two values are loosely equal - that is, + * if they are plain objects, do they have the same shape? + */ +function looseEqual(a, b) { + if (a === b) + return true; + const isObjectA = isObject(a); + const isObjectB = isObject(b); + if (isObjectA && isObjectB) { + try { + const isArrayA = Array.isArray(a); + const isArrayB = Array.isArray(b); + if (isArrayA && isArrayB) { + return (a.length === b.length && + a.every((e, i) => { + return looseEqual(e, b[i]); + })); + } + else if (a instanceof Date && b instanceof Date) { + return a.getTime() === b.getTime(); + } + else if (!isArrayA && !isArrayB) { + const keysA = Object.keys(a); + const keysB = Object.keys(b); + return (keysA.length === keysB.length && + keysA.every(key => { + return looseEqual(a[key], b[key]); + })); + } + else { + /* istanbul ignore next */ + return false; + } + } + catch (e) { + /* istanbul ignore next */ + return false; + } + } + else if (!isObjectA && !isObjectB) { + return String(a) === String(b); + } + else { + return false; + } +} +/** + * Return the first index at which a loosely equal value can be + * found in the array (if value is a plain object, the array must + * contain an object of the same shape), or -1 if it is not present. + */ +function looseIndexOf(arr, val) { + for (let i = 0; i < arr.length; i++) { + if (looseEqual(arr[i], val)) + return i; + } + return -1; +} +/** + * Ensure a function is called only once. + */ +function once(fn) { + let called = false; + return function () { + if (!called) { + called = true; + fn.apply(this, arguments); + } + }; +} +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#polyfill +function hasChanged(x, y) { + if (x === y) { + return x === 0 && 1 / x !== 1 / y; + } + else { + return x === x || y === y; + } +} + +const SSR_ATTR = 'data-server-rendered'; +const ASSET_TYPES = ['component', 'directive', 'filter']; +const LIFECYCLE_HOOKS = [ + 'beforeCreate', + 'created', + 'beforeMount', + 'mounted', + 'beforeUpdate', + 'updated', + 'beforeDestroy', + 'destroyed', + 'activated', + 'deactivated', + 'errorCaptured', + 'serverPrefetch', + 'renderTracked', + 'renderTriggered' +]; + +var config = { + /** + * Option merge strategies (used in core/util/options) + */ + // $flow-disable-line + optionMergeStrategies: Object.create(null), + /** + * Whether to suppress warnings. + */ + silent: false, + /** + * Show production mode tip message on boot? + */ + productionTip: true, + /** + * Whether to enable devtools + */ + devtools: true, + /** + * Whether to record perf + */ + performance: false, + /** + * Error handler for watcher errors + */ + errorHandler: null, + /** + * Warn handler for watcher warns + */ + warnHandler: null, + /** + * Ignore certain custom elements + */ + ignoredElements: [], + /** + * Custom user key aliases for v-on + */ + // $flow-disable-line + keyCodes: Object.create(null), + /** + * Check if a tag is reserved so that it cannot be registered as a + * component. This is platform-dependent and may be overwritten. + */ + isReservedTag: no, + /** + * Check if an attribute is reserved so that it cannot be used as a component + * prop. This is platform-dependent and may be overwritten. + */ + isReservedAttr: no, + /** + * Check if a tag is an unknown element. + * Platform-dependent. + */ + isUnknownElement: no, + /** + * Get the namespace of an element + */ + getTagNamespace: noop, + /** + * Parse the real tag name for the specific platform. + */ + parsePlatformTagName: identity, + /** + * Check if an attribute must be bound using property, e.g. value + * Platform-dependent. + */ + mustUseProp: no, + /** + * Perform updates asynchronously. Intended to be used by Vue Test Utils + * This will significantly reduce performance if set to false. + */ + async: true, + /** + * Exposed for legacy reasons + */ + _lifecycleHooks: LIFECYCLE_HOOKS +}; + +/** + * unicode letters used for parsing html tags, component names and property paths. + * using https://www.w3.org/TR/html53/semantics-scripting.html#potentialcustomelementname + * skipping \u10000-\uEFFFF due to it freezing up PhantomJS + */ +const unicodeRegExp = /a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/; +/** + * Check if a string starts with $ or _ + */ +function isReserved(str) { + const c = (str + '').charCodeAt(0); + return c === 0x24 || c === 0x5f; +} +/** + * Define a property. + */ +function def(obj, key, val, enumerable) { + Object.defineProperty(obj, key, { + value: val, + enumerable: !!enumerable, + writable: true, + configurable: true + }); +} +/** + * Parse simple path. + */ +const bailRE = new RegExp(`[^${unicodeRegExp.source}.$_\\d]`); +function parsePath(path) { + if (bailRE.test(path)) { + return; + } + const segments = path.split('.'); + return function (obj) { + for (let i = 0; i < segments.length; i++) { + if (!obj) + return; + obj = obj[segments[i]]; + } + return obj; + }; +} + +// can we use __proto__? +const hasProto = '__proto__' in {}; +// Browser environment sniffing +const inBrowser = typeof window !== 'undefined'; +const UA = inBrowser && window.navigator.userAgent.toLowerCase(); +const isIE = UA && /msie|trident/.test(UA); +const isIE9 = UA && UA.indexOf('msie 9.0') > 0; +const isEdge = UA && UA.indexOf('edge/') > 0; +UA && UA.indexOf('android') > 0; +const isIOS = UA && /iphone|ipad|ipod|ios/.test(UA); +UA && /chrome\/\d+/.test(UA) && !isEdge; +UA && /phantomjs/.test(UA); +const isFF = UA && UA.match(/firefox\/(\d+)/); +// Firefox has a "watch" function on Object.prototype... +// @ts-expect-error firebox support +const nativeWatch = {}.watch; +let supportsPassive = false; +if (inBrowser) { + try { + const opts = {}; + Object.defineProperty(opts, 'passive', { + get() { + /* istanbul ignore next */ + supportsPassive = true; + } + }); // https://github.com/facebook/flow/issues/285 + window.addEventListener('test-passive', null, opts); + } + catch (e) { } +} +// this needs to be lazy-evaled because vue may be required before +// vue-server-renderer can set VUE_ENV +let _isServer; +const isServerRendering = () => { + if (_isServer === undefined) { + /* istanbul ignore if */ + if (!inBrowser && typeof global !== 'undefined') { + // detect presence of vue-server-renderer and avoid + // Webpack shimming the process + _isServer = + global['process'] && global['process'].env.VUE_ENV === 'server'; + } + else { + _isServer = false; + } + } + return _isServer; +}; +// detect devtools +const devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__; +/* istanbul ignore next */ +function isNative(Ctor) { + return typeof Ctor === 'function' && /native code/.test(Ctor.toString()); +} +const hasSymbol = typeof Symbol !== 'undefined' && + isNative(Symbol) && + typeof Reflect !== 'undefined' && + isNative(Reflect.ownKeys); +let _Set; // $flow-disable-line +/* istanbul ignore if */ if (typeof Set !== 'undefined' && isNative(Set)) { + // use native Set when available. + _Set = Set; +} +else { + // a non-standard Set polyfill that only works with primitive keys. + _Set = class Set { + constructor() { + this.set = Object.create(null); + } + has(key) { + return this.set[key] === true; + } + add(key) { + this.set[key] = true; + } + clear() { + this.set = Object.create(null); + } + }; +} + +let currentInstance = null; +/** + * This is exposed for compatibility with v3 (e.g. some functions in VueUse + * relies on it). Do not use this internally, just use `currentInstance`. + * + * @internal this function needs manual type declaration because it relies + * on previously manually authored types from Vue 2 + */ +function getCurrentInstance() { + return currentInstance && { proxy: currentInstance }; +} +/** + * @internal + */ +function setCurrentInstance(vm = null) { + if (!vm) + currentInstance && currentInstance._scope.off(); + currentInstance = vm; + vm && vm._scope.on(); +} + +/** + * @internal + */ +class VNode { + constructor(tag, data, children, text, elm, context, componentOptions, asyncFactory) { + this.tag = tag; + this.data = data; + this.children = children; + this.text = text; + this.elm = elm; + this.ns = undefined; + this.context = context; + this.fnContext = undefined; + this.fnOptions = undefined; + this.fnScopeId = undefined; + this.key = data && data.key; + this.componentOptions = componentOptions; + this.componentInstance = undefined; + this.parent = undefined; + this.raw = false; + this.isStatic = false; + this.isRootInsert = true; + this.isComment = false; + this.isCloned = false; + this.isOnce = false; + this.asyncFactory = asyncFactory; + this.asyncMeta = undefined; + this.isAsyncPlaceholder = false; + } + // DEPRECATED: alias for componentInstance for backwards compat. + /* istanbul ignore next */ + get child() { + return this.componentInstance; + } +} +const createEmptyVNode = (text = '') => { + const node = new VNode(); + node.text = text; + node.isComment = true; + return node; +}; +function createTextVNode(val) { + return new VNode(undefined, undefined, undefined, String(val)); +} +// optimized shallow clone +// used for static nodes and slot nodes because they may be reused across +// multiple renders, cloning them avoids errors when DOM manipulations rely +// on their elm reference. +function cloneVNode(vnode) { + const cloned = new VNode(vnode.tag, vnode.data, + // #7975 + // clone children array to avoid mutating original in case of cloning + // a child. + vnode.children && vnode.children.slice(), vnode.text, vnode.elm, vnode.context, vnode.componentOptions, vnode.asyncFactory); + cloned.ns = vnode.ns; + cloned.isStatic = vnode.isStatic; + cloned.key = vnode.key; + cloned.isComment = vnode.isComment; + cloned.fnContext = vnode.fnContext; + cloned.fnOptions = vnode.fnOptions; + cloned.fnScopeId = vnode.fnScopeId; + cloned.asyncMeta = vnode.asyncMeta; + cloned.isCloned = true; + return cloned; +} + +/* not type checking this file because flow doesn't play well with Proxy */ +let initProxy; +{ + const allowedGlobals = makeMap('Infinity,undefined,NaN,isFinite,isNaN,' + + 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' + + 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,' + + 'require' // for Webpack/Browserify + ); + const warnNonPresent = (target, key) => { + warn$2(`Property or method "${key}" is not defined on the instance but ` + + 'referenced during render. Make sure that this property is reactive, ' + + 'either in the data option, or for class-based components, by ' + + 'initializing the property. ' + + 'See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.', target); + }; + const warnReservedPrefix = (target, key) => { + warn$2(`Property "${key}" must be accessed with "$data.${key}" because ` + + 'properties starting with "$" or "_" are not proxied in the Vue instance to ' + + 'prevent conflicts with Vue internals. ' + + 'See: https://v2.vuejs.org/v2/api/#data', target); + }; + const hasProxy = typeof Proxy !== 'undefined' && isNative(Proxy); + if (hasProxy) { + const isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,exact'); + config.keyCodes = new Proxy(config.keyCodes, { + set(target, key, value) { + if (isBuiltInModifier(key)) { + warn$2(`Avoid overwriting built-in modifier in config.keyCodes: .${key}`); + return false; + } + else { + target[key] = value; + return true; + } + } + }); + } + const hasHandler = { + has(target, key) { + const has = key in target; + const isAllowed = allowedGlobals(key) || + (typeof key === 'string' && + key.charAt(0) === '_' && + !(key in target.$data)); + if (!has && !isAllowed) { + if (key in target.$data) + warnReservedPrefix(target, key); + else + warnNonPresent(target, key); + } + return has || !isAllowed; + } + }; + const getHandler = { + get(target, key) { + if (typeof key === 'string' && !(key in target)) { + if (key in target.$data) + warnReservedPrefix(target, key); + else + warnNonPresent(target, key); + } + return target[key]; + } + }; + initProxy = function initProxy(vm) { + if (hasProxy) { + // determine which proxy handler to use + const options = vm.$options; + const handlers = options.render && options.render._withStripped ? getHandler : hasHandler; + vm._renderProxy = new Proxy(vm, handlers); + } + else { + vm._renderProxy = vm; + } + }; +} + +let uid$2 = 0; +const pendingCleanupDeps = []; +const cleanupDeps = () => { + for (let i = 0; i < pendingCleanupDeps.length; i++) { + const dep = pendingCleanupDeps[i]; + dep.subs = dep.subs.filter(s => s); + dep._pending = false; + } + pendingCleanupDeps.length = 0; +}; +/** + * A dep is an observable that can have multiple + * directives subscribing to it. + * @internal + */ +class Dep { + constructor() { + // pending subs cleanup + this._pending = false; + this.id = uid$2++; + this.subs = []; + } + addSub(sub) { + this.subs.push(sub); + } + removeSub(sub) { + // #12696 deps with massive amount of subscribers are extremely slow to + // clean up in Chromium + // to workaround this, we unset the sub for now, and clear them on + // next scheduler flush. + this.subs[this.subs.indexOf(sub)] = null; + if (!this._pending) { + this._pending = true; + pendingCleanupDeps.push(this); + } + } + depend(info) { + if (Dep.target) { + Dep.target.addDep(this); + if (info && Dep.target.onTrack) { + Dep.target.onTrack(Object.assign({ effect: Dep.target }, info)); + } + } + } + notify(info) { + // stabilize the subscriber list first + const subs = this.subs.filter(s => s); + if (!config.async) { + // subs aren't sorted in scheduler if not running async + // we need to sort them now to make sure they fire in correct + // order + subs.sort((a, b) => a.id - b.id); + } + for (let i = 0, l = subs.length; i < l; i++) { + const sub = subs[i]; + if (info) { + sub.onTrigger && + sub.onTrigger(Object.assign({ effect: subs[i] }, info)); + } + sub.update(); + } + } +} +// The current target watcher being evaluated. +// This is globally unique because only one watcher +// can be evaluated at a time. +Dep.target = null; +const targetStack = []; +function pushTarget(target) { + targetStack.push(target); + Dep.target = target; +} +function popTarget() { + targetStack.pop(); + Dep.target = targetStack[targetStack.length - 1]; +} + +/* + * not type checking this file because flow doesn't play well with + * dynamically accessing methods on Array prototype + */ +const arrayProto = Array.prototype; +const arrayMethods = Object.create(arrayProto); +const methodsToPatch = [ + 'push', + 'pop', + 'shift', + 'unshift', + 'splice', + 'sort', + 'reverse' +]; +/** + * Intercept mutating methods and emit events + */ +methodsToPatch.forEach(function (method) { + // cache original method + const original = arrayProto[method]; + def(arrayMethods, method, function mutator(...args) { + const result = original.apply(this, args); + const ob = this.__ob__; + let inserted; + switch (method) { + case 'push': + case 'unshift': + inserted = args; + break; + case 'splice': + inserted = args.slice(2); + break; + } + if (inserted) + ob.observeArray(inserted); + // notify change + { + ob.dep.notify({ + type: "array mutation" /* TriggerOpTypes.ARRAY_MUTATION */, + target: this, + key: method + }); + } + return result; + }); +}); + +const arrayKeys = Object.getOwnPropertyNames(arrayMethods); +const NO_INITIAL_VALUE = {}; +/** + * In some cases we may want to disable observation inside a component's + * update computation. + */ +let shouldObserve = true; +function toggleObserving(value) { + shouldObserve = value; +} +// ssr mock dep +const mockDep = { + notify: noop, + depend: noop, + addSub: noop, + removeSub: noop +}; +/** + * Observer class that is attached to each observed + * object. Once attached, the observer converts the target + * object's property keys into getter/setters that + * collect dependencies and dispatch updates. + */ +class Observer { + constructor(value, shallow = false, mock = false) { + this.value = value; + this.shallow = shallow; + this.mock = mock; + // this.value = value + this.dep = mock ? mockDep : new Dep(); + this.vmCount = 0; + def(value, '__ob__', this); + if (isArray(value)) { + if (!mock) { + if (hasProto) { + value.__proto__ = arrayMethods; + /* eslint-enable no-proto */ + } + else { + for (let i = 0, l = arrayKeys.length; i < l; i++) { + const key = arrayKeys[i]; + def(value, key, arrayMethods[key]); + } + } + } + if (!shallow) { + this.observeArray(value); + } + } + else { + /** + * Walk through all properties and convert them into + * getter/setters. This method should only be called when + * value type is Object. + */ + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + defineReactive(value, key, NO_INITIAL_VALUE, undefined, shallow, mock); + } + } + } + /** + * Observe a list of Array items. + */ + observeArray(value) { + for (let i = 0, l = value.length; i < l; i++) { + observe(value[i], false, this.mock); + } + } +} +// helpers +/** + * Attempt to create an observer instance for a value, + * returns the new observer if successfully observed, + * or the existing observer if the value already has one. + */ +function observe(value, shallow, ssrMockReactivity) { + if (value && hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { + return value.__ob__; + } + if (shouldObserve && + (ssrMockReactivity || !isServerRendering()) && + (isArray(value) || isPlainObject(value)) && + Object.isExtensible(value) && + !value.__v_skip /* ReactiveFlags.SKIP */ && + !isRef(value) && + !(value instanceof VNode)) { + return new Observer(value, shallow, ssrMockReactivity); + } +} +/** + * Define a reactive property on an Object. + */ +function defineReactive(obj, key, val, customSetter, shallow, mock, observeEvenIfShallow = false) { + const dep = new Dep(); + const property = Object.getOwnPropertyDescriptor(obj, key); + if (property && property.configurable === false) { + return; + } + // cater for pre-defined getter/setters + const getter = property && property.get; + const setter = property && property.set; + if ((!getter || setter) && + (val === NO_INITIAL_VALUE || arguments.length === 2)) { + val = obj[key]; + } + let childOb = shallow ? val && val.__ob__ : observe(val, false, mock); + Object.defineProperty(obj, key, { + enumerable: true, + configurable: true, + get: function reactiveGetter() { + const value = getter ? getter.call(obj) : val; + if (Dep.target) { + { + dep.depend({ + target: obj, + type: "get" /* TrackOpTypes.GET */, + key + }); + } + if (childOb) { + childOb.dep.depend(); + if (isArray(value)) { + dependArray(value); + } + } + } + return isRef(value) && !shallow ? value.value : value; + }, + set: function reactiveSetter(newVal) { + const value = getter ? getter.call(obj) : val; + if (!hasChanged(value, newVal)) { + return; + } + if (customSetter) { + customSetter(); + } + if (setter) { + setter.call(obj, newVal); + } + else if (getter) { + // #7981: for accessor properties without setter + return; + } + else if (!shallow && isRef(value) && !isRef(newVal)) { + value.value = newVal; + return; + } + else { + val = newVal; + } + childOb = shallow ? newVal && newVal.__ob__ : observe(newVal, false, mock); + { + dep.notify({ + type: "set" /* TriggerOpTypes.SET */, + target: obj, + key, + newValue: newVal, + oldValue: value + }); + } + } + }); + return dep; +} +function set(target, key, val) { + if ((isUndef(target) || isPrimitive(target))) { + warn$2(`Cannot set reactive property on undefined, null, or primitive value: ${target}`); + } + if (isReadonly(target)) { + warn$2(`Set operation on key "${key}" failed: target is readonly.`); + return; + } + const ob = target.__ob__; + if (isArray(target) && isValidArrayIndex(key)) { + target.length = Math.max(target.length, key); + target.splice(key, 1, val); + // when mocking for SSR, array methods are not hijacked + if (ob && !ob.shallow && ob.mock) { + observe(val, false, true); + } + return val; + } + if (key in target && !(key in Object.prototype)) { + target[key] = val; + return val; + } + if (target._isVue || (ob && ob.vmCount)) { + warn$2('Avoid adding reactive properties to a Vue instance or its root $data ' + + 'at runtime - declare it upfront in the data option.'); + return val; + } + if (!ob) { + target[key] = val; + return val; + } + defineReactive(ob.value, key, val, undefined, ob.shallow, ob.mock); + { + ob.dep.notify({ + type: "add" /* TriggerOpTypes.ADD */, + target: target, + key, + newValue: val, + oldValue: undefined + }); + } + return val; +} +function del(target, key) { + if ((isUndef(target) || isPrimitive(target))) { + warn$2(`Cannot delete reactive property on undefined, null, or primitive value: ${target}`); + } + if (isArray(target) && isValidArrayIndex(key)) { + target.splice(key, 1); + return; + } + const ob = target.__ob__; + if (target._isVue || (ob && ob.vmCount)) { + warn$2('Avoid deleting properties on a Vue instance or its root $data ' + + '- just set it to null.'); + return; + } + if (isReadonly(target)) { + warn$2(`Delete operation on key "${key}" failed: target is readonly.`); + return; + } + if (!hasOwn(target, key)) { + return; + } + delete target[key]; + if (!ob) { + return; + } + { + ob.dep.notify({ + type: "delete" /* TriggerOpTypes.DELETE */, + target: target, + key + }); + } +} +/** + * Collect dependencies on array elements when the array is touched, since + * we cannot intercept array element access like property getters. + */ +function dependArray(value) { + for (let e, i = 0, l = value.length; i < l; i++) { + e = value[i]; + if (e && e.__ob__) { + e.__ob__.dep.depend(); + } + if (isArray(e)) { + dependArray(e); + } + } +} + +function reactive(target) { + makeReactive(target, false); + return target; +} +/** + * Return a shallowly-reactive copy of the original object, where only the root + * level properties are reactive. It also does not auto-unwrap refs (even at the + * root level). + */ +function shallowReactive(target) { + makeReactive(target, true); + def(target, "__v_isShallow" /* ReactiveFlags.IS_SHALLOW */, true); + return target; +} +function makeReactive(target, shallow) { + // if trying to observe a readonly proxy, return the readonly version. + if (!isReadonly(target)) { + { + if (isArray(target)) { + warn$2(`Avoid using Array as root value for ${shallow ? `shallowReactive()` : `reactive()`} as it cannot be tracked in watch() or watchEffect(). Use ${shallow ? `shallowRef()` : `ref()`} instead. This is a Vue-2-only limitation.`); + } + const existingOb = target && target.__ob__; + if (existingOb && existingOb.shallow !== shallow) { + warn$2(`Target is already a ${existingOb.shallow ? `` : `non-`}shallow reactive object, and cannot be converted to ${shallow ? `` : `non-`}shallow.`); + } + } + const ob = observe(target, shallow, isServerRendering() /* ssr mock reactivity */); + if (!ob) { + if (target == null || isPrimitive(target)) { + warn$2(`value cannot be made reactive: ${String(target)}`); + } + if (isCollectionType(target)) { + warn$2(`Vue 2 does not support reactive collection types such as Map or Set.`); + } + } + } +} +function isReactive(value) { + if (isReadonly(value)) { + return isReactive(value["__v_raw" /* ReactiveFlags.RAW */]); + } + return !!(value && value.__ob__); +} +function isShallow(value) { + return !!(value && value.__v_isShallow); +} +function isReadonly(value) { + return !!(value && value.__v_isReadonly); +} +function isProxy(value) { + return isReactive(value) || isReadonly(value); +} +function toRaw(observed) { + const raw = observed && observed["__v_raw" /* ReactiveFlags.RAW */]; + return raw ? toRaw(raw) : observed; +} +function markRaw(value) { + // non-extensible objects won't be observed anyway + if (Object.isExtensible(value)) { + def(value, "__v_skip" /* ReactiveFlags.SKIP */, true); + } + return value; +} +/** + * @internal + */ +function isCollectionType(value) { + const type = toRawType(value); + return (type === 'Map' || type === 'WeakMap' || type === 'Set' || type === 'WeakSet'); +} + +/** + * @internal + */ +const RefFlag = `__v_isRef`; +function isRef(r) { + return !!(r && r.__v_isRef === true); +} +function ref$1(value) { + return createRef(value, false); +} +function shallowRef(value) { + return createRef(value, true); +} +function createRef(rawValue, shallow) { + if (isRef(rawValue)) { + return rawValue; + } + const ref = {}; + def(ref, RefFlag, true); + def(ref, "__v_isShallow" /* ReactiveFlags.IS_SHALLOW */, shallow); + def(ref, 'dep', defineReactive(ref, 'value', rawValue, null, shallow, isServerRendering())); + return ref; +} +function triggerRef(ref) { + if (!ref.dep) { + warn$2(`received object is not a triggerable ref.`); + } + { + ref.dep && + ref.dep.notify({ + type: "set" /* TriggerOpTypes.SET */, + target: ref, + key: 'value' + }); + } +} +function unref(ref) { + return isRef(ref) ? ref.value : ref; +} +function proxyRefs(objectWithRefs) { + if (isReactive(objectWithRefs)) { + return objectWithRefs; + } + const proxy = {}; + const keys = Object.keys(objectWithRefs); + for (let i = 0; i < keys.length; i++) { + proxyWithRefUnwrap(proxy, objectWithRefs, keys[i]); + } + return proxy; +} +function proxyWithRefUnwrap(target, source, key) { + Object.defineProperty(target, key, { + enumerable: true, + configurable: true, + get: () => { + const val = source[key]; + if (isRef(val)) { + return val.value; + } + else { + const ob = val && val.__ob__; + if (ob) + ob.dep.depend(); + return val; + } + }, + set: value => { + const oldValue = source[key]; + if (isRef(oldValue) && !isRef(value)) { + oldValue.value = value; + } + else { + source[key] = value; + } + } + }); +} +function customRef(factory) { + const dep = new Dep(); + const { get, set } = factory(() => { + { + dep.depend({ + target: ref, + type: "get" /* TrackOpTypes.GET */, + key: 'value' + }); + } + }, () => { + { + dep.notify({ + target: ref, + type: "set" /* TriggerOpTypes.SET */, + key: 'value' + }); + } + }); + const ref = { + get value() { + return get(); + }, + set value(newVal) { + set(newVal); + } + }; + def(ref, RefFlag, true); + return ref; +} +function toRefs(object) { + if (!isReactive(object)) { + warn$2(`toRefs() expects a reactive object but received a plain one.`); + } + const ret = isArray(object) ? new Array(object.length) : {}; + for (const key in object) { + ret[key] = toRef(object, key); + } + return ret; +} +function toRef(object, key, defaultValue) { + const val = object[key]; + if (isRef(val)) { + return val; + } + const ref = { + get value() { + const val = object[key]; + return val === undefined ? defaultValue : val; + }, + set value(newVal) { + object[key] = newVal; + } + }; + def(ref, RefFlag, true); + return ref; +} + +const rawToReadonlyFlag = `__v_rawToReadonly`; +const rawToShallowReadonlyFlag = `__v_rawToShallowReadonly`; +function readonly(target) { + return createReadonly(target, false); +} +function createReadonly(target, shallow) { + if (!isPlainObject(target)) { + { + if (isArray(target)) { + warn$2(`Vue 2 does not support readonly arrays.`); + } + else if (isCollectionType(target)) { + warn$2(`Vue 2 does not support readonly collection types such as Map or Set.`); + } + else { + warn$2(`value cannot be made readonly: ${typeof target}`); + } + } + return target; + } + if (!Object.isExtensible(target)) { + warn$2(`Vue 2 does not support creating readonly proxy for non-extensible object.`); + } + // already a readonly object + if (isReadonly(target)) { + return target; + } + // already has a readonly proxy + const existingFlag = shallow ? rawToShallowReadonlyFlag : rawToReadonlyFlag; + const existingProxy = target[existingFlag]; + if (existingProxy) { + return existingProxy; + } + const proxy = Object.create(Object.getPrototypeOf(target)); + def(target, existingFlag, proxy); + def(proxy, "__v_isReadonly" /* ReactiveFlags.IS_READONLY */, true); + def(proxy, "__v_raw" /* ReactiveFlags.RAW */, target); + if (isRef(target)) { + def(proxy, RefFlag, true); + } + if (shallow || isShallow(target)) { + def(proxy, "__v_isShallow" /* ReactiveFlags.IS_SHALLOW */, true); + } + const keys = Object.keys(target); + for (let i = 0; i < keys.length; i++) { + defineReadonlyProperty(proxy, target, keys[i], shallow); + } + return proxy; +} +function defineReadonlyProperty(proxy, target, key, shallow) { + Object.defineProperty(proxy, key, { + enumerable: true, + configurable: true, + get() { + const val = target[key]; + return shallow || !isPlainObject(val) ? val : readonly(val); + }, + set() { + warn$2(`Set operation on key "${key}" failed: target is readonly.`); + } + }); +} +/** + * Returns a reactive-copy of the original object, where only the root level + * properties are readonly, and does NOT unwrap refs nor recursively convert + * returned properties. + * This is used for creating the props proxy object for stateful components. + */ +function shallowReadonly(target) { + return createReadonly(target, true); +} + +function computed(getterOrOptions, debugOptions) { + let getter; + let setter; + const onlyGetter = isFunction(getterOrOptions); + if (onlyGetter) { + getter = getterOrOptions; + setter = () => { + warn$2('Write operation failed: computed value is readonly'); + } + ; + } + else { + getter = getterOrOptions.get; + setter = getterOrOptions.set; + } + const watcher = isServerRendering() + ? null + : new Watcher(currentInstance, getter, noop, { lazy: true }); + if (watcher && debugOptions) { + watcher.onTrack = debugOptions.onTrack; + watcher.onTrigger = debugOptions.onTrigger; + } + const ref = { + // some libs rely on the presence effect for checking computed refs + // from normal refs, but the implementation doesn't matter + effect: watcher, + get value() { + if (watcher) { + if (watcher.dirty) { + watcher.evaluate(); + } + if (Dep.target) { + if (Dep.target.onTrack) { + Dep.target.onTrack({ + effect: Dep.target, + target: ref, + type: "get" /* TrackOpTypes.GET */, + key: 'value' + }); + } + watcher.depend(); + } + return watcher.value; + } + else { + return getter(); + } + }, + set value(newVal) { + setter(newVal); + } + }; + def(ref, RefFlag, true); + def(ref, "__v_isReadonly" /* ReactiveFlags.IS_READONLY */, onlyGetter); + return ref; +} + +let mark; +let measure; +{ + const perf = inBrowser && window.performance; + /* istanbul ignore if */ + if (perf && + // @ts-ignore + perf.mark && + // @ts-ignore + perf.measure && + // @ts-ignore + perf.clearMarks && + // @ts-ignore + perf.clearMeasures) { + mark = tag => perf.mark(tag); + measure = (name, startTag, endTag) => { + perf.measure(name, startTag, endTag); + perf.clearMarks(startTag); + perf.clearMarks(endTag); + // perf.clearMeasures(name) + }; + } +} + +const normalizeEvent = cached((name) => { + const passive = name.charAt(0) === '&'; + name = passive ? name.slice(1) : name; + const once = name.charAt(0) === '~'; // Prefixed last, checked first + name = once ? name.slice(1) : name; + const capture = name.charAt(0) === '!'; + name = capture ? name.slice(1) : name; + return { + name, + once, + capture, + passive + }; +}); +function createFnInvoker(fns, vm) { + function invoker() { + const fns = invoker.fns; + if (isArray(fns)) { + const cloned = fns.slice(); + for (let i = 0; i < cloned.length; i++) { + invokeWithErrorHandling(cloned[i], null, arguments, vm, `v-on handler`); + } + } + else { + // return handler return value for single handlers + return invokeWithErrorHandling(fns, null, arguments, vm, `v-on handler`); + } + } + invoker.fns = fns; + return invoker; +} +function updateListeners(on, oldOn, add, remove, createOnceHandler, vm) { + let name, cur, old, event; + for (name in on) { + cur = on[name]; + old = oldOn[name]; + event = normalizeEvent(name); + if (isUndef(cur)) { + warn$2(`Invalid handler for event "${event.name}": got ` + String(cur), vm); + } + else if (isUndef(old)) { + if (isUndef(cur.fns)) { + cur = on[name] = createFnInvoker(cur, vm); + } + if (isTrue(event.once)) { + cur = on[name] = createOnceHandler(event.name, cur, event.capture); + } + add(event.name, cur, event.capture, event.passive, event.params); + } + else if (cur !== old) { + old.fns = cur; + on[name] = old; + } + } + for (name in oldOn) { + if (isUndef(on[name])) { + event = normalizeEvent(name); + remove(event.name, oldOn[name], event.capture); + } + } +} + +function mergeVNodeHook(def, hookKey, hook) { + if (def instanceof VNode) { + def = def.data.hook || (def.data.hook = {}); + } + let invoker; + const oldHook = def[hookKey]; + function wrappedHook() { + hook.apply(this, arguments); + // important: remove merged hook to ensure it's called only once + // and prevent memory leak + remove$2(invoker.fns, wrappedHook); + } + if (isUndef(oldHook)) { + // no existing hook + invoker = createFnInvoker([wrappedHook]); + } + else { + /* istanbul ignore if */ + if (isDef(oldHook.fns) && isTrue(oldHook.merged)) { + // already a merged invoker + invoker = oldHook; + invoker.fns.push(wrappedHook); + } + else { + // existing plain hook + invoker = createFnInvoker([oldHook, wrappedHook]); + } + } + invoker.merged = true; + def[hookKey] = invoker; +} + +function extractPropsFromVNodeData(data, Ctor, tag) { + // we are only extracting raw values here. + // validation and default values are handled in the child + // component itself. + const propOptions = Ctor.options.props; + if (isUndef(propOptions)) { + return; + } + const res = {}; + const { attrs, props } = data; + if (isDef(attrs) || isDef(props)) { + for (const key in propOptions) { + const altKey = hyphenate(key); + { + const keyInLowerCase = key.toLowerCase(); + if (key !== keyInLowerCase && attrs && hasOwn(attrs, keyInLowerCase)) { + tip(`Prop "${keyInLowerCase}" is passed to component ` + + `${formatComponentName( + // @ts-expect-error tag is string + tag || Ctor)}, but the declared prop name is` + + ` "${key}". ` + + `Note that HTML attributes are case-insensitive and camelCased ` + + `props need to use their kebab-case equivalents when using in-DOM ` + + `templates. You should probably use "${altKey}" instead of "${key}".`); + } + } + checkProp(res, props, key, altKey, true) || + checkProp(res, attrs, key, altKey, false); + } + } + return res; +} +function checkProp(res, hash, key, altKey, preserve) { + if (isDef(hash)) { + if (hasOwn(hash, key)) { + res[key] = hash[key]; + if (!preserve) { + delete hash[key]; + } + return true; + } + else if (hasOwn(hash, altKey)) { + res[key] = hash[altKey]; + if (!preserve) { + delete hash[altKey]; + } + return true; + } + } + return false; +} + +// The template compiler attempts to minimize the need for normalization by +// statically analyzing the template at compile time. +// +// For plain HTML markup, normalization can be completely skipped because the +// generated render function is guaranteed to return Array. There are +// two cases where extra normalization is needed: +// 1. When the children contains components - because a functional component +// may return an Array instead of a single root. In this case, just a simple +// normalization is needed - if any child is an Array, we flatten the whole +// thing with Array.prototype.concat. It is guaranteed to be only 1-level deep +// because functional components already normalize their own children. +function simpleNormalizeChildren(children) { + for (let i = 0; i < children.length; i++) { + if (isArray(children[i])) { + return Array.prototype.concat.apply([], children); + } + } + return children; +} +// 2. When the children contains constructs that always generated nested Arrays, +// e.g.