diff --git a/docs/src/content/docs/extending/the-plugin-sdk.md b/docs/src/content/docs/extending/the-plugin-sdk.md index 8654af68..85634f81 100644 --- a/docs/src/content/docs/extending/the-plugin-sdk.md +++ b/docs/src/content/docs/extending/the-plugin-sdk.md @@ -355,7 +355,7 @@ covers `Needs` in full. A capability is one named permission, such as `notes.manage`. A role is a set of capabilities an account holds. The core declares four -roles, `admin`, `editor`, `author` and `member`, and six +roles, `admin`, `editor`, `author` and `member`, and seven capabilities. A plugin adds its own through `RoleProvider`, which returns them as data: @@ -463,8 +463,14 @@ export const plugin = { `make generate` wires it in: routes mount inside the admin layout and the rows of `nav` appear in the sidebar after the built-in ones. Each row is a `MenuItem`: the `label` it shows, the address `to`, and -an optional `icon` and `capability`. No built-in plugin uses this path -yet, so expect to be the first through it. +an optional `icon`, `capability` and `count`. No built-in plugin uses +this path yet, so expect to be the first through it. + +A `count` is `{ value, label }`: the number drawn after the label, +hidden at zero, and the translated sentence a screen reader reads for +it, such as `1 update available`. The core's Updates row counts the +update that waits this way. A plugin's `nav` is plain data, so a count +there stays the same while the admin is open. A row naming a `capability` shows only to an account whose role carries it. The screen still opens from a pasted link, so the Go @@ -481,6 +487,10 @@ const session = useSession().data const manages = can(session, 'hello.manage') ``` +The SDK names the core's capabilities as constants, such as +`MANAGE_USERS` and `UPDATE_CORE`, so `can(session, UPDATE_CORE)` +asks whether the account may update Gophenberg. + A row can open a sub menu of its own, as the Site Editor's Navigation row opens the list of menus. Give the route a `staticData.Sidebar` component that draws a `NavigationScreen`. The admin swaps the main @@ -553,8 +563,8 @@ admin: `audioIcon`, `authorIcon`, `backIcon`, `backupIcon`, `downIcon`, `fileIcon`, `imageIcon`, `languageIcon`, `listIcon`, `listViewIcon`, `mediaIcon`, `pageIcon`, `postIcon`, `redoIcon`, `saveIcon`, `settingsIcon`, `sidebarIcon`, `sidebarRtlIcon`, -`trashIcon`, `undoIcon`, `upIcon`, `uploadIcon` and `videoIcon`. -`authorIcon` is the one an +`trashIcon`, `undoIcon`, `upIcon`, `updateIcon`, `uploadIcon` and +`videoIcon`. `authorIcon` is the one an author cell shows when the site shows no avatars, `postIcon` the one an empty content list shows, `mediaIcon` the one an empty media library shows, and `uploadIcon` the one an upload button carries. @@ -569,8 +579,8 @@ The sidebar rows carry the icons WordPress draws for the same rows: `postIcon` for Posts and every type a site adds, `pageIcon` for Pages, `categoryIcon` for Categories, `mediaIcon` for Media, `brushIcon` for Themes, `customPostTypeIcon` for Content Types, -`listIcon` for Field Groups, `languageIcon` for Language and -`settingsIcon` for Settings. +`listIcon` for Field Groups, `languageIcon` for Language, +`settingsIcon` for Settings and `updateIcon` for Updates. Import them from the SDK, so the admin keeps one copy of the icon set: ```ts diff --git a/docs/src/content/docs/self-hosting/updates-and-backups.md b/docs/src/content/docs/self-hosting/updates-and-backups.md index f6b9e439..559263a7 100644 --- a/docs/src/content/docs/self-hosting/updates-and-backups.md +++ b/docs/src/content/docs/self-hosting/updates-and-backups.md @@ -695,6 +695,81 @@ its start check, it goes back on its own, as shows, and the admin can try that version again once you have fixed what failed. +### The Updates screen + +**Updates** is the last item of the admin menu. It shows to every role +carrying `update_core`, which `admin` carries. While a newer version +waits, a small number sits beside **Updates**, and a line above every +other admin screen names the version and links to the screen. After an +update fails before it switches builds, a line says the update to that +version failed to complete and links to the screen to try again. When +the failed version is the one on offer, only that line shows. + +From top to bottom, the screen shows: + +- The version that runs, under the title. +- When the site last checked for a new version, and when the next + check runs. **Check again** checks now. A second check within + `GOPHENBERG_UPDATES_SCREEN_CHECK_AGE`, one minute unless set, is + refused, and the screen asks you to try again later. When + `GOPHENBERG_UPDATE_CHECKS` is `false`, the screen says the site does + not check on its own. +- That the site receives no automatic updates. Nothing installs until + you press the button. +- The version on offer and a link to its release notes, or that the + site runs the latest version. Before the first good check it says + neither, as it cannot know yet. There is no button to install the + same version again, since the server refuses a version that is not + newer than the one that runs. +- How many database backups the install root keeps, and when the + newest was taken. + +**Update to version** asks before it starts, and says what happens if +the new version does not start. Once you confirm, the warning to back +up and the sentence above the button go away, and the screen shows each +step on its own line, the one under way marked: the download, the +unpacking, the check of the unpacked files, the database backup, the +restart and the check of the new version. It asks the server where the +update stands every `GOPHENBERG_UPDATES_SCREEN_PROGRESS_INTERVAL`, 2 +seconds unless set. While the server restarts it cannot answer, so the +screen keeps asking for up to `GOPHENBERG_UPDATES_SCREEN_RESTART_WAIT`, +5 minutes unless set. Opening the screen while an update runs shows its +steps and its ending too. + +The update ends in one of five ways: + +- **Gophenberg updated successfully.** The open tab still runs the old + admin, so press **Reload the admin**. +- **The update to 1.4.1 failed.** The message adds that Gophenberg went + back to 1.4.0 and is running normally, since the new version failed + its start check. It stays until you dismiss it. The version stays on + offer, and under the line saying it failed its start check, the + button now reads **Re-install version 1.4.1**. It tries that version + again, as `-retry` does, so fix what failed first. +- **The update to 1.4.1 failed its start check, and Gophenberg cannot + go back to 1.4.0 on its own.** An update that raised the minimum + version failed its start check, and the screen says so once the + service manager starts the new version again. Run `update:status` to + see the backup taken before the update, then restore it or fix what + failed, see + [an update that raised the minimum version](#an-update-that-raised-the-minimum-version). +- **The update failed before anything changed.** A step before the + switch failed, and the reason follows. The site keeps running the + version it ran, and **Update to version** tries again. +- **Gophenberg has not come back yet.** The wait passed with no answer + from the new version. Check that your service manager starts + Gophenberg again after exit code 75, and run `update:status` on the + server to see where the update stands. The screen keeps asking, and + shows how the update ended once Gophenberg answers again. + +Two offers show no button. An update that needs a newer PostgreSQL +names the version it needs. An install that updates by hand, such as +the Docker image or a binary you built yourself, says why and links to +this page. An update that raised the minimum version keeps its button, +and says the backup is required and that the site stays down if the +new version does not start, see +[an update that raised the minimum version](#an-update-that-raised-the-minimum-version). + ### The boot guard At every start, before it opens the database, Gophenberg reads diff --git a/frontend/package.json b/frontend/package.json index 9dd89b24..22d92ad6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -21,12 +21,13 @@ }, "dependencies": { "@gophenberg/frontend-sdk": "workspace:*", - "@gopherium/godmin": "0.25.0", + "@gopherium/godmin": "0.26.0", "@gopherium/gottext": "0.7.0", "@gopherium/react-auth": "0.15.0", "@tanstack/react-query": "^5.102.8", "@tanstack/react-router": "^1.170.44", "@wordpress/date": "5.57.0", + "@wordpress/element": "9.0.0", "@wordpress/i18n": "6.30.0", "@wordpress/icons": "18.0.0", "@wordpress/theme": "2.3.0", diff --git a/frontend/src/Layout.tsx b/frontend/src/Layout.tsx index dae1cb33..1cdbec3b 100644 --- a/frontend/src/Layout.tsx +++ b/frontend/src/Layout.tsx @@ -11,6 +11,8 @@ import { __, sprintf } from '@wordpress/i18n' import { useContentNav, useDefaultType } from './content/nav' import { coreNav } from './menu/coreNav' import { plugins } from './plugins' +import { useUpdatesMenuItem } from './updates/nav' +import { UpdateNag } from './updates/UpdateNag' import { useAppVersion } from './version' /** @@ -38,12 +40,12 @@ export function Layout() { > plugin.nav)]} + items={[...useContentNav(), ...coreNav, useUpdatesMenuItem(), ...plugins.flatMap((plugin) => plugin.nav)]} home={useHome()} can={(capability) => can(session, capability)} /> - + }> diff --git a/frontend/src/index.css b/frontend/src/index.css index 7cd38426..7067eb2a 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -71,6 +71,51 @@ } } +.gophenberg-updates__check { + padding: 0; + border: 0; + background: none; + font: inherit; + text-decoration: underline; + cursor: pointer; +} + +.gophenberg-updates__check:disabled { + cursor: default; +} + +.gophenberg-updates__last-check { + text-wrap: wrap; +} + +.gophenberg-updates__version { + white-space: nowrap; +} + +.gophenberg-updates__steps { + display: flex; + flex-direction: column; + gap: var(--wpds-dimension-gap-sm); + margin: 0; + padding: 0; + list-style: none; +} + +.gophenberg-updates__steps:focus { + outline: none; +} + +.gophenberg-updates__steps > li { + display: flex; + align-items: center; + gap: var(--wpds-dimension-gap-sm); + color: var(--wpds-color-foreground-content-neutral-weak); +} + +.gophenberg-updates__steps > li[aria-current='step'] { + color: var(--wpds-color-foreground-content-neutral); +} + .gophenberg-no-access { box-sizing: border-box; max-width: min(var(--wpds-dimension-surface-width-lg), calc(100% - 2 * var(--wpds-dimension-padding-lg))); diff --git a/frontend/src/languages/es-ES.json b/frontend/src/languages/es-ES.json index 491c9dac..ee837c14 100644 --- a/frontend/src/languages/es-ES.json +++ b/frontend/src/languages/es-ES.json @@ -1 +1 @@ -{"":{"lang":"es","plural-forms":"nplurals=3; plural=((n == 1) ? 0 : ((n != 0 && n % 1000000 == 0) ? 1 : 2));"}," and ":[" y "]," or ":[" o "],"\"%s\" activated.":["Se ha activado «%s»."],"\"%s\" deactivated.":["Se ha desactivado «%s»."],"\"%s\" has been restored.":["«%s» se ha restaurado."],"\"%s\" moved to the trash.":["«%s» trasladado a la papelera."],"\"%s\" permanently deleted.":["«%s» borrado permanentemente."],"\"%s\" successfully created.":["«%s» creado correctamente."],"\"%s\" uploaded.":["«%s» subido."],"%(field)s address":["Dirección de %(field)s"],"%(field)s cannot move inside itself. Pick a container that is not one of its own.":["%(field)s no puede moverse dentro de sí mismo. Elige un contenedor que no sea uno de los suyos."],"%(field)s declared.":["%(field)s declarado."],"%(field)s deleted.":["%(field)s borrado."],"%(field)s does not match the format its field asks for. Check it and save again.":["%(field)s no tiene el formato que su campo requiere. Revísalo y guarda de nuevo."],"%(field)s goes no higher than %(limit)s. Lower the value and save again.":["%(field)s no pasa de %(limit)s. Baja el valor y guarda de nuevo."],"%(field)s goes no lower than %(limit)s. Raise the value and save again.":["%(field)s no baja de %(limit)s. Sube el valor y guarda de nuevo."],"%(field)s holds no value of its own, so it cannot be required. Make it optional.":["%(field)s no guarda ningún valor propio, así que no puede ser obligatorio. Hazlo opcional."],"%(field)s is optional again.":["%(field)s vuelve a ser opcional."],"%(field)s is required now.":["%(field)s ahora es obligatorio."],"%(field)s moved.":["%(field)s movido."],"%(field)s names the same one twice. Remove the repeat and save again.":["%(field)s nombra el mismo dos veces. Quita la repetición y guarda de nuevo."],"%(field)s needs at least %(limit)s files. Add one and save again.":["%(field)s necesita al menos %(limit)s archivos. Añade uno y guarda de nuevo."],"%(field)s needs at least %(limit)s rows. Add one and save again.":["%(field)s necesita al menos %(limit)s filas. Añade una y guarda de nuevo."],"%(field)s only takes one of its listed choices. Pick one and save again.":["%(field)s solo admite una de las opciones de su lista. Elige una y guarda de nuevo."],"%(field)s reads a relation field that is not there. Pick a group and a relation field it holds.":["%(field)s lee un campo de relación que no existe. Elige un grupo y un campo de relación que contenga."],"%(field)s reads a relation pointing at %(type)s, so it would list nothing here. Pick a relation pointing at the items this group is shown on.":["%(field)s lee una relación que apunta a %(type)s, así que aquí no mostraría nada. Elige una relación que apunte a los elementos donde se muestra este grupo."],"%(field)s renamed.":["%(field)s renombrado."],"%(field)s settled.":["%(field)s ajustado."],"%(field)s shows by its rules now.":["%(field)s ahora se muestra según sus reglas."],"%(field)s stands in the list.":["%(field)s aparece en la lista."],"%(field)s stays out of the list.":["%(field)s se queda fuera de la lista."],"%(field)s takes at most %(limit)s files. Remove one and save again.":["%(field)s acepta como mucho %(limit)s archivos. Quita uno y guarda de nuevo."],"%(field)s takes at most %(limit)s letters. Shorten what you wrote and save again.":["%(field)s acepta como mucho %(limit)s letras. Acorta lo que has escrito y guarda de nuevo."],"%(field)s takes at most %(limit)s rows. Remove one and save again.":["%(field)s admite como mucho %(limit)s filas. Quita una y guarda de nuevo."],"%(field)s title":["Título de %(field)s"],"%(file)s is larger than one upload may be.":["%(file)s es más grande de lo que una subida permite."],"%(file)s is not a file this block accepts.":["%(file)s no es un archivo que este bloque acepte."],"%(file)s: %(reason)s":["%(file)s: %(reason)s"],"%(group)s created.":["%(group)s creado."],"%(group)s now appears where you said.":["%(group)s ya aparece donde has dicho."],"%(group)s removed.":["%(group)s eliminado."],"%(group)s updated.":["%(group)s actualizado."],"%(key)s is served by %(winner)s, so %(loser)s does not show it on %(where)s.":["%(key)s lo sirve %(winner)s, así que %(loser)s no lo muestra en %(where)s."],"%(name)s %(version)s is serving the public site.":["%(name)s %(version)s está publicado en la web."],"%(name)s belongs to the site now.":["%(name)s ya pertenece al sitio."],"%(name)s came from the %(plugin)s plugin, which no longer declares it.":["%(name)s vino del plugin %(plugin)s, que ya no lo declara."],"%(name)s cannot be used as a theme name. Name the zip file after the theme, with no dot at the start and no slashes in it.":["%(name)s no se puede usar como nombre de tema. Nombra el archivo zip como el tema, sin punto al principio y sin barras."],"%(name)s moves to /%(word)s. Every address of both types changes.":["El tipo %(name)s pasa a /%(word)s. Cambian todas las direcciones de ambos tipos."],"%(name)s would move to /%(word)s, which Gophenberg keeps for itself. Change its plural name and try again.":["El tipo %(name)s pasaría a /%(word)s, que Gophenberg reserva para sí mismo. Cambia su nombre en plural e inténtalo de nuevo."],"%(source)s is %(value)s":["%(source)s es %(value)s"],"%(theme)s failed to start, so the built-in renderer is serving.":["%(theme)s no pudo arrancar, así que el renderizador ha tomado el relevo."],"%(theme)s is now serving the public site.":["%(theme)s ya sirve el sitio público."],"%(theme)s is serving the public site.":["%(theme)s sirve el sitio público."],"%(theme)s is still starting, so the built-in renderer is serving.":["%(theme)s todavía está arrancando, así que el renderizador ha tomado el relevo."],"%(theme)s was installed.":["%(theme)s se ha instalado."],"%(theme)s will not load, so the built-in renderer is serving.":["%(theme)s no se carga, así que el renderizador ha tomado el relevo."],"%(type)s answers on a new address, and stored links move with it.":["%(type)s responde en una dirección nueva, y los enlaces guardados se mueven con ella."],"%(type)s becomes the type the site opens on, and the old one takes an address.":["%(type)s pasa a ser el tipo con el que abre el sitio, y el anterior toma una dirección."],"%(type)s keeps nesting while %(items)s of its items sit inside another. Move those to the top level first, the ones in the trash included.":["%(type)s sigue anidando mientras %(items)s de sus elementos están dentro de otro. Muévelos primero al nivel superior, incluidos los de la papelera."],"%(type)s keeps nesting, because some of its items sit inside another.":["%(type)s sigue anidando, porque algunos de sus elementos están dentro de otro."],"%(type)s will answer at the root.":["El tipo %(type)s responderá en la raíz."],"%s content type activated.":["Se ha activado %s tipo de contenido.","Se han activado %s de tipos de contenido.","Se han activado %s tipos de contenido."],"%s content type could not be activated.":["No se ha podido activar %s tipo de contenido.","No se han podido activar %s de tipos de contenido.","No se han podido activar %s tipos de contenido."],"%s content type could not be deactivated.":["No se ha podido desactivar %s tipo de contenido.","No se han podido desactivar %s de tipos de contenido.","No se han podido desactivar %s tipos de contenido."],"%s content type could not be permanently deleted.":["No se ha podido borrar permanentemente %s tipo de contenido.","No se han podido borrar permanentemente %s de tipos de contenido.","No se han podido borrar permanentemente %s tipos de contenido."],"%s content type deactivated.":["Se ha desactivado %s tipo de contenido.","Se han desactivado %s de tipos de contenido.","Se han desactivado %s tipos de contenido."],"%s content type permanently deleted.":["Se ha borrado permanentemente %s tipo de contenido.","Se han borrado permanentemente %s de tipos de contenido.","Se han borrado permanentemente %s tipos de contenido."],"%s item could not be moved to the trash.":["No se ha podido mover %s elemento a la papelera.","No se han podido mover %s de elementos a la papelera.","No se han podido mover %s elementos a la papelera."],"%s item could not be permanently deleted.":["No se ha podido borrar permanentemente %s elemento.","No se han podido borrar permanentemente %s de elementos.","No se han podido borrar permanentemente %s elementos."],"%s item could not be restored.":["No se ha podido restaurar %s elemento.","No se han podido restaurar %s de elementos.","No se han podido restaurar %s elementos."],"%s item moved to the trash.":["%s elemento movido a la papelera.","%s de elementos movidos a la papelera.","%s elementos movidos a la papelera."],"%s item permanently deleted.":["%s elemento borrado permanentemente.","%s de elementos borrados permanentemente.","%s elementos borrados permanentemente."],"%s item stays in the trash.":["%s elemento sigue en la papelera.","%s de elementos siguen en la papelera.","%s elementos siguen en la papelera."],"%s page has been restored.":["Se ha restaurado %s página.","Se han restaurado %s de páginas.","Se han restaurado %s páginas."],"%s post has been restored.":["Se ha restaurado %s entrada.","Se han restaurado %s de entradas.","Se han restaurado %s entradas."],"(no title)":["(sin título)"],"A %(kind)s field does not take a setting called %(setting)s. Remove it and try again.":["Un campo %(kind)s no acepta un ajuste llamado %(setting)s. Quítalo y prueba de nuevo."],"A Linked from field stands on its own, not inside a section or a repeater. Declare %(field)s beside the container.":["Un campo Enlazado desde va por su cuenta, no dentro de una sección ni de un repetidor. Declara %(field)s junto al contenedor."],"A content type needs a singular and a plural name, like Guide and Guides. Fill both in and try again.":["Un tipo de contenido necesita un nombre en singular y otro en plural, como Guía y Guías. Rellena ambos e inténtalo de nuevo."],"A descriptive summary of the content type.":["Un resumen descriptivo del tipo de contenido."],"A field group key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Rename the group in the file so its key comes out in that shape.":["La clave de un grupo de campos tiene que empezar por una letra minúscula y después llevar solo letras minúsculas, números y guiones. Cambia el nombre del grupo en el archivo para que su clave salga con esa forma."],"A field key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Rename the field so its key comes out in that shape.":["La clave de un campo tiene que empezar por una letra minúscula y contener solo letras minúsculas, números y guiones. Renombra el campo para que su clave tenga esa forma."],"A field needs a name. Type one and try again.":["El campo necesita un nombre. Escribe uno e inténtalo de nuevo."],"A field with that name already exists on the items this group reaches. Pick another name.":["Ya existe un campo con ese nombre en los elementos que este grupo alcanza. Elige otro nombre."],"A flexible content field holds layouts, and %(field)s is not one. Add a layout first, then declare the field inside that layout.":["Un campo de contenido flexible contiene diseños, y %(field)s no lo es. Añade primero un diseño y después declara el campo dentro de ese diseño."],"A higher quality stores larger files, and it applies to pictures uploaded from now on.":["Una calidad más alta almacena archivos más grandes, y se aplica a las imágenes que subas a partir de ahora."],"A layout stands inside a flexible content field only. Put %(field)s inside one of those instead.":["Un diseño solo va dentro de un campo de contenido flexible. Pon %(field)s dentro de uno de ellos."],"A layout stands inside a flexible content field, never on its own. Declare a flexible content field first, then add %(field)s inside it.":["Un diseño va dentro de un campo de contenido flexible, nunca por su cuenta. Declara primero un campo de contenido flexible y después añade %(field)s dentro."],"A listing carries between 1 and %(max)s items, so %(value)s is not a size Gophenberg takes. Pick a number inside that range.":["Un listado muestra entre 1 y %(max)s elementos, así que %(value)s no es un tamaño que Gophenberg acepte. Elige un número dentro de ese rango."],"A relation field has to say which content type it points at. Pick that type and try again.":["Un campo de relación tiene que indicar a qué tipo de contenido apunta. Elige ese tipo e inténtalo de nuevo."],"A reload shows the admin in the language you chose.":["Al recargar verás el panel de administración en el idioma que has elegido."],"A route word has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Change it and try again.":["La palabra de ruta de la URL tiene que empezar por una letra minúscula y contener solo letras minúsculas, números y guiones. Cámbiala e inténtalo de nuevo."],"A row of %(field)s has to name the layout it takes. Pick a layout for the row, or remove the row.":["Una fila de %(field)s tiene que nombrar el diseño que toma. Elige un diseño para la fila, o quita la fila."],"A row of %(field)s takes one layout and no more. Reload the page and build the row again.":["Una fila de %(field)s toma un solo diseño. Recarga la página y crea la fila otra vez."],"A rule matching any %(source)s cannot be turned into an exclusion. Leave it as is, or name the ones to leave out instead.":["Una regla que vale para cualquier %(source)s no se puede convertir en exclusión. Déjala como está, o nombra los que quieras dejar fuera."],"A theme naming its own page size uses that instead.":["Un tema que indica su propio tamaño de página usa ese en su lugar."],"A type key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Change the key and try again.":["La clave de un tipo tiene que empezar por una letra minúscula y contener solo letras minúsculas, números y guiones. Cambia la clave e inténtalo de nuevo."],"Actions":["Acciones"],"Activate":["Activar"],"Activate %(theme)s":["Activar %(theme)s"],"Active":["Activo"],"Add":["Añadir"],"Add %(layout)s":["Añadir %(layout)s"],"Add %(name)s":["Añadir %(name)s"],"Add %(type)s":["Añadir %(type)s"],"Add Category":["Añadir categoría"],"Add Content Type":["Añadir tipo de contenido"],"Add Field Group":["Añadir grupo de campos"],"Add Media File":["Añadir medios"],"Add Page":["Añadir página"],"Add Post":["Añadir entrada"],"Add User":["Añadir usuario"],"Add block":["Añadir bloque"],"Add choice":["Añadir opción"],"Add condition":["Añadir condición"],"Add field":["Añadir campo"],"Add field to %(field)s":["Añadir campo a %(field)s"],"Add layout":["Añadir diseño"],"Add layout to %(field)s":["Añadir diseño a %(field)s"],"Add one with %(button)s.":["Añade un elemento con %(button)s."],"Add row":["Añadir fila"],"Add rule set":["Añadir conjunto de reglas"],"Add title":["Añadir título"],"Add to %(field)s":["Añadir a %(field)s"],"Address":["Dirección"],"Address updated.":["Dirección actualizada."],"Adopt":["Adoptar"],"Allow custom":["Permitir valores propios"],"Allow empty":["Permitir vacío"],"Alt text":["Texto alternativo"],"An item cannot point at itself. Pick a different item for %(field)s.":["Un elemento no puede apuntarse a sí mismo. Elige otro elemento para %(field)s."],"An item cannot sit inside itself, or inside one of the items nested under it. Pick a parent outside this branch.":["Un elemento no puede estar dentro de sí mismo, ni dentro de otro anidado bajo él. Elige un nivel superior fuera de esta rama."],"Another account wrote this, and only its author, an editor or an administrator may change it. You can still read it.":["Otra cuenta escribió esto, y solo su autor, un editor o un administrador pueden cambiarlo. Todavía puedes leerlo."],"Another account wrote this, so you are reading it rather than editing it.":["Otra cuenta escribió esto, así que lo estás leyendo, no editando."],"Another content type already answers under this route word. Pick a different word.":["Ya hay otro tipo de contenido que responde con esta palabra de ruta de URL. Elige una palabra distinta."],"Another content type already lives at the root of your site, and only one can. Give this type a route word, or hand the root over with Make default.":["Ya hay otro tipo de contenido en la raíz de tu sitio, y solo puede haber uno. Dale a este tipo de contenido una palabra de ruta de URL, o cede la raíz con Establecer como predeterminado."],"Another content type already uses this key. Give this type a different name.":["Ya hay otro tipo de contenido que usa esta clave. Dale a este tipo un nombre distinto."],"Another item of this content type already uses that address. Pick a different slug and save again.":["Ya hay otro elemento de este tipo de contenido que usa esa dirección. Elige un slug distinto y guarda de nuevo."],"Another update is currently in progress.":["En este momento hay otra actualización en marcha."],"Appears on":["Aparece en"],"Apply":["Aplicar"],"April":["abril"],"Are you sure you want to move \"%s\" to the trash?":["¿Seguro que quieres mover «%s» a la papelera?"],"Audio":["Audio"],"August":["agosto"],"Author":["Autor"],"Back to %(type)s":["Volver a %(type)s"],"Back to the latest posts":["Volver a las últimas entradas"],"Block":["Bloque"],"Broken":["Roto"],"Bundles of fields, shown where their rules place them.":["Conjuntos de campos, mostrados donde sus reglas los colocan."],"Button group":["Grupo de botones"],"Cancel":["Cancelar"],"Caption":["Leyenda"],"Change %(name)s":["Cambiar %(name)s"],"Change address":["Cambiar la dirección"],"Change address…":["Cambiar la dirección…"],"Change role":["Cambiar el rol"],"Change the role of %(name)s":["Cambiar el rol de %(name)s"],"Checkbox group":["Grupo de casillas"],"Choices":["Opciones"],"Choose %(field)s":["Elegir %(field)s"],"Choose how the site serves its content.":["Elige cómo el sitio sirve su contenido."],"Choose the language the admin reads in.":["Elige el idioma en el que se lee el panel de administración."],"Choose the role of %(name)s.":["Elige el rol de %(name)s."],"Choose the version to update to.":["Elige la versión a la que actualizar."],"Clear %(field)s":["Vaciar %(field)s"],"Close":["Cerrar"],"Close Settings":["Cerrar ajustes"],"Closed":["Cerrado"],"Condition":["Condición"],"Content":["Contenido"],"Content Types":["Tipos de contenido"],"Content nests at most %(max)s levels deep, and this item would sit deeper. Pick a parent closer to the top.":["El contenido se anida como mucho %(max)s niveles, y este elemento quedaría más abajo. Elige un nivel superior más cercano al inicio."],"Content type":["Tipo de contenido"],"Content type updated.":["Tipo de contenido actualizado."],"Could not load that post.":["No se ha podido cargar esa entrada."],"Could not save image. %s":["No se ha podido guardar la imagen. %s"],"Could not save media. %s":["No se ha podido guardar el archivo multimedia. %s"],"Could not save that post.":["No se ha podido guardar esa entrada."],"Create":["Crear"],"Create a field group":["Crear un grupo de campos"],"Create user":["Crear usuario"],"Created":["Fecha de creación"],"Date added":["Fecha de inclusión"],"Date modified":["Fecha de modificación"],"Deactivate":["Desactivar"],"Deactivate %(theme)s":["Desactivar %(theme)s"],"December":["diciembre"],"Default":["Por defecto"],"Default content type updated.":["Tipo de contenido predeterminado actualizado."],"Definitions file":["Archivo de definiciones"],"Delete":["Borrar"],"Delete \"%(title)s\" for good? This cannot be undone.":["¿Borrar permanentemente «%(title)s»? Esto no se puede deshacer."],"Delete %(field)s":["Borrar %(field)s"],"Delete %(group)s":["Eliminar %(group)s"],"Delete %s content type for good? This cannot be undone.":["¿Borrar permanentemente %s tipo de contenido? Esto no se puede deshacer.","¿Borrar permanentemente %s de tipos de contenido? Esto no se puede deshacer.","¿Borrar permanentemente %s tipos de contenido? Esto no se puede deshacer."],"Delete %s item for good? This cannot be undone.":["¿Borrar permanentemente %s elemento? Esto no se puede deshacer.","¿Borrar permanentemente %s de elementos? Esto no se puede deshacer.","¿Borrar permanentemente %s elementos? Esto no se puede deshacer."],"Delete permanently":["Borrar permanentemente"],"Delete the field":["Borrar el campo"],"Delete the group":["Eliminar el grupo"],"Delete…":["Borrar…"],"Describe":["Describir"],"Describe the purpose of the image.":["Describe el propósito de la imagen."],"Describe…":["Describir…"],"Description":["Descripción"],"Description updated.":["Descripción actualizada."],"Desktop":["Escritorio"],"Destination":["Destino"],"Dimensions":["Dimensiones"],"Disable":["Desactivar"],"Disable %(name)s":["Desactivar a %(name)s"],"Disabled":["Desactivado"],"Dismiss":["Descartar"],"Document":["Documento"],"Documents":["Documentos"],"Done. The site now holds what the file describes.":["Hecho. El sitio ya tiene lo que describe el archivo."],"Draft saved.":["Borrador guardado."],"Drop files to upload":["Arrastra los archivos para subirlos"],"Edit media":["Editar los medios"],"Edit…":["Editar…"],"Email":["Correo electrónico"],"Empty Trash":["Vaciar papelera"],"Empty trash":["Vaciar papelera"],"Enable":["Activar"],"Enable %(name)s":["Activar a %(name)s"],"Every address of this type moves. Links kept elsewhere to the old addresses stop working.":["Cambian todas las direcciones de este tipo. Los enlaces guardados en otro sitio hacia las direcciones antiguas dejan de funcionar."],"Every content type":["Todos los tipos de contenido"],"Every field group needs a title. Give it a name and save again.":["Todo grupo de campos necesita un título. Ponle un nombre y guarda otra vez."],"Every item needs an author who exists. Pick one from the list and save again.":["Cada elemento necesita un autor que exista. Elige uno de la lista y guarda de nuevo."],"Every kind of content this site holds.":["Todos los tipos de contenido que hay en este sitio."],"Every value stored under this field goes with it, in every item the group reaches and in the revisions behind them.":["Todos los valores guardados en este campo se van con él, en cada elemento que el grupo alcanza y en las revisiones que hay detrás."],"Excerpt":["Extracto"],"Export definitions":["Exportar definiciones"],"February":["febrero"],"Fewest files":["Mínimo de archivos"],"Fewest rows":["Mínimo de filas"],"Field":["Campo"],"Field Groups":["Grupos de campos"],"Field group":["Grupo de campos"],"Fields":["Campos"],"Fields of %(group)s":["Campos de %(group)s"],"File name":["Nombre del archivo"],"File size":["Tamaño del archivo"],"File type":["Tipo de archivo"],"Filter by status":["Filtrar por estado"],"Follow the browser":["Sigue al navegador"],"From %(plugin)s":["De %(plugin)s"],"Full Size":["Tamaño completo"],"Gophenberg cannot start this update: %(reason)s":["Gophenberg no puede empezar esta actualización: %(reason)s"],"Gophenberg checked for updates moments ago. Try again later.":["Gophenberg ha buscado actualizaciones hace un momento. Inténtalo de nuevo más tarde."],"Gophenberg could not read what your browser sent. Reload the page and try again, and tell whoever looks after your site if it keeps happening.":["Gophenberg no ha podido leer lo que ha enviado tu navegador. Recarga la página e inténtalo de nuevo, y avisa a quien gestiona tu sitio si sigue pasando."],"Gophenberg could not read which item you picked as parent. Reload the page and pick it again.":["Gophenberg no ha podido leer qué elemento has elegido como elemento superior. Recarga la página y vuelve a elegirlo."],"Gophenberg does not accept %(extension)s files. Upload a picture, a video, an audio file, a PDF or a zip instead.":["Gophenberg no acepta archivos %(extension)s. Sube una imagen, un vídeo, un audio, un PDF o un zip."],"Gophenberg does not answer in %(value)s. Pick one of the languages on the list.":["Gophenberg no responde en %(value)s. Elige uno de los idiomas de la lista."],"Gophenberg has no autosave of yours for this item. Open the item to see the version that is stored.":["Gophenberg no tiene ningún guardado automático tuyo de este elemento. Ábrelo para ver la versión guardada."],"Gophenberg holds no kind of definition called %(subject)s, so nothing was taken over. Reload the page so the admin and the server agree again.":["Gophenberg no tiene ninguna clase de definición llamada %(subject)s, así que no se ha adoptado nada. Recarga la página para que el admin y el servidor vuelvan a coincidir."],"Gophenberg keeps /%(path)s for itself or for another content type, so your content cannot answer there. Give the item a different slug.":["Gophenberg reserva la dirección /%(path)s para sí mismo o para otro tipo de contenido, así que tu contenido no puede usarla. Dale al elemento otro slug."],"Gophenberg keeps this word for itself, so no content type can answer under it. Pick a different route word.":["Gophenberg reserva esta palabra para sí mismo, así que ningún tipo de contenido puede usarla. Elige otra palabra de ruta de URL."],"Group":["Grupo"],"Highest":["Máximo"],"Holds":["Contiene"],"Images":["Imágenes"],"Import definitions":["Importar definiciones"],"In list":["En la lista"],"Inactive":["Inactivo"],"Installed":["Instalado"],"Instructions":["Instrucciones"],"It moves here from another group and keeps its stored values.":["Se mueve aquí desde otro grupo y conserva sus valores guardados."],"It moves to another group and keeps its stored values.":["Se mueve a otro grupo y conserva sus valores guardados."],"It moves to another group, so its stored values do not follow.":["Se mueve a otro grupo, así que sus valores guardados no le siguen."],"It reads a relation inside a container, and only an import can point it elsewhere.":["Lee una relación dentro de un contenedor, y solo una importación puede apuntarlo a otro sitio."],"It starts on %(type)s, and the rules may be edited afterwards.":["Empieza en %(type)s, y las reglas se pueden editar después."],"Items could not be loaded.":["No se han podido cargar los elementos."],"Its items sit inside one another, so it keeps nesting.":["Sus elementos están unos dentro de otros, así que sigue anidando."],"Its kind changed, so its stored values go with it.":["Su tipo ha cambiado, así que sus valores guardados se van con él."],"January":["enero"],"July":["julio"],"June":["junio"],"Keep %(field)s out of the list":["Dejar %(field)s fuera de la lista"],"Keep it":["Conservarlo"],"Keep it here":["Dejarlo aquí"],"Key":["Clave"],"Label":["Etiqueta"],"Language":["Idioma"],"Large":["Grande"],"Leave empty if decorative.":["Déjalo vacío si es decorativo."],"Let items nest":["Permitir anidar"],"Linked from":["Enlazado desde"],"List view":["Vista de lista"],"Loading field groups.":["Cargando los grupos de campos."],"Loading the post.":["Cargando la entrada."],"Loading the screen.":["Cargando la pantalla."],"Loading themes.":["Cargando los temas."],"Loading users.":["Cargando los usuarios."],"Loading…":["Cargando…"],"Longest":["Largo máximo"],"Lowest":["Mínimo"],"Make %(field)s optional":["Hacer %(field)s opcional"],"Make default":["Establecer como predeterminado"],"Make default…":["Establecer como predeterminado…"],"Make optional":["Hacer opcional"],"Manage the categories on this site.":["Gestiona las categorías de este sitio."],"Manage the images and files this site holds.":["Gestiona las imágenes y los archivos que hay en este sitio."],"Manage the items of this content type.":["Gestiona los elementos de este tipo de contenido."],"Manage the pages on this site.":["Gestiona las páginas de este sitio."],"Manage the posts on this site.":["Gestiona las entradas de este sitio."],"Many targets":["Varios destinos"],"Many values":["Varios valores"],"March":["marzo"],"May":["mayo"],"Media %(id)s":["Medio %(id)s"],"Media Library":["Biblioteca de medios"],"Media file updated.":["Archivo de medios actualizado."],"Medium":["Mediano"],"Mobile":["Móvil"],"Modified: %s":["Modificado: %s"],"Most files":["Máximo de archivos"],"Most rows":["Máximo de filas"],"Move":["Mover"],"Move \"%(title)s\" to the trash?":["¿Mover «%(title)s» a la papelera?"],"Move %(field)s down":["Bajar %(field)s"],"Move %(field)s elsewhere":["Mover %(field)s a otro sitio"],"Move %(field)s up":["Subir %(field)s"],"Move %(group)s down":["Bajar %(group)s"],"Move %(group)s up":["Subir %(group)s"],"Move %(name)s down":["Bajar %(name)s"],"Move %(name)s up":["Subir %(name)s"],"Move %s item to the trash?":["¿Mover %s elemento a la papelera?","¿Mover %s de elementos a la papelera?","¿Mover %s elementos a la papelera?"],"Move every address":["Mover todas las direcciones"],"Move row down":["Bajar la fila"],"Move row up":["Subir la fila"],"Move the field":["Mover el campo"],"Move to trash":["Mover a la papelera"],"Name":["Nombre"],"Name updated.":["Nombre actualizado."],"Nests":["Anida"],"Newer posts":["Entradas más recientes"],"No":["No"],"No content types found.":["No se han encontrado tipos de contenido."],"No description":["Sin descripción"],"No file arrived with this upload. Choose a file and try again.":["No ha llegado ningún archivo con esta subida. Elige un archivo e inténtalo de nuevo."],"No items found.":["No se han encontrado elementos."],"No items yet.":["Todavía no hay elementos."],"No media chosen":["Ningún medio elegido"],"No media has been uploaded yet.":["Todavía no se ha subido ningún medio."],"No media items found.":["No se han encontrado archivos de medios."],"No media items yet.":["Todavía no hay archivos de medios."],"No page lives at this address.":["No existe ninguna página en esta dirección."],"No parent":["Sin elemento superior"],"No theme arrived with this upload. Choose a zip file and try again.":["No ha llegado ningún tema con esta subida. Elige un archivo zip e inténtalo de nuevo."],"No themes are installed.":["No hay ningún tema instalado."],"No title":["Sin título"],"None":["Ninguno"],"Not %(type)s":["Excepto %(type)s"],"Not found":["No encontrado"],"Not serving":["No está sirviendo"],"Nothing declares that role.":["Nada declara ese rol."],"Nothing points here yet.":["Todavía no apunta nada aquí."],"Nothing published here yet.":["Todavía no hay nada publicado aquí."],"Nothing published yet.":["Todavía no hay nada publicado."],"November":["noviembre"],"Nowhere":["En ningún sitio"],"Number":["Número"],"October":["octubre"],"Older posts":["Entradas anteriores"],"One frame of this animation holds more than %(max)s pixels, which is more than Gophenberg opens. Upload a smaller animation.":["Un fotograma de esta animación tiene más de %(max)s píxeles, más de lo que Gophenberg abre. Sube una animación más pequeña."],"One of the filters on this list is not one Gophenberg understands. Clear the filters and try again.":["Uno de los filtros de esta lista no es un filtro que Gophenberg entienda. Quita los filtros e inténtalo de nuevo."],"One of the items picked for %(field)s is not the kind of content that field points at. Reload the page and pick from the list the field offers.":["Uno de los elementos elegidos para %(field)s no es del tipo de contenido al que apunta ese campo. Recarga la página y elige de la lista que ofrece el campo."],"One of the items picked for %(field)s was not named in a way Gophenberg understands. Reload the page and pick the items again.":["Uno de los elementos elegidos para %(field)s no venía nombrado de una forma que Gophenberg entienda. Recarga la página y vuelve a elegir los elementos."],"One of the items picked no longer exists. Reload the page and pick again.":["Uno de los elementos elegidos ya no existe. Recarga la página y vuelve a elegir."],"One target":["Un destino"],"Only a relation field points at another content type or holds many items. Pick the Relation kind, or leave the target and the many option empty.":["Solo un campo de relación apunta a otro tipo de contenido o guarda varios elementos. Elige el tipo Relación, o deja vacío el destino y la opción de varios."],"Only one file may be placed here.":["Aquí solo se puede colocar un archivo."],"Only the content type at the root of your site may go without a route word. Give this type one and try again.":["Solo el tipo de contenido que está en la raíz de tu sitio puede ir sin palabra de ruta de URL. Dale una a este tipo e inténtalo de nuevo."],"Open %(field)s in a new tab":["Abrir %(field)s en una pestaña nueva"],"Order stored.":["Orden guardado."],"Other":["Otro"],"Out of list":["Fuera de la lista"],"Parent":["Elemento superior"],"Password":["Contraseña"],"Pending":["Pendiente"],"Pending Review":["Pendiente de revisión"],"Permanently delete…":["Eliminar permanentemente…"],"Picture quality":["Calidad de imagen"],"Picture quality runs from 1 to %(max)s, so %(value)s is not a quality Gophenberg stores at. Pick a number inside that range.":["La calidad de imagen va de 1 a %(max)s, así que %(value)s no es una calidad con la que Gophenberg guarde. Elige un número dentro de ese rango."],"Placeholder":["Texto de ejemplo"],"Plural name":["Nombre en plural"],"Points at":["Apunta a"],"Post published.":["Entrada publicada."],"Posts per page":["Entradas por página"],"Preview":["Vista previa"],"Private":["Privada"],"Publish":["Publicar"],"Published: %s":["Publicado: %s"],"Radio group":["Grupo de botones de radio"],"Reads from":["Lee de"],"Redo":["Rehacer"],"Relation":["Relación"],"Remove":["Quitar"],"Remove %(name)s":["Quitar %(name)s"],"Remove %(title)s":["Quitar %(title)s"],"Remove row":["Quitar fila"],"Rename":["Renombrar"],"Rename %(field)s":["Renombrar %(field)s"],"Rename…":["Renombrar…"],"Require":["Hacer obligatorio"],"Require %(field)s":["Hacer %(field)s obligatorio"],"Required":["Obligatorio"],"Restore":["Restaurar"],"Role changed.":["Rol cambiado."],"Roll back to %(theme)s":["Revertir a %(theme)s"],"Roll back to the built-in renderer":["Revertir al renderizador integrado"],"Route word":["Palabra de ruta"],"Rule %(number)s of set %(set)s":["Regla %(number)s del conjunto %(set)s"],"Rule set %(number)s":["Conjunto de reglas %(number)s"],"Rules":["Reglas"],"Rules showing %(field)s":["Reglas que muestran %(field)s"],"Save":["Guardar"],"Save draft":["Guardar el borrador"],"Save rules":["Guardar las reglas"],"Save settings":["Guardar los ajustes"],"Saved":["Guardado"],"Saving":["Guardando"],"Scheduled":["Programada"],"Scheduled: %s":["Programado: %s"],"Search %(type)s…":["Buscar %(type)s…"],"Search audio":["Buscar audios"],"Search images":["Buscar imágenes"],"Search media":["Buscar medios"],"Search videos":["Buscar vídeos"],"Select":["Seleccionar"],"September":["septiembre"],"Serving":["Atendiendo"],"Settings":["Ajustes"],"Settings of %(field)s":["Ajustes de %(field)s"],"Shadowed":["Eclipsado"],"Show %(field)s in the list":["Mostrar %(field)s en la lista"],"Showing %(held)s of %(total)s.":["Mostrando %(held)s de %(total)s."],"Singular name":["Nombre en singular"],"Slug":["Slug"],"Somebody must be able to manage users.":["Alguien tiene que poder gestionar los usuarios."],"Someone else changed this media item while you were editing it. Reload the page and make your change again.":["Otra persona ha cambiado este medio mientras lo editabas. Recarga la página y vuelve a hacer tu cambio."],"Someone else saved changes to this item while you were editing, so yours were not saved. Copy your text somewhere safe, then reload the item and put your changes back in.":["Otra persona ha guardado cambios en este elemento mientras editabas, así que los tuyos no se han guardado. Copia tu texto a un lugar seguro, recarga el elemento y vuelve a colocarlos de vuelta."],"Something went wrong inside Gophenberg. Try again in a moment, and tell whoever looks after your site if it keeps happening.":["Algo ha fallado dentro de Gophenberg. Inténtalo de nuevo en un momento, y avisa a quien gestione tu sitio si sigue pasando."],"Something went wrong.":["Algo ha ido mal."],"Something went wrong. Try again.":["Algo ha ido mal. Inténtalo de nuevo."],"Sorry, you are not allowed to access this page.":["Lo siento, no tienes permisos para acceder a esta página."],"Source":["Origen"],"Steps of":["Pasos de"],"Stop nesting":["Dejar de anidar"],"Tablet":["Tableta"],"Text":["Texto"],"Text area":["Área de texto"],"That email is already in use.":["Ese correo electrónico ya está en uso."],"That field group no longer exists. Reload the page to see the groups your site holds now.":["Ese grupo de campos ya no existe. Recarga la página para ver los grupos que tiene ahora tu sitio."],"That field is not on this content type any more. Reload the page to see the fields it has now.":["Ese campo ya no está en este tipo de contenido. Recarga la página para ver los campos que tiene ahora."],"That revision does not exist, and older ones drop off once a type holds more than it keeps. Open the item to see which revisions are left.":["Esa revisión no existe, y las más antiguas se pierden cuando un tipo guarda más de las que conserva. Abre el elemento para ver qué revisiones quedan."],"That role holds more than your own.":["Ese rol abarca más que el tuyo."],"That web address does not name a media item Gophenberg can look up. Open the media library and pick the item from there.":["Esa dirección web no nombra ningún medio que Gophenberg pueda encontrar. Abre la biblioteca de medios y elige el elemento desde ahí."],"That web address does not name a revision Gophenberg can look up. Open the item and pick a revision from its history.":["Esa dirección web no alude a ninguna revisión que Gophenberg pueda identificar. Abre el elemento y elige una revisión de su historial."],"That web address does not name an item Gophenberg can look up. Go back to the list and open the item from there.":["Esa dirección web no alude a ningún elemento que Gophenberg pueda identificar. Vuelve a la lista y abre el elemento desde ahí."],"The %(count)s item in the trash is deleted for good. This cannot be undone.":["%(count)s elemento de la papelera se borrará permanentemente. Esto no se puede deshacer.","%(count)s de elementos de la papelera se borrarán permanentemente. Esto no se puede deshacer.","Los %(count)s elementos de la papelera se borrarán permanentemente. Esto no se puede deshacer."],"The %(file)s calls this theme %(declared)s, but it is being installed as %(installed)s. Rename the zip file to match, or change the name inside %(file)s.":["El archivo %(file)s llama a este tema %(declared)s, pero se está instalando como %(installed)s. Renombra el zip para que coincida, o cambia el nombre dentro de %(file)s."],"The %(file)s inside %(name)s is not valid JSON, so it could not be read. Fix that file and package the theme again.":["El archivo %(file)s dentro de %(name)s no es JSON válido, así que no se ha podido leer. Corrige ese archivo y vuelve a empaquetar el tema."],"The %(file)s inside %(name)s names its theme kit as %(declared)s, which is not a version number. Build the theme again, and the build will fill that in.":["El %(file)s dentro de %(name)s identifica su kit de temas como %(declared)s, que no srive como número de versión. Compila el tema de nuevo y la compilación lo rellenará."],"The %(origin)s plugin declared this, so it can only be changed in that plugin. Turning it off is still yours to do.":["El plugin %(origin)s lo declaró, así que solo se puede cambiar en ese plugin. Desactivarlo sigue estando en tu mano."],"The %(plugin)s plugin also declares %(name)s, and the site keeps the key.":["El plugin %(plugin)s también declara %(name)s, y el sitio se queda con la clave."],"The %(plugin)s plugin declared these fields, so they change only in its code.":["El plugin %(plugin)s declaró estos campos, así que solo cambian en su código."],"The %(plugin)s plugin declares %(name)s flat, and the site keeps it nesting while its items sit inside another.":["El plugin %(plugin)s declara %(name)s sin anidar, y el sitio lo mantiene anidando mientras sus elementos están dentro de otro."],"The browser kept an unsaved version of this post.":["El navegador ha guardado una versión sin guardar de esta entrada."],"The built-in renderer is now serving the public site.":["El renderizador integrado ya presta servicio al sitio público."],"The built-in renderer is serving the public site.":["El renderizador integrado presta servicio al sitio público."],"The content type this field points at is not named in a shape Gophenberg accepts. Give it a key that starts with a lowercase letter and then holds only lowercase letters, numbers and hyphens.":["El tipo de contenido al que apunta este campo no está nombrado con un formato que Gophenberg acepte. Dale una clave que empiece por una letra minúscula y contenga solo letras minúsculas, números y guiones."],"The content types could not be loaded, so where these groups appear and which fields they shadow are not shown.":["No se han podido cargar los tipos de contenido, así que no se muestra dónde aparecen estos grupos ni qué campos eclipsan."],"The content types could not be loaded.":["No se han podido cargar los tipos de contenido."],"The content types could not be refreshed, so where these groups appear and what they shadow may be out of date.":["No se han podido actualizar los tipos de contenido, así que dónde aparecen estos grupos y qué eclipsan puede estar desactualizado."],"The draft could not be created.":["No se ha podido crear el borrador."],"The entry %(entry)s in this zip would be written outside the theme folder, so nothing was installed. Package the theme again.":["La entrada %(entry)s de este zip se escribiría fuera de la carpeta del tema, así que no se ha instalado nada. Vuelve a empaquetar el tema."],"The field %(field)s cannot go, because %(by)s reads it. Change %(by)s first.":["El campo %(field)s no se puede quitar, porque %(by)s lo lee. Cambia antes %(by)s."],"The field %(field)s cannot hold the value it was given. Check what kind of field it is and enter a value that matches.":["El campo %(field)s no puede guardar el valor que se le ha dado. Comprueba de qué tipo de campo se trata e introduce un valor que encaje."],"The field %(field)s has to hold a value before this item can be published. Fill it in, or leave the item as a draft.":["El campo %(field)s tiene que tener un valor antes de poder publicar este elemento. Rellénalo, o deja el elemento como borrador."],"The field %(field)s in %(group)s still points at this content type. Delete that field first, then delete this type.":["El campo %(field)s de %(group)s todavía apunta a este tipo de contenido. Borra antes ese campo y luego borra este tipo."],"The field %(field)s is hidden by its own rules right now, so it cannot hold a value. Show it again before filling it in.":["El campo %(field)s está oculto por sus propias reglas ahora mismo, así que no puede guardar ningún valor. Vuelve a mostrarlo antes de rellenarlo."],"The field %(field)s points at one item only. Remove the extra choices and keep one.":["El campo %(field)s apunta a un solo elemento. Quita las opciones de más y deja una."],"The field %(field)s points at other items, so it does not take a plain value. Pick the items it points at instead.":["El campo %(field)s apunta a otros elementos, así que no admite un valor suelto. Elige en su lugar los elementos a los que apunta."],"The field %(field)s takes a list of items, and what arrived was not a list. Reload the page and pick the items again.":["El campo %(field)s admite una lista de elementos, y lo que ha llegado no era una lista. Recarga la página y vuelve a elegir los elementos."],"The field %(source)s cannot hold the value %(value)s, so no rule can compare it. Write a value of the kind %(source)s stores.":["El campo %(source)s no puede guardar el valor %(value)s, así que ninguna regla puede compararlo. Escribe un valor de la clase que %(source)s guarda."],"The field groups could not be loaded.":["No se han podido cargar los grupos de campos."],"The field groups could not be reached.":["No se ha podido contactar con los grupos de campos."],"The field keeps its values on the content both groups reach.":["El campo conserva sus valores en el contenido al que llegan ambos grupos."],"The fields this group holds go with it, and so do the values every item stored in them.":["Los campos que contiene este grupo se van con él, y también los valores que cada elemento guardó en ellos."],"The groups were reordered.":["Los grupos se han reordenado."],"The item could not be duplicated.":["No se ha podido duplicar el elemento."],"The item could not be moved to the trash.":["No se ha podido mover el elemento a la papelera."],"The item could not be permanently deleted.":["No se ha podido borrar permanentemente el elemento."],"The item could not be restored.":["No se ha podido restaurar el elemento."],"The item you picked as parent holds another kind of content. Pick a parent of the same content type as this item.":["El elemento que has elegido como superior tiene otro tipo de contenido. Elige un elemento superior del mismo tipo de contenido que este elemento."],"The item you picked as parent is in the trash. Restore it, or pick another parent.":["El elemento que has elegido como superior está en la papelera. Restáuralo, o elige otro elemento superior."],"The item you picked as parent no longer exists. Reload the page and pick another parent.":["El elemento que has elegido como superior ya no existe. Recarga la página y elige otro."],"The media library could not be loaded.":["No se ha podido cargar la biblioteca de medios."],"The name changes. Nothing stored under this field moves.":["El nombre cambia. Nada de lo guardado en este campo se mueve."],"The name could not be updated.":["No se ha podido actualizar el nombre."],"The new order has to name every field group exactly once. Reload the page and move the groups again.":["El nuevo orden tiene que nombrar cada grupo de campos exactamente una vez. Recarga la página y mueve los grupos otra vez."],"The new order has to name every field of this content type exactly once. Reload the page and move the fields again.":["El nuevo orden tiene que nombrar cada campo de este tipo de contenido exactamente una vez. Recarga la página y mueve los campos de nuevo."],"The number of revisions to keep has to be a whole number, and it cannot be negative. Enter a different number.":["El número de revisiones que se conservan tiene que ser un número entero, y no puede ser negativo. Introduce otro número."],"The registry could not be reached.":["No se ha podido acceder al registro."],"The role could not be changed.":["No se ha podido cambiar el rol."],"The rule on %(source)s names nothing to match. Pick a value, or remove the rule.":["La regla sobre %(source)s no nombra nada con lo que coincidir. Elige un valor, o quita la regla."],"The rules could not be loaded.":["No se han podido cargar las reglas."],"The rules on %(field)s lead back to %(field)s itself, so nothing can decide whether to show it. Point one of them at another field.":["Las reglas de %(field)s vuelven al propio %(field)s, así que nada puede decidir si mostrarlo. Apunta una de ellas a otro campo."],"The same item was picked twice for %(field)s. Pick each item once.":["El mismo elemento se ha elegido dos veces para %(field)s. Elige cada elemento una sola vez."],"The server could not be reached, so nothing was changed.":["No se ha podido acceder al servidor, así que no se ha cambiado nada."],"The server could not be reached, so nothing was saved.":["No se ha podido acceder al servidor, así que no se ha guardado nada."],"The server could not be reached, so nothing was uploaded.":["No se ha podido acceder al servidor, así que no se ha subido nada."],"The setting %(setting)s cannot hold the value it was given. Check what this setting takes and try again.":["El ajuste %(setting)s no puede contener el valor que se le dio. Comprueba qué acepta este ajuste y prueba de nuevo."],"The setting %(setting)s falls outside the others. Keep min below max and the default inside the bounds.":["El ajuste %(setting)s queda fuera de los demás. Mantén min por debajo de max y el valor por defecto dentro de los límites."],"The settings could not be read, so nothing can be changed here yet.":["No se han podido leer los ajustes, así que todavía no se puede cambiar nada aquí."],"The site default":["El idioma por defecto del sitio"],"The site may already hold part of this file. Import it again to see what is left.":["Puede que el sitio ya tenga parte de este archivo. Impórtalo de nuevo para ver lo que queda."],"The source %(source)s does not offer %(operator)s. Pick one of the comparisons it does offer.":["La fuente %(source)s no ofrece %(operator)s. Elige una de las comparaciones que sí ofrece."],"The theme %(name)s carries no %(file)s, so Gophenberg cannot tell what it is. Put that file at the top level of the zip and package the theme again.":["El tema %(name)s no lleva ningún %(file)s, así que Gophenberg no puede saber qué es. Pon ese archivo en el primer nivel del zip y vuelve a empaquetar el tema."],"The theme %(name)s could not be read, so it cannot serve your site. Upload it again, or choose another theme.":["El tema %(name)s no se ha podido leer, así que no puede servir tu sitio. Vuelve a subirlo, o elige otro tema."],"The theme %(name)s did not start, so your site is still served by the theme it had. Ask whoever looks after your site to check the server log for what the theme reported.":["El tema %(name)s no ha arrancado, así que tu sitio lo sigue sirviendo el tema que tenía. Pide a quien gestiona tu sitio que mire en el registro del servidor para saber qué problema ha informado el tema."],"The theme %(name)s does not carry %(path)s as a file, so there is nothing to run. Package the built theme rather than its source.":["El tema %(name)s no lleva %(path)s como archivo, así que no hay nada que ejecutar. Empaqueta el tema ya construido, no su código fuente."],"The theme %(name)s does not carry %(path)s as a folder, so its styles and scripts are missing. Package the built theme rather than its source.":["El tema %(name)s no lleva %(path)s como carpeta, así que le faltan los estilos y los scripts. Empaqueta el tema ya construido, no su código fuente."],"The theme %(name)s holds a link to another file at %(path)s, and a theme may only carry real files. Replace it and package the theme again.":["El tema %(name)s lleva un enlace a otro archivo en %(path)s, y un tema solo puede llevar archivos de verdad. Sustitúyelo y vuelve a empaquetar el tema."],"The theme %(name)s is serving your site right now, so it cannot be replaced. Deactivate it first, or install this copy under another name.":["El tema %(name)s sirve tu sitio ahora mismo, así que no se puede sustituir. Desactívalo primero, o instala esta copia con otro nombre."],"The theme %(name)s is the one chosen, but it is not installed, so your site is served by the built-in renderer. Upload the theme again, or choose another one.":["El tema %(name)s es el elegido, pero no está instalado, así que el renderizador integrado está prestando servicio a tu sitio. Vuelve a subir el tema, o elige otro."],"The theme %(name)s was built on theme kit %(declared)s, and this site serves %(served)s. Build the theme again against a kit this site serves, then install it.":["El tema %(name)s se compiló con el kit de temas %(declared)s y este sitio sirve %(served)s. Compila el tema de nuevo con un kit que este sitio sirva y después instálalo."],"The trash could not be emptied.":["No se ha podido vaciar la papelera."],"The user could not be created.":["No se ha podido crear el usuario."],"The values stored under it do not follow.":["Los valores guardados debajo no le siguen."],"Theme":["Tema"],"Themes":["Temas"],"Themes could not be loaded.":["No se han podido cargar los temas."],"There is no content type called %(value)s. Pick a type your site holds, or register it first.":["No existe ningún tipo de contenido llamado %(value)s. Elige un tipo que tenga tu sitio, o regístralo primero."],"There is no content type called %(value)s. Pick one of the types your site holds and try again.":["No existe ningún tipo de contenido llamado %(value)s. Elige uno de los tipos que tiene tu sitio e inténtalo de nuevo."],"There is no kind of field called %(value)s. Pick one of these instead: %(allowed)s.":["No existe ningún tipo de campo llamado %(value)s. Elige uno de estos: %(allowed)s."],"There is no page kind called %(value)s. Pick one of these instead: %(allowed)s.":["No existe ningún tipo de página llamado %(value)s. Elige uno de estos: %(allowed)s."],"There is no status called %(value)s. Pick one of these instead: %(allowed)s.":["No existe ningún estado llamado %(value)s. Elige uno de estos: %(allowed)s."],"There is nothing at this address. Check the link and try again.":["No hay nada en esta dirección. Comprueba el enlace e inténtalo de nuevo."],"There is nothing to roll back to, because your site has not been through a theme change yet. Install a theme first, then a rollback has somewhere to go.":["No hay nada a lo que retornar, porque tu sitio todavía no ha cambiado de tema. Instala un tema primero y así el retorno tendrá adónde ir."],"These files could not be read.":["No se han podido leer estos archivos."],"These were left alone, because nobody confirmed losing them.":["Estos se han dejado como estaban, porque nadie confirmó perderlos."],"This content type does not exist any more. Reload the page to see the types your site holds now.":["Este tipo de contenido ya no existe. Recarga la página para ver los tipos que tiene ahora tu sitio."],"This content type does not nest, so one of its items cannot sit inside another. Mark the type as Nests first.":["Este tipo de contenido no anida, así que uno de sus elementos no puede estar dentro de otro. Marca el tipo como Anida primero."],"This content type has no field called %(field)s. Check the name, or declare the field on the type first.":["Este tipo de contenido no tiene ningún campo llamado %(field)s. Comprueba el nombre, o declara antes el campo en el tipo."],"This content type is turned off, so its content is not served or edited. Activate it first.":["Este tipo de contenido está desactivado, así que su contenido ni se sirve ni se edita. Actívalo primero."],"This content type still holds content, so it cannot be deleted. Move or delete its items first.":["Este tipo de contenido todavía tiene contenido, así que no se puede borrar. Mueve o borra antes sus elementos."],"This definitions file is larger than the %(max)s bytes Gophenberg reads in one request. Split it, or raise the limit your site runs with.":["Este archivo de definiciones es mayor que los %(max)s bytes que Gophenberg lee en una petición. Divídelo, o sube el límite con el que funciona tu sitio."],"This field holds no layouts yet.":["Este campo todavía no tiene diseños."],"This field would stand inside too many containers. Put it nearer the top and try again.":["Este campo quedaría dentro de demasiados contenedores. Ponlo más cerca del nivel superior e inténtalo de nuevo."],"This file could not be opened as a zip. Package the theme again and upload the new file.":["Este archivo no se ha podido abrir como zip. Vuelve a empaquetar el tema y sube el archivo nuevo."],"This file is larger than the upload limit. Upload a smaller file.":["Este archivo es más grande que el límite de subida. Sube un archivo más pequeño."],"This file is named %(extension)s but it holds %(detected)s content. Upload it under a name that matches what is inside it.":["Este archivo se llama %(extension)s pero lleva contenido %(detected)s. Súbelo con un nombre que coincida con lo que lleva dentro."],"This file matches the site, so there is nothing to change.":["Este archivo coincide con el sitio, así que no hay nada que cambiar."],"This file says it was written in format %(declared)s, which is not a version Gophenberg can read. Export the definitions again from the site they came from.":["Este archivo dice estar escrito en el formato %(declared)s, que no es una versión que Gophenberg pueda leer. Vuelve a exportar las definiciones desde el sitio del que vinieron."],"This file was written in format %(declared)s, and this release reads %(served)s. Upgrade the site the file came from, or this one.":["Este archivo está escrito en el formato %(declared)s, y esta versión lee %(served)s. Actualiza el sitio del que viene el archivo, o este."],"This group holds no fields yet.":["Este grupo todavía no tiene campos."],"This install of Gophenberg has no install root, so it updates by hand.":["Esta instalación de Gophenberg no tiene raíz de instalación, así que se actualiza a mano."],"This is a custom build of Gophenberg, so it updates by hand.":["Esta es una compilación propia de Gophenberg, así que se actualiza a mano."],"This item cannot go straight to that status from the one it holds now. Save it as a draft first, then try again.":["Este elemento no puede pasar directamente a ese estado desde el que tiene ahora. Guárdalo antes como borrador e inténtalo de nuevo."],"This item does not exist, and it may have been deleted. Go back to the list to see what is there.":["Este elemento no existe, y puede que se haya borrado. Vuelve a la lista para ver qué hay."],"This item is already in the trash. Restore it first to work on it again.":["Este elemento ya está en la papelera. Restáuralo primero para volver a trabajar en él."],"This item is in the trash. Restore it first to work on it again.":["Este elemento está en la papelera. Restáuralo primero para volver a trabajar en él."],"This item is not in the trash, so there is nothing to restore. Open it from the list to work on it as it is.":["Este elemento no está en la papelera, así que no hay nada que restaurar. Ábrelo desde la lista para trabajar en él tal como está."],"This item still holds items nested inside it. Move or delete those first.":["Este elemento todavía tiene elementos anidados dentro. Mueve o borra antes esos."],"This kind of field holds no fields inside it. Put the field in a section or a repeater instead.":["Este tipo de campo no contiene campos dentro. Pon el campo en una sección o en un repetidor."],"This media item is not in the library, and someone may have deleted it. Reload the page to see what is there now.":["Este medio no está en la biblioteca, y puede que alguien lo haya borrado. Recarga la página para ver qué hay ahora."],"This picture could not be read, so nothing was stored. The file may be damaged, so open it on your computer and upload it again.":["Esta imagen no se ha podido leer, así que no se ha guardado nada. Puede que el archivo esté dañado, así que ábrelo en tu ordenador y vuelve a subirlo."],"This picture is %(width)s by %(height)s pixels, over the limit of %(max)s pixels in all. Make it smaller and upload it again.":["Esta imagen tiene %(width)s por %(height)s píxeles, por encima del límite de %(max)s píxeles en total. Hazla más pequeña y vuelve a subirla."],"This post changed elsewhere. Reload before saving again.":["Esta entrada ha cambiado en otro sitio. Recarga antes de volver a guardar."],"This request came from a page on another site, so it was refused. Open the admin on this site and try again.":["Esta petición vino de una página de otro sitio, así que se rechazó. Abre la administración en este sitio e inténtalo de nuevo."],"This request carried %(attribute)s, which fields do not take. Reload the page so the admin and the server agree again.":["Esta petición llevaba %(attribute)s, que los campos no aceptan. Recarga la página para que la administración y el servidor vuelvan a coincidir."],"This request left out %(field)s, which Gophenberg needs. Reload the page and try again.":["En esta petición faltaba %(field)s, que Gophenberg necesita. Recarga la página e inténtalo de nuevo."],"This rule reads a source called %(source)s, and nothing on your site declares one. A plugin that added it may have been removed.":["Esta regla lee una fuente llamada %(source)s, y nada en tu sitio declara ninguna. Puede que se haya quitado un plugin que la añadía."],"This site cannot write to its themes folder, so no theme can be installed. Ask whoever looks after your site to make the folder that %(setting)s points at writable. A read-only mount is the usual cause.":["Este sitio no puede escribir en su carpeta de temas, así que no se puede instalar ninguno. Pide a quien gestione tu sitio que haga escribible la carpeta a la que apunta %(setting)s. La causa habitual es un montaje de solo lectura."],"This site has nowhere to keep themes, so no theme can be installed. Ask whoever looks after your site to point %(setting)s at a folder the server can write to.":["Este sitio no tiene dónde guardar los temas, así que no se puede instalar ninguno. Pide a quien gestione tu sitio que apunte %(setting)s a una carpeta en la que el servidor pueda escribir."],"This site has nowhere to store uploads, so nothing can be uploaded. Ask whoever looks after your site to point %(setting)s at a folder the server can write to.":["Este sitio no tiene dónde guardar las subidas, así que no se puede subir nada. Pide a quien gestione tu sitio que apunte %(setting)s a una carpeta en la que el servidor pueda escribir."],"This theme is over the limit of %(max)s bytes, packed or unpacked. Leave out what the theme does not need and package it again.":["Este tema pasa del límite de %(max)s bytes, comprimido o sin comprimir. Saca lo que el tema no necesite y vuelve a empaquetarlo."],"This type will answer under /%(word)s.":["Este tipo responderá como /%(word)s."],"This zip holds %(entries)s files, more than the %(max)s a theme may carry. Package only the built theme.":["Este zip lleva %(entries)s archivos, más de los %(max)s que puede llevar un tema. Empaqueta solo el tema ya construido."],"Through":["A través de"],"Thumbnail":["Miniatura"],"Title":["Título"],"Two field groups in this file share the key %(key)s. Give one of them a different key and import again.":["Dos grupos de campos de este archivo comparten la clave %(key)s. Dale una clave distinta a uno de ellos e importa de nuevo."],"Two rule sources are registered under the name %(param)s. A plugin is declaring a source your site already holds.":["Hay dos fuentes de reglas registradas con el nombre %(param)s. Un plugin declara una fuente que tu sitio ya tiene."],"Type":["Tipo"],"Type a whole number in both boxes before saving.":["Escribe un número entero en las dos casillas antes de guardar."],"Undo":["Deshacer"],"Unsaved changes":["Cambios sin guardar"],"Update":["Actualizar"],"Update failed.":["No se ha podido actualizar."],"Upload theme":["Subir tema"],"Uploaded %s file.":["%s archivo subido.","%s de archivos subidos.","%s archivos subidos."],"Users":["Usuarios"],"Users could not be loaded.":["No se han podido cargar los usuarios."],"Value":["Valor"],"Version":["Versión"],"Videos":["Vídeos"],"Visit Site":["Visitar el sitio"],"Web address":["Dirección web"],"What each Linked from field reads":["Qué lee cada campo Enlazado desde"],"What it points at changed, so its stored values go with it.":["Aquello a lo que apunta ha cambiado, así que sus valores guardados se van con él."],"Where %(group)s appears":["Dónde aparece %(group)s"],"Without a rule this field always shows.":["Sin ninguna regla este campo siempre se muestra."],"Without a rule this group appears nowhere.":["Sin una regla este grupo no aparece en ningún sitio."],"Yes":["Sí"],"Yes or no":["Sí o no"],"You cannot change your own role.":["No puedes cambiar tu propio rol."],"Your language":["Tu idioma"],"Your role does not allow %(capability)s.":["Tu rol no permite %(capability)s."],"Your server pins the site to the theme %(name)s, so themes cannot be changed here. Ask whoever looks after your site to remove the pin.":["Tu servidor bloque el sitio al tema %(name)s, así que los temas no se pueden cambiar desde aquí. Pide a quien gestiona tu sitio que quite ese bloqueo."],"Your site always needs one default content type, so this one cannot be turned off or deleted. Make another type the default first.":["Tu sitio siempre necesita un tipo de contenido por defecto, así que este no se puede desactivar ni borrar. Haz antes que otro tipo sea el que está por defecto."],"a content type":["un tipo de contenido"],"account\u0004Role":["Rol"],"account\u0004Status":["Estado"],"action label\u0004Duplicate":["Duplicar"],"action label\u0004Duplicate…":["Duplicar…"],"address":["dirección"],"admin section\u0004Content Types":["Tipos de contenido"],"admin section\u0004Field Groups":["Grupos de campos"],"admin section\u0004Language":["Idioma"],"admin section\u0004Media":["Medios"],"admin section\u0004Settings":["Ajustes"],"admin section\u0004Themes":["Temas"],"column\u0004Date":["Fecha"],"content type\u0004\"%s\" permanently deleted.":["Se ha borrado permanentemente el tipo de contenido «%s»."],"content type\u0004\"%s\" successfully created.":["Se ha creado correctamente el tipo de contenido «%s»."],"content type\u0004Status":["Estado"],"field\u0004Name":["Nombre"],"field group\u0004Status":["Estado"],"field type\u0004Choice":["Elección"],"field type\u0004Color":["Color"],"field type\u0004Date":["Fecha"],"field type\u0004Flexible content":["Contenido flexible"],"field type\u0004Gallery":["Galería"],"field type\u0004Kind":["Tipo"],"field type\u0004Layout":["Diseño"],"field type\u0004Link":["Enlace"],"field type\u0004Media":["Medio"],"field type\u0004Range":["Rango"],"field type\u0004Repeater":["Repetidor"],"field type\u0004Section":["Sección"],"field type\u0004Select":["Desplegable"],"file size\u0004%1$s %2$s":["%1$s %2$s"],"file type group\u0004Archives":["Archivos"],"file type group\u0004Audio":["Audio"],"file type group\u0004Video":["Vídeo"],"holds":["contiene"],"holds anything":["contiene algo"],"https://www.w3.org/WAI/tutorials/images/decision-tree/":["https://www.w3.org/WAI/tutorials/images/decision-tree/"],"image dimensions\u0004%1$s × %2$s":["%1$s × %2$s"],"is":["es"],"is above":["es mayor que"],"is below":["es menor que"],"is empty":["está vacío"],"is not":["no es"],"panel button label\u0004Settings":["Ajustes"],"person\u0004Name":["Nombre"],"post\u0004%s (Copy)":["%s (copia)"],"post\u0004Status":["Estado"],"post status\u0004Draft":["Borrador"],"post status\u0004Published":["Publicada"],"post status\u0004Trash":["Papelera"],"post type general name\u0004Pages":["Páginas"],"post type general name\u0004Posts":["Entradas"],"post type singular name\u0004Page":["Página"],"post type singular name\u0004Post":["Entrada"],"relation target\u0004None":["Ninguno"],"role\u0004Administrator":["Administrador"],"role\u0004Author":["Autor"],"role\u0004Editor":["Editor"],"role\u0004Member":["Miembro"],"role\u0004No role":["Sin rol"],"status filter\u0004All":["Todo"],"taxonomy general name\u0004Categories":["Categorías"],"taxonomy singular name\u0004Category":["Categoría"],"theme\u0004Status":["Estado"],"trash\u0004Restore":["Restaurar"],"unit symbol\u0004B":["B"],"unit symbol\u0004EB":["EB"],"unit symbol\u0004GB":["GB"],"unit symbol\u0004KB":["KB"],"unit symbol\u0004MB":["MB"],"unit symbol\u0004PB":["PB"],"unit symbol\u0004TB":["TB"],"unit symbol\u0004YB":["YB"],"unit symbol\u0004ZB":["ZB"],"v%(version)s":["v%(version)s"],"verb\u0004Trash…":["Papelera…"],"verb\u0004View":["Ver"],"{day} {month} {year}":["{day} de {month} de {year}"]} +{"":{"lang":"es","plural-forms":"nplurals=3; plural=((n == 1) ? 0 : ((n != 0 && n % 1000000 == 0) ? 1 : 2));"}," and ":[" y "]," or ":[" o "],"\"%s\" activated.":["Se ha activado «%s»."],"\"%s\" deactivated.":["Se ha desactivado «%s»."],"\"%s\" has been restored.":["«%s» se ha restaurado."],"\"%s\" moved to the trash.":["«%s» trasladado a la papelera."],"\"%s\" permanently deleted.":["«%s» borrado permanentemente."],"\"%s\" successfully created.":["«%s» creado correctamente."],"\"%s\" uploaded.":["«%s» subido."],"%(field)s address":["Dirección de %(field)s"],"%(field)s cannot move inside itself. Pick a container that is not one of its own.":["%(field)s no puede moverse dentro de sí mismo. Elige un contenedor que no sea uno de los suyos."],"%(field)s declared.":["%(field)s declarado."],"%(field)s deleted.":["%(field)s borrado."],"%(field)s does not match the format its field asks for. Check it and save again.":["%(field)s no tiene el formato que su campo requiere. Revísalo y guarda de nuevo."],"%(field)s goes no higher than %(limit)s. Lower the value and save again.":["%(field)s no pasa de %(limit)s. Baja el valor y guarda de nuevo."],"%(field)s goes no lower than %(limit)s. Raise the value and save again.":["%(field)s no baja de %(limit)s. Sube el valor y guarda de nuevo."],"%(field)s holds no value of its own, so it cannot be required. Make it optional.":["%(field)s no guarda ningún valor propio, así que no puede ser obligatorio. Hazlo opcional."],"%(field)s is optional again.":["%(field)s vuelve a ser opcional."],"%(field)s is required now.":["%(field)s ahora es obligatorio."],"%(field)s moved.":["%(field)s movido."],"%(field)s names the same one twice. Remove the repeat and save again.":["%(field)s nombra el mismo dos veces. Quita la repetición y guarda de nuevo."],"%(field)s needs at least %(limit)s files. Add one and save again.":["%(field)s necesita al menos %(limit)s archivos. Añade uno y guarda de nuevo."],"%(field)s needs at least %(limit)s rows. Add one and save again.":["%(field)s necesita al menos %(limit)s filas. Añade una y guarda de nuevo."],"%(field)s only takes one of its listed choices. Pick one and save again.":["%(field)s solo admite una de las opciones de su lista. Elige una y guarda de nuevo."],"%(field)s reads a relation field that is not there. Pick a group and a relation field it holds.":["%(field)s lee un campo de relación que no existe. Elige un grupo y un campo de relación que contenga."],"%(field)s reads a relation pointing at %(type)s, so it would list nothing here. Pick a relation pointing at the items this group is shown on.":["%(field)s lee una relación que apunta a %(type)s, así que aquí no mostraría nada. Elige una relación que apunte a los elementos donde se muestra este grupo."],"%(field)s renamed.":["%(field)s renombrado."],"%(field)s settled.":["%(field)s ajustado."],"%(field)s shows by its rules now.":["%(field)s ahora se muestra según sus reglas."],"%(field)s stands in the list.":["%(field)s aparece en la lista."],"%(field)s stays out of the list.":["%(field)s se queda fuera de la lista."],"%(field)s takes at most %(limit)s files. Remove one and save again.":["%(field)s acepta como mucho %(limit)s archivos. Quita uno y guarda de nuevo."],"%(field)s takes at most %(limit)s letters. Shorten what you wrote and save again.":["%(field)s acepta como mucho %(limit)s letras. Acorta lo que has escrito y guarda de nuevo."],"%(field)s takes at most %(limit)s rows. Remove one and save again.":["%(field)s admite como mucho %(limit)s filas. Quita una y guarda de nuevo."],"%(field)s title":["Título de %(field)s"],"%(file)s is larger than one upload may be.":["%(file)s es más grande de lo que una subida permite."],"%(file)s is not a file this block accepts.":["%(file)s no es un archivo que este bloque acepte."],"%(file)s: %(reason)s":["%(file)s: %(reason)s"],"%(group)s created.":["%(group)s creado."],"%(group)s now appears where you said.":["%(group)s ya aparece donde has dicho."],"%(group)s removed.":["%(group)s eliminado."],"%(group)s updated.":["%(group)s actualizado."],"%(key)s is served by %(winner)s, so %(loser)s does not show it on %(where)s.":["%(key)s lo sirve %(winner)s, así que %(loser)s no lo muestra en %(where)s."],"%(name)s %(version)s is serving the public site.":["%(name)s %(version)s está publicado en la web."],"%(name)s belongs to the site now.":["%(name)s ya pertenece al sitio."],"%(name)s came from the %(plugin)s plugin, which no longer declares it.":["%(name)s vino del plugin %(plugin)s, que ya no lo declara."],"%(name)s cannot be used as a theme name. Name the zip file after the theme, with no dot at the start and no slashes in it.":["%(name)s no se puede usar como nombre de tema. Nombra el archivo zip como el tema, sin punto al principio y sin barras."],"%(name)s moves to /%(word)s. Every address of both types changes.":["El tipo %(name)s pasa a /%(word)s. Cambian todas las direcciones de ambos tipos."],"%(name)s would move to /%(word)s, which Gophenberg keeps for itself. Change its plural name and try again.":["El tipo %(name)s pasaría a /%(word)s, que Gophenberg reserva para sí mismo. Cambia su nombre en plural e inténtalo de nuevo."],"%(source)s is %(value)s":["%(source)s es %(value)s"],"%(theme)s failed to start, so the built-in renderer is serving.":["%(theme)s no pudo arrancar, así que el renderizador ha tomado el relevo."],"%(theme)s is now serving the public site.":["%(theme)s ya sirve el sitio público."],"%(theme)s is serving the public site.":["%(theme)s sirve el sitio público."],"%(theme)s is still starting, so the built-in renderer is serving.":["%(theme)s todavía está arrancando, así que el renderizador ha tomado el relevo."],"%(theme)s was installed.":["%(theme)s se ha instalado."],"%(theme)s will not load, so the built-in renderer is serving.":["%(theme)s no se carga, así que el renderizador ha tomado el relevo."],"%(type)s answers on a new address, and stored links move with it.":["%(type)s responde en una dirección nueva, y los enlaces guardados se mueven con ella."],"%(type)s becomes the type the site opens on, and the old one takes an address.":["%(type)s pasa a ser el tipo con el que abre el sitio, y el anterior toma una dirección."],"%(type)s keeps nesting while %(items)s of its items sit inside another. Move those to the top level first, the ones in the trash included.":["%(type)s sigue anidando mientras %(items)s de sus elementos están dentro de otro. Muévelos primero al nivel superior, incluidos los de la papelera."],"%(type)s keeps nesting, because some of its items sit inside another.":["%(type)s sigue anidando, porque algunos de sus elementos están dentro de otro."],"%(type)s will answer at the root.":["El tipo %(type)s responderá en la raíz."],"%s content type activated.":["Se ha activado %s tipo de contenido.","Se han activado %s de tipos de contenido.","Se han activado %s tipos de contenido."],"%s content type could not be activated.":["No se ha podido activar %s tipo de contenido.","No se han podido activar %s de tipos de contenido.","No se han podido activar %s tipos de contenido."],"%s content type could not be deactivated.":["No se ha podido desactivar %s tipo de contenido.","No se han podido desactivar %s de tipos de contenido.","No se han podido desactivar %s tipos de contenido."],"%s content type could not be permanently deleted.":["No se ha podido borrar permanentemente %s tipo de contenido.","No se han podido borrar permanentemente %s de tipos de contenido.","No se han podido borrar permanentemente %s tipos de contenido."],"%s content type deactivated.":["Se ha desactivado %s tipo de contenido.","Se han desactivado %s de tipos de contenido.","Se han desactivado %s tipos de contenido."],"%s content type permanently deleted.":["Se ha borrado permanentemente %s tipo de contenido.","Se han borrado permanentemente %s de tipos de contenido.","Se han borrado permanentemente %s tipos de contenido."],"%s day":["%s día","%s de días","%s días"],"%s hour":["%s hora","%s de horas","%s horas"],"%s item could not be moved to the trash.":["No se ha podido mover %s elemento a la papelera.","No se han podido mover %s de elementos a la papelera.","No se han podido mover %s elementos a la papelera."],"%s item could not be permanently deleted.":["No se ha podido borrar permanentemente %s elemento.","No se han podido borrar permanentemente %s de elementos.","No se han podido borrar permanentemente %s elementos."],"%s item could not be restored.":["No se ha podido restaurar %s elemento.","No se han podido restaurar %s de elementos.","No se han podido restaurar %s elementos."],"%s item moved to the trash.":["%s elemento movido a la papelera.","%s de elementos movidos a la papelera.","%s elementos movidos a la papelera."],"%s item permanently deleted.":["%s elemento borrado permanentemente.","%s de elementos borrados permanentemente.","%s elementos borrados permanentemente."],"%s item stays in the trash.":["%s elemento sigue en la papelera.","%s de elementos siguen en la papelera.","%s elementos siguen en la papelera."],"%s minute":["%s minuto","%s de minutos","%s minutos"],"%s page has been restored.":["Se ha restaurado %s página.","Se han restaurado %s de páginas.","Se han restaurado %s páginas."],"%s post has been restored.":["Se ha restaurado %s entrada.","Se han restaurado %s de entradas.","Se han restaurado %s entradas."],"%s update available":["%s actualización disponible","%s de actualizaciones disponibles","%s actualizaciones disponibles"],"(no title)":["(sin título)"],"Gophenberg %(version)s is available! Please update now.":["¡Ya está disponible Gophenberg %(version)s! Por favor, actualiza ahora."],"Important: Before updating, please back up your database and files. For help with updates, visit the Updating Gophenberg documentation page.":["Importante: Antes de actualizar, por favor, haz una copia de seguridad de tu base de datos y de los archivos. Para obtener ayuda con las actualizaciones, visita la página de documentación Actualización de Gophenberg."],"A %(kind)s field does not take a setting called %(setting)s. Remove it and try again.":["Un campo %(kind)s no acepta un ajuste llamado %(setting)s. Quítalo y prueba de nuevo."],"A Linked from field stands on its own, not inside a section or a repeater. Declare %(field)s beside the container.":["Un campo Enlazado desde va por su cuenta, no dentro de una sección ni de un repetidor. Declara %(field)s junto al contenedor."],"A backup of the database is taken first, and Gophenberg goes back to %(running)s on its own if the new version does not start.":["Primero se hace una copia de seguridad de la base de datos, y Gophenberg vuelve a %(running)s por su cuenta si la nueva versión no arranca."],"A backup of the database is taken first, and the site stays down until you restore it if the new version does not start.":["Primero se hace una copia de seguridad de la base de datos, y el sitio deja de funcionar hasta que la restaures si la nueva versión no arranca."],"A content type needs a singular and a plural name, like Guide and Guides. Fill both in and try again.":["Un tipo de contenido necesita un nombre en singular y otro en plural, como Guía y Guías. Rellena ambos e inténtalo de nuevo."],"A descriptive summary of the content type.":["Un resumen descriptivo del tipo de contenido."],"A field group key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Rename the group in the file so its key comes out in that shape.":["La clave de un grupo de campos tiene que empezar por una letra minúscula y después llevar solo letras minúsculas, números y guiones. Cambia el nombre del grupo en el archivo para que su clave salga con esa forma."],"A field key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Rename the field so its key comes out in that shape.":["La clave de un campo tiene que empezar por una letra minúscula y contener solo letras minúsculas, números y guiones. Renombra el campo para que su clave tenga esa forma."],"A field needs a name. Type one and try again.":["El campo necesita un nombre. Escribe uno e inténtalo de nuevo."],"A field with that name already exists on the items this group reaches. Pick another name.":["Ya existe un campo con ese nombre en los elementos que este grupo alcanza. Elige otro nombre."],"A flexible content field holds layouts, and %(field)s is not one. Add a layout first, then declare the field inside that layout.":["Un campo de contenido flexible contiene diseños, y %(field)s no lo es. Añade primero un diseño y después declara el campo dentro de ese diseño."],"A higher quality stores larger files, and it applies to pictures uploaded from now on.":["Una calidad más alta almacena archivos más grandes, y se aplica a las imágenes que subas a partir de ahora."],"A layout stands inside a flexible content field only. Put %(field)s inside one of those instead.":["Un diseño solo va dentro de un campo de contenido flexible. Pon %(field)s dentro de uno de ellos."],"A layout stands inside a flexible content field, never on its own. Declare a flexible content field first, then add %(field)s inside it.":["Un diseño va dentro de un campo de contenido flexible, nunca por su cuenta. Declara primero un campo de contenido flexible y después añade %(field)s dentro."],"A listing carries between 1 and %(max)s items, so %(value)s is not a size Gophenberg takes. Pick a number inside that range.":["Un listado muestra entre 1 y %(max)s elementos, así que %(value)s no es un tamaño que Gophenberg acepte. Elige un número dentro de ese rango."],"A relation field has to say which content type it points at. Pick that type and try again.":["Un campo de relación tiene que indicar a qué tipo de contenido apunta. Elige ese tipo e inténtalo de nuevo."],"A reload shows the admin in the language you chose.":["Al recargar verás el panel de administración en el idioma que has elegido."],"A route word has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Change it and try again.":["La palabra de ruta de la URL tiene que empezar por una letra minúscula y contener solo letras minúsculas, números y guiones. Cámbiala e inténtalo de nuevo."],"A row of %(field)s has to name the layout it takes. Pick a layout for the row, or remove the row.":["Una fila de %(field)s tiene que nombrar el diseño que toma. Elige un diseño para la fila, o quita la fila."],"A row of %(field)s takes one layout and no more. Reload the page and build the row again.":["Una fila de %(field)s toma un solo diseño. Recarga la página y crea la fila otra vez."],"A rule matching any %(source)s cannot be turned into an exclusion. Leave it as is, or name the ones to leave out instead.":["Una regla que vale para cualquier %(source)s no se puede convertir en exclusión. Déjala como está, o nombra los que quieras dejar fuera."],"A theme naming its own page size uses that instead.":["Un tema que indica su propio tamaño de página usa ese en su lugar."],"A type key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Change the key and try again.":["La clave de un tipo tiene que empezar por una letra minúscula y contener solo letras minúsculas, números y guiones. Cambia la clave e inténtalo de nuevo."],"Actions":["Acciones"],"Activate":["Activar"],"Activate %(theme)s":["Activar %(theme)s"],"Active":["Activo"],"Add":["Añadir"],"Add %(layout)s":["Añadir %(layout)s"],"Add %(name)s":["Añadir %(name)s"],"Add %(type)s":["Añadir %(type)s"],"Add Category":["Añadir categoría"],"Add Content Type":["Añadir tipo de contenido"],"Add Field Group":["Añadir grupo de campos"],"Add Media File":["Añadir medios"],"Add Page":["Añadir página"],"Add Post":["Añadir entrada"],"Add User":["Añadir usuario"],"Add block":["Añadir bloque"],"Add choice":["Añadir opción"],"Add condition":["Añadir condición"],"Add field":["Añadir campo"],"Add field to %(field)s":["Añadir campo a %(field)s"],"Add layout":["Añadir diseño"],"Add layout to %(field)s":["Añadir diseño a %(field)s"],"Add one with %(button)s.":["Añade un elemento con %(button)s."],"Add row":["Añadir fila"],"Add rule set":["Añadir conjunto de reglas"],"Add title":["Añadir título"],"Add to %(field)s":["Añadir a %(field)s"],"Address":["Dirección"],"Address updated.":["Dirección actualizada."],"Adopt":["Adoptar"],"Allow custom":["Permitir valores propios"],"Allow empty":["Permitir vacío"],"Alt text":["Texto alternativo"],"An item cannot point at itself. Pick a different item for %(field)s.":["Un elemento no puede apuntarse a sí mismo. Elige otro elemento para %(field)s."],"An item cannot sit inside itself, or inside one of the items nested under it. Pick a parent outside this branch.":["Un elemento no puede estar dentro de sí mismo, ni dentro de otro anidado bajo él. Elige un nivel superior fuera de esta rama."],"An updated version of Gophenberg is available.":["Hay disponible una versión actualizada de Gophenberg."],"Another account wrote this, and only its author, an editor or an administrator may change it. You can still read it.":["Otra cuenta escribió esto, y solo su autor, un editor o un administrador pueden cambiarlo. Todavía puedes leerlo."],"Another account wrote this, so you are reading it rather than editing it.":["Otra cuenta escribió esto, así que lo estás leyendo, no editando."],"Another content type already answers under this route word. Pick a different word.":["Ya hay otro tipo de contenido que responde con esta palabra de ruta de URL. Elige una palabra distinta."],"Another content type already lives at the root of your site, and only one can. Give this type a route word, or hand the root over with Make default.":["Ya hay otro tipo de contenido en la raíz de tu sitio, y solo puede haber uno. Dale a este tipo de contenido una palabra de ruta de URL, o cede la raíz con Establecer como predeterminado."],"Another content type already uses this key. Give this type a different name.":["Ya hay otro tipo de contenido que usa esta clave. Dale a este tipo un nombre distinto."],"Another item of this content type already uses that address. Pick a different slug and save again.":["Ya hay otro elemento de este tipo de contenido que usa esa dirección. Elige un slug distinto y guarda de nuevo."],"Another update is currently in progress.":["En este momento hay otra actualización en marcha."],"Appears on":["Aparece en"],"Apply":["Aplicar"],"April":["abril"],"Are you sure you want to move \"%s\" to the trash?":["¿Seguro que quieres mover «%s» a la papelera?"],"Audio":["Audio"],"August":["agosto"],"Author":["Autor"],"Back to %(type)s":["Volver a %(type)s"],"Back to the latest posts":["Volver a las últimas entradas"],"Backing up the database…":["Haciendo copia de seguridad de la base de datos…"],"Backups kept: %(kept)s of %(limit)s, taken on %(date)s at %(time)s.":["Copias de seguridad guardadas: %(kept)s de %(limit)s, hecha el %(date)s a las %(time)s.","Copias de seguridad guardadas: %(kept)s de %(limit)s, la más reciente del %(date)s a las %(time)s.","Copias de seguridad guardadas: %(kept)s de %(limit)s, la más reciente del %(date)s a las %(time)s."],"Block":["Bloque"],"Broken":["Roto"],"Bundles of fields, shown where their rules place them.":["Conjuntos de campos, mostrados donde sus reglas los colocan."],"Button group":["Grupo de botones"],"Cancel":["Cancelar"],"Caption":["Leyenda"],"Change %(name)s":["Cambiar %(name)s"],"Change address":["Cambiar la dirección"],"Change address…":["Cambiar la dirección…"],"Change role":["Cambiar el rol"],"Change the role of %(name)s":["Cambiar el rol de %(name)s"],"Check again.":["Comprobar de nuevo."],"Check now.":["Comprobar ahora."],"Checkbox group":["Grupo de casillas"],"Checking the new version…":["Comprobando la nueva versión…"],"Choices":["Opciones"],"Choose %(field)s":["Elegir %(field)s"],"Choose how the site serves its content.":["Elige cómo el sitio sirve su contenido."],"Choose the language the admin reads in.":["Elige el idioma en el que se lee el panel de administración."],"Choose the role of %(name)s.":["Elige el rol de %(name)s."],"Choose the version to update to.":["Elige la versión a la que actualizar."],"Clear %(field)s":["Vaciar %(field)s"],"Close":["Cerrar"],"Close Settings":["Cerrar ajustes"],"Closed":["Cerrado"],"Condition":["Condición"],"Content":["Contenido"],"Content Types":["Tipos de contenido"],"Content nests at most %(max)s levels deep, and this item would sit deeper. Pick a parent closer to the top.":["El contenido se anida como mucho %(max)s niveles, y este elemento quedaría más abajo. Elige un nivel superior más cercano al inicio."],"Content type":["Tipo de contenido"],"Content type updated.":["Tipo de contenido actualizado."],"Could not load that post.":["No se ha podido cargar esa entrada."],"Could not save image. %s":["No se ha podido guardar la imagen. %s"],"Could not save media. %s":["No se ha podido guardar el archivo multimedia. %s"],"Could not save that post.":["No se ha podido guardar esa entrada."],"Create":["Crear"],"Create a field group":["Crear un grupo de campos"],"Create user":["Crear usuario"],"Created":["Fecha de creación"],"Current version: %(version)s":["Versión actual: %(version)s"],"Date added":["Fecha de inclusión"],"Date modified":["Fecha de modificación"],"Deactivate":["Desactivar"],"Deactivate %(theme)s":["Desactivar %(theme)s"],"December":["diciembre"],"Default":["Por defecto"],"Default content type updated.":["Tipo de contenido predeterminado actualizado."],"Definitions file":["Archivo de definiciones"],"Delete":["Borrar"],"Delete \"%(title)s\" for good? This cannot be undone.":["¿Borrar permanentemente «%(title)s»? Esto no se puede deshacer."],"Delete %(field)s":["Borrar %(field)s"],"Delete %(group)s":["Eliminar %(group)s"],"Delete %s content type for good? This cannot be undone.":["¿Borrar permanentemente %s tipo de contenido? Esto no se puede deshacer.","¿Borrar permanentemente %s de tipos de contenido? Esto no se puede deshacer.","¿Borrar permanentemente %s tipos de contenido? Esto no se puede deshacer."],"Delete %s item for good? This cannot be undone.":["¿Borrar permanentemente %s elemento? Esto no se puede deshacer.","¿Borrar permanentemente %s de elementos? Esto no se puede deshacer.","¿Borrar permanentemente %s elementos? Esto no se puede deshacer."],"Delete permanently":["Borrar permanentemente"],"Delete the field":["Borrar el campo"],"Delete the group":["Eliminar el grupo"],"Delete…":["Borrar…"],"Describe":["Describir"],"Describe the purpose of the image.":["Describe el propósito de la imagen."],"Describe…":["Describir…"],"Description":["Descripción"],"Description updated.":["Descripción actualizada."],"Desktop":["Escritorio"],"Destination":["Destino"],"Dimensions":["Dimensiones"],"Disable":["Desactivar"],"Disable %(name)s":["Desactivar a %(name)s"],"Disabled":["Desactivado"],"Dismiss":["Descartar"],"Document":["Documento"],"Documents":["Documentos"],"Done. The site now holds what the file describes.":["Hecho. El sitio ya tiene lo que describe el archivo."],"Downloading Gophenberg %(version)s…":["Descargando Gophenberg %(version)s…"],"Draft saved.":["Borrador guardado."],"Drop files to upload":["Arrastra los archivos para subirlos"],"Edit media":["Editar los medios"],"Edit…":["Editar…"],"Email":["Correo electrónico"],"Empty Trash":["Vaciar papelera"],"Empty trash":["Vaciar papelera"],"Enable":["Activar"],"Enable %(name)s":["Activar a %(name)s"],"Every address of this type moves. Links kept elsewhere to the old addresses stop working.":["Cambian todas las direcciones de este tipo. Los enlaces guardados en otro sitio hacia las direcciones antiguas dejan de funcionar."],"Every content type":["Todos los tipos de contenido"],"Every field group needs a title. Give it a name and save again.":["Todo grupo de campos necesita un título. Ponle un nombre y guarda otra vez."],"Every item needs an author who exists. Pick one from the list and save again.":["Cada elemento necesita un autor que exista. Elige uno de la lista y guarda de nuevo."],"Every kind of content this site holds.":["Todos los tipos de contenido que hay en este sitio."],"Every value stored under this field goes with it, in every item the group reaches and in the revisions behind them.":["Todos los valores guardados en este campo se van con él, en cada elemento que el grupo alcanza y en las revisiones que hay detrás."],"Excerpt":["Extracto"],"Export definitions":["Exportar definiciones"],"February":["febrero"],"Fewest files":["Mínimo de archivos"],"Fewest rows":["Mínimo de filas"],"Field":["Campo"],"Field Groups":["Grupos de campos"],"Field group":["Grupo de campos"],"Fields":["Campos"],"Fields of %(group)s":["Campos de %(group)s"],"File name":["Nombre del archivo"],"File size":["Tamaño del archivo"],"File type":["Tipo de archivo"],"Filter by status":["Filtrar por estado"],"Follow the browser":["Sigue al navegador"],"Follow the steps on the Updating Gophenberg documentation page to update by hand.":["Sigue los pasos de la página de documentación Actualización de Gophenberg para actualizar a mano."],"From %(plugin)s":["De %(plugin)s"],"Full Size":["Tamaño completo"],"Gophenberg %(version)s failed its start check on this site. Fix what failed before you try it again.":["Gophenberg %(version)s no ha superado su comprobación de arranque en este sitio. Corrige lo que ha fallado antes de volver a intentarlo."],"Gophenberg Updates":["Actualizaciones de Gophenberg"],"Gophenberg cannot start this update: %(reason)s":["Gophenberg no puede empezar esta actualización: %(reason)s"],"Gophenberg checked for updates moments ago. Try again later.":["Gophenberg ha buscado actualizaciones hace un momento. Inténtalo de nuevo más tarde."],"Gophenberg could not read what your browser sent. Reload the page and try again, and tell whoever looks after your site if it keeps happening.":["Gophenberg no ha podido leer lo que ha enviado tu navegador. Recarga la página e inténtalo de nuevo, y avisa a quien gestiona tu sitio si sigue pasando."],"Gophenberg could not read which item you picked as parent. Reload the page and pick it again.":["Gophenberg no ha podido leer qué elemento has elegido como elemento superior. Recarga la página y vuelve a elegirlo."],"Gophenberg does not accept %(extension)s files. Upload a picture, a video, an audio file, a PDF or a zip instead.":["Gophenberg no acepta archivos %(extension)s. Sube una imagen, un vídeo, un audio, un PDF o un zip."],"Gophenberg does not answer in %(value)s. Pick one of the languages on the list.":["Gophenberg no responde en %(value)s. Elige uno de los idiomas de la lista."],"Gophenberg has no autosave of yours for this item. Open the item to see the version that is stored.":["Gophenberg no tiene ningún guardado automático tuyo de este elemento. Ábrelo para ver la versión guardada."],"Gophenberg has not checked for updates yet.":["Gophenberg todavía no ha buscado actualizaciones."],"Gophenberg has not come back yet.":["Gophenberg todavía no ha vuelto."],"Gophenberg holds no kind of definition called %(subject)s, so nothing was taken over. Reload the page so the admin and the server agree again.":["Gophenberg no tiene ninguna clase de definición llamada %(subject)s, así que no se ha adoptado nada. Recarga la página para que el admin y el servidor vuelvan a coincidir."],"Gophenberg keeps /%(path)s for itself or for another content type, so your content cannot answer there. Give the item a different slug.":["Gophenberg reserva la dirección /%(path)s para sí mismo o para otro tipo de contenido, así que tu contenido no puede usarla. Dale al elemento otro slug."],"Gophenberg keeps this word for itself, so no content type can answer under it. Pick a different route word.":["Gophenberg reserva esta palabra para sí mismo, así que ningún tipo de contenido puede usarla. Elige otra palabra de ruta de URL."],"Gophenberg stopped after the switch so that its service manager, such as systemd, starts the new version. Check that the service manager starts it again after exit code 75, and run update:status on the server to see where the update stands.":["Gophenberg se ha detenido tras el cambio para que su gestor de servicios, como systemd, arranque la nueva versión. Comprueba que el gestor de servicios lo vuelve a arrancar tras el código de salida 75, y ejecuta update:status en el servidor para ver en qué punto está la actualización."],"Gophenberg updated successfully.":["Gophenberg se ha actualizado correctamente."],"Gophenberg went back to %(from)s and is running normally.":["Gophenberg ha vuelto a %(from)s y funciona con normalidad."],"Group":["Grupo"],"Highest":["Máximo"],"Holds":["Contiene"],"Images":["Imágenes"],"Import definitions":["Importar definiciones"],"In list":["En la lista"],"Inactive":["Inactivo"],"Installed":["Instalado"],"Instructions":["Instrucciones"],"It moves here from another group and keeps its stored values.":["Se mueve aquí desde otro grupo y conserva sus valores guardados."],"It moves to another group and keeps its stored values.":["Se mueve a otro grupo y conserva sus valores guardados."],"It moves to another group, so its stored values do not follow.":["Se mueve a otro grupo, así que sus valores guardados no le siguen."],"It reads a relation inside a container, and only an import can point it elsewhere.":["Lee una relación dentro de un contenedor, y solo una importación puede apuntarlo a otro sitio."],"It starts on %(type)s, and the rules may be edited afterwards.":["Empieza en %(type)s, y las reglas se pueden editar después."],"Items could not be loaded.":["No se han podido cargar los elementos."],"Its items sit inside one another, so it keeps nesting.":["Sus elementos están unos dentro de otros, así que sigue anidando."],"Its kind changed, so its stored values go with it.":["Su tipo ha cambiado, así que sus valores guardados se van con él."],"January":["enero"],"July":["julio"],"June":["junio"],"Keep %(field)s out of the list":["Dejar %(field)s fuera de la lista"],"Keep it":["Conservarlo"],"Keep it here":["Dejarlo aquí"],"Key":["Clave"],"Label":["Etiqueta"],"Language":["Idioma"],"Large":["Grande"],"Last checked on %(date)s at %(time)s.":["Última comprobación el %(date)s a las %(time)s."],"Leave empty if decorative.":["Déjalo vacío si es decorativo."],"Let items nest":["Permitir anidar"],"Linked from":["Enlazado desde"],"List view":["Vista de lista"],"Loading field groups.":["Cargando los grupos de campos."],"Loading the post.":["Cargando la entrada."],"Loading the screen.":["Cargando la pantalla."],"Loading themes.":["Cargando los temas."],"Loading users.":["Cargando los usuarios."],"Loading…":["Cargando…"],"Longest":["Largo máximo"],"Lowest":["Mínimo"],"Make %(field)s optional":["Hacer %(field)s opcional"],"Make default":["Establecer como predeterminado"],"Make default…":["Establecer como predeterminado…"],"Make optional":["Hacer opcional"],"Manage the categories on this site.":["Gestiona las categorías de este sitio."],"Manage the images and files this site holds.":["Gestiona las imágenes y los archivos que hay en este sitio."],"Manage the items of this content type.":["Gestiona los elementos de este tipo de contenido."],"Manage the pages on this site.":["Gestiona las páginas de este sitio."],"Manage the posts on this site.":["Gestiona las entradas de este sitio."],"Many targets":["Varios destinos"],"Many values":["Varios valores"],"March":["marzo"],"May":["mayo"],"Media %(id)s":["Medio %(id)s"],"Media Library":["Biblioteca de medios"],"Media file updated.":["Archivo de medios actualizado."],"Medium":["Mediano"],"Mobile":["Móvil"],"Modified: %s":["Modificado: %s"],"Most files":["Máximo de archivos"],"Most rows":["Máximo de filas"],"Move":["Mover"],"Move \"%(title)s\" to the trash?":["¿Mover «%(title)s» a la papelera?"],"Move %(field)s down":["Bajar %(field)s"],"Move %(field)s elsewhere":["Mover %(field)s a otro sitio"],"Move %(field)s up":["Subir %(field)s"],"Move %(group)s down":["Bajar %(group)s"],"Move %(group)s up":["Subir %(group)s"],"Move %(name)s down":["Bajar %(name)s"],"Move %(name)s up":["Subir %(name)s"],"Move %s item to the trash?":["¿Mover %s elemento a la papelera?","¿Mover %s de elementos a la papelera?","¿Mover %s elementos a la papelera?"],"Move every address":["Mover todas las direcciones"],"Move row down":["Bajar la fila"],"Move row up":["Subir la fila"],"Move the field":["Mover el campo"],"Move to trash":["Mover a la papelera"],"Name":["Nombre"],"Name updated.":["Nombre actualizado."],"Nests":["Anida"],"Newer posts":["Entradas más recientes"],"No":["No"],"No content types found.":["No se han encontrado tipos de contenido."],"No description":["Sin descripción"],"No file arrived with this upload. Choose a file and try again.":["No ha llegado ningún archivo con esta subida. Elige un archivo e inténtalo de nuevo."],"No items found.":["No se han encontrado elementos."],"No items yet.":["Todavía no hay elementos."],"No media chosen":["Ningún medio elegido"],"No media has been uploaded yet.":["Todavía no se ha subido ningún medio."],"No media items found.":["No se han encontrado archivos de medios."],"No media items yet.":["Todavía no hay archivos de medios."],"No new updates found.":["No se han encontrado actualizaciones nuevas."],"No page lives at this address.":["No existe ninguna página en esta dirección."],"No parent":["Sin elemento superior"],"No theme arrived with this upload. Choose a zip file and try again.":["No ha llegado ningún tema con esta subida. Elige un archivo zip e inténtalo de nuevo."],"No themes are installed.":["No hay ningún tema instalado."],"No title":["Sin título"],"None":["Ninguno"],"Not %(type)s":["Excepto %(type)s"],"Not found":["No encontrado"],"Not serving":["No está sirviendo"],"Nothing declares that role.":["Nada declara ese rol."],"Nothing points here yet.":["Todavía no apunta nada aquí."],"Nothing published here yet.":["Todavía no hay nada publicado aquí."],"Nothing published yet.":["Todavía no hay nada publicado."],"November":["noviembre"],"Nowhere":["En ningún sitio"],"Number":["Número"],"October":["octubre"],"Older posts":["Entradas anteriores"],"One frame of this animation holds more than %(max)s pixels, which is more than Gophenberg opens. Upload a smaller animation.":["Un fotograma de esta animación tiene más de %(max)s píxeles, más de lo que Gophenberg abre. Sube una animación más pequeña."],"One of the filters on this list is not one Gophenberg understands. Clear the filters and try again.":["Uno de los filtros de esta lista no es un filtro que Gophenberg entienda. Quita los filtros e inténtalo de nuevo."],"One of the items picked for %(field)s is not the kind of content that field points at. Reload the page and pick from the list the field offers.":["Uno de los elementos elegidos para %(field)s no es del tipo de contenido al que apunta ese campo. Recarga la página y elige de la lista que ofrece el campo."],"One of the items picked for %(field)s was not named in a way Gophenberg understands. Reload the page and pick the items again.":["Uno de los elementos elegidos para %(field)s no venía nombrado de una forma que Gophenberg entienda. Recarga la página y vuelve a elegir los elementos."],"One of the items picked no longer exists. Reload the page and pick again.":["Uno de los elementos elegidos ya no existe. Recarga la página y vuelve a elegir."],"One target":["Un destino"],"Only a relation field points at another content type or holds many items. Pick the Relation kind, or leave the target and the many option empty.":["Solo un campo de relación apunta a otro tipo de contenido o guarda varios elementos. Elige el tipo Relación, o deja vacío el destino y la opción de varios."],"Only one file may be placed here.":["Aquí solo se puede colocar un archivo."],"Only the content type at the root of your site may go without a route word. Give this type one and try again.":["Solo el tipo de contenido que está en la raíz de tu sitio puede ir sin palabra de ruta de URL. Dale una a este tipo e inténtalo de nuevo."],"Open %(field)s in a new tab":["Abrir %(field)s en una pestaña nueva"],"Order stored.":["Orden guardado."],"Other":["Otro"],"Out of list":["Fuera de la lista"],"Parent":["Elemento superior"],"Password":["Contraseña"],"Pending":["Pendiente"],"Pending Review":["Pendiente de revisión"],"Permanently delete…":["Eliminar permanentemente…"],"Picture quality":["Calidad de imagen"],"Picture quality runs from 1 to %(max)s, so %(value)s is not a quality Gophenberg stores at. Pick a number inside that range.":["La calidad de imagen va de 1 a %(max)s, así que %(value)s no es una calidad con la que Gophenberg guarde. Elige un número dentro de ese rango."],"Placeholder":["Texto de ejemplo"],"Plural name":["Nombre en plural"],"Points at":["Apunta a"],"Post published.":["Entrada publicada."],"Posts per page":["Entradas por página"],"Preview":["Vista previa"],"Private":["Privada"],"Publish":["Publicar"],"Published: %s":["Publicado: %s"],"Radio group":["Grupo de botones de radio"],"Re-install version %(version)s":["Reinstalar la versión %(version)s"],"Reads from":["Lee de"],"Redo":["Rehacer"],"Relation":["Relación"],"Reload the admin":["Recargar la administración"],"Remove":["Quitar"],"Remove %(name)s":["Quitar %(name)s"],"Remove %(title)s":["Quitar %(title)s"],"Remove row":["Quitar fila"],"Rename":["Renombrar"],"Rename %(field)s":["Renombrar %(field)s"],"Rename…":["Renombrar…"],"Require":["Hacer obligatorio"],"Require %(field)s":["Hacer %(field)s obligatorio"],"Required":["Obligatorio"],"Restarting Gophenberg…":["Reiniciando Gophenberg…"],"Restore":["Restaurar"],"Role changed.":["Rol cambiado."],"Roll back to %(theme)s":["Revertir a %(theme)s"],"Roll back to the built-in renderer":["Revertir al renderizador integrado"],"Route word":["Palabra de ruta"],"Rule %(number)s of set %(set)s":["Regla %(number)s del conjunto %(set)s"],"Rule set %(number)s":["Conjunto de reglas %(number)s"],"Rules":["Reglas"],"Rules showing %(field)s":["Reglas que muestran %(field)s"],"Run update:status on the server to see the backup taken before the update. Then restore that backup, or fix what failed and start Gophenberg again.":["Ejecuta update:status en el servidor para ver la copia de seguridad hecha antes de la actualización. Después, restaura esa copia de seguridad, o corrige lo que ha fallado y vuelve a arrancar Gophenberg."],"Save":["Guardar"],"Save draft":["Guardar el borrador"],"Save rules":["Guardar las reglas"],"Save settings":["Guardar los ajustes"],"Saved":["Guardado"],"Saving":["Guardando"],"Scheduled":["Programada"],"Scheduled: %s":["Programado: %s"],"Search %(type)s…":["Buscar %(type)s…"],"Search audio":["Buscar audios"],"Search images":["Buscar imágenes"],"Search media":["Buscar medios"],"Search videos":["Buscar vídeos"],"Select":["Seleccionar"],"September":["septiembre"],"Serving":["Atendiendo"],"Settings":["Ajustes"],"Settings of %(field)s":["Ajustes de %(field)s"],"Shadowed":["Eclipsado"],"Show %(field)s in the list":["Mostrar %(field)s en la lista"],"Showing %(held)s of %(total)s.":["Mostrando %(held)s de %(total)s."],"Singular name":["Nombre en singular"],"Slug":["Slug"],"Somebody must be able to manage users.":["Alguien tiene que poder gestionar los usuarios."],"Someone else changed this media item while you were editing it. Reload the page and make your change again.":["Otra persona ha cambiado este medio mientras lo editabas. Recarga la página y vuelve a hacer tu cambio."],"Someone else saved changes to this item while you were editing, so yours were not saved. Copy your text somewhere safe, then reload the item and put your changes back in.":["Otra persona ha guardado cambios en este elemento mientras editabas, así que los tuyos no se han guardado. Copia tu texto a un lugar seguro, recarga el elemento y vuelve a colocarlos de vuelta."],"Something went wrong inside Gophenberg. Try again in a moment, and tell whoever looks after your site if it keeps happening.":["Algo ha fallado dentro de Gophenberg. Inténtalo de nuevo en un momento, y avisa a quien gestione tu sitio si sigue pasando."],"Something went wrong.":["Algo ha ido mal."],"Something went wrong. Try again.":["Algo ha ido mal. Inténtalo de nuevo."],"Sorry, you are not allowed to access this page.":["Lo siento, no tienes permisos para acceder a esta página."],"Source":["Origen"],"Steps of":["Pasos de"],"Stop nesting":["Dejar de anidar"],"Tablet":["Tableta"],"Text":["Texto"],"Text area":["Área de texto"],"That email is already in use.":["Ese correo electrónico ya está en uso."],"That field group no longer exists. Reload the page to see the groups your site holds now.":["Ese grupo de campos ya no existe. Recarga la página para ver los grupos que tiene ahora tu sitio."],"That field is not on this content type any more. Reload the page to see the fields it has now.":["Ese campo ya no está en este tipo de contenido. Recarga la página para ver los campos que tiene ahora."],"That revision does not exist, and older ones drop off once a type holds more than it keeps. Open the item to see which revisions are left.":["Esa revisión no existe, y las más antiguas se pierden cuando un tipo guarda más de las que conserva. Abre el elemento para ver qué revisiones quedan."],"That role holds more than your own.":["Ese rol abarca más que el tuyo."],"That web address does not name a media item Gophenberg can look up. Open the media library and pick the item from there.":["Esa dirección web no nombra ningún medio que Gophenberg pueda encontrar. Abre la biblioteca de medios y elige el elemento desde ahí."],"That web address does not name a revision Gophenberg can look up. Open the item and pick a revision from its history.":["Esa dirección web no alude a ninguna revisión que Gophenberg pueda identificar. Abre el elemento y elige una revisión de su historial."],"That web address does not name an item Gophenberg can look up. Go back to the list and open the item from there.":["Esa dirección web no alude a ningún elemento que Gophenberg pueda identificar. Vuelve a la lista y abre el elemento desde ahí."],"The %(count)s item in the trash is deleted for good. This cannot be undone.":["%(count)s elemento de la papelera se borrará permanentemente. Esto no se puede deshacer.","%(count)s de elementos de la papelera se borrarán permanentemente. Esto no se puede deshacer.","Los %(count)s elementos de la papelera se borrarán permanentemente. Esto no se puede deshacer."],"The %(file)s calls this theme %(declared)s, but it is being installed as %(installed)s. Rename the zip file to match, or change the name inside %(file)s.":["El archivo %(file)s llama a este tema %(declared)s, pero se está instalando como %(installed)s. Renombra el zip para que coincida, o cambia el nombre dentro de %(file)s."],"The %(file)s inside %(name)s is not valid JSON, so it could not be read. Fix that file and package the theme again.":["El archivo %(file)s dentro de %(name)s no es JSON válido, así que no se ha podido leer. Corrige ese archivo y vuelve a empaquetar el tema."],"The %(file)s inside %(name)s names its theme kit as %(declared)s, which is not a version number. Build the theme again, and the build will fill that in.":["El %(file)s dentro de %(name)s identifica su kit de temas como %(declared)s, que no srive como número de versión. Compila el tema de nuevo y la compilación lo rellenará."],"The %(origin)s plugin declared this, so it can only be changed in that plugin. Turning it off is still yours to do.":["El plugin %(origin)s lo declaró, así que solo se puede cambiar en ese plugin. Desactivarlo sigue estando en tu mano."],"The %(plugin)s plugin also declares %(name)s, and the site keeps the key.":["El plugin %(plugin)s también declara %(name)s, y el sitio se queda con la clave."],"The %(plugin)s plugin declared these fields, so they change only in its code.":["El plugin %(plugin)s declaró estos campos, así que solo cambian en su código."],"The %(plugin)s plugin declares %(name)s flat, and the site keeps it nesting while its items sit inside another.":["El plugin %(plugin)s declara %(name)s sin anidar, y el sitio lo mantiene anidando mientras sus elementos están dentro de otro."],"The browser kept an unsaved version of this post.":["El navegador ha guardado una versión sin guardar de esta entrada."],"The built-in renderer is now serving the public site.":["El renderizador integrado ya presta servicio al sitio público."],"The built-in renderer is serving the public site.":["El renderizador integrado presta servicio al sitio público."],"The check on %(date)s at %(time)s failed: %(error)s":["La comprobación del %(date)s a las %(time)s ha fallado: %(error)s"],"The content type this field points at is not named in a shape Gophenberg accepts. Give it a key that starts with a lowercase letter and then holds only lowercase letters, numbers and hyphens.":["El tipo de contenido al que apunta este campo no está nombrado con un formato que Gophenberg acepte. Dale una clave que empiece por una letra minúscula y contenga solo letras minúsculas, números y guiones."],"The content types could not be loaded, so where these groups appear and which fields they shadow are not shown.":["No se han podido cargar los tipos de contenido, así que no se muestra dónde aparecen estos grupos ni qué campos eclipsan."],"The content types could not be loaded.":["No se han podido cargar los tipos de contenido."],"The content types could not be refreshed, so where these groups appear and what they shadow may be out of date.":["No se han podido actualizar los tipos de contenido, así que dónde aparecen estos grupos y qué eclipsan puede estar desactualizado."],"The draft could not be created.":["No se ha podido crear el borrador."],"The entry %(entry)s in this zip would be written outside the theme folder, so nothing was installed. Package the theme again.":["La entrada %(entry)s de este zip se escribiría fuera de la carpeta del tema, así que no se ha instalado nada. Vuelve a empaquetar el tema."],"The field %(field)s cannot go, because %(by)s reads it. Change %(by)s first.":["El campo %(field)s no se puede quitar, porque %(by)s lo lee. Cambia antes %(by)s."],"The field %(field)s cannot hold the value it was given. Check what kind of field it is and enter a value that matches.":["El campo %(field)s no puede guardar el valor que se le ha dado. Comprueba de qué tipo de campo se trata e introduce un valor que encaje."],"The field %(field)s has to hold a value before this item can be published. Fill it in, or leave the item as a draft.":["El campo %(field)s tiene que tener un valor antes de poder publicar este elemento. Rellénalo, o deja el elemento como borrador."],"The field %(field)s in %(group)s still points at this content type. Delete that field first, then delete this type.":["El campo %(field)s de %(group)s todavía apunta a este tipo de contenido. Borra antes ese campo y luego borra este tipo."],"The field %(field)s is hidden by its own rules right now, so it cannot hold a value. Show it again before filling it in.":["El campo %(field)s está oculto por sus propias reglas ahora mismo, así que no puede guardar ningún valor. Vuelve a mostrarlo antes de rellenarlo."],"The field %(field)s points at one item only. Remove the extra choices and keep one.":["El campo %(field)s apunta a un solo elemento. Quita las opciones de más y deja una."],"The field %(field)s points at other items, so it does not take a plain value. Pick the items it points at instead.":["El campo %(field)s apunta a otros elementos, así que no admite un valor suelto. Elige en su lugar los elementos a los que apunta."],"The field %(field)s takes a list of items, and what arrived was not a list. Reload the page and pick the items again.":["El campo %(field)s admite una lista de elementos, y lo que ha llegado no era una lista. Recarga la página y vuelve a elegir los elementos."],"The field %(source)s cannot hold the value %(value)s, so no rule can compare it. Write a value of the kind %(source)s stores.":["El campo %(source)s no puede guardar el valor %(value)s, así que ninguna regla puede compararlo. Escribe un valor de la clase que %(source)s guarda."],"The field groups could not be loaded.":["No se han podido cargar los grupos de campos."],"The field groups could not be reached.":["No se ha podido contactar con los grupos de campos."],"The field keeps its values on the content both groups reach.":["El campo conserva sus valores en el contenido al que llegan ambos grupos."],"The fields this group holds go with it, and so do the values every item stored in them.":["Los campos que contiene este grupo se van con él, y también los valores que cada elemento guardó en ellos."],"The groups were reordered.":["Los grupos se han reordenado."],"The item could not be duplicated.":["No se ha podido duplicar el elemento."],"The item could not be moved to the trash.":["No se ha podido mover el elemento a la papelera."],"The item could not be permanently deleted.":["No se ha podido borrar permanentemente el elemento."],"The item could not be restored.":["No se ha podido restaurar el elemento."],"The item you picked as parent holds another kind of content. Pick a parent of the same content type as this item.":["El elemento que has elegido como superior tiene otro tipo de contenido. Elige un elemento superior del mismo tipo de contenido que este elemento."],"The item you picked as parent is in the trash. Restore it, or pick another parent.":["El elemento que has elegido como superior está en la papelera. Restáuralo, o elige otro elemento superior."],"The item you picked as parent no longer exists. Reload the page and pick another parent.":["El elemento que has elegido como superior ya no existe. Recarga la página y elige otro."],"The media library could not be loaded.":["No se ha podido cargar la biblioteca de medios."],"The name changes. Nothing stored under this field moves.":["El nombre cambia. Nada de lo guardado en este campo se mueve."],"The name could not be updated.":["No se ha podido actualizar el nombre."],"The new order has to name every field group exactly once. Reload the page and move the groups again.":["El nuevo orden tiene que nombrar cada grupo de campos exactamente una vez. Recarga la página y mueve los grupos otra vez."],"The new order has to name every field of this content type exactly once. Reload the page and move the fields again.":["El nuevo orden tiene que nombrar cada campo de este tipo de contenido exactamente una vez. Recarga la página y mueve los campos de nuevo."],"The next check runs in %(time)s.":["La próxima comprobación será dentro de %(time)s."],"The number of revisions to keep has to be a whole number, and it cannot be negative. Enter a different number.":["El número de revisiones que se conservan tiene que ser un número entero, y no puede ser negativo. Introduce otro número."],"The registry could not be reached.":["No se ha podido acceder al registro."],"The role could not be changed.":["No se ha podido cambiar el rol."],"The rule on %(source)s names nothing to match. Pick a value, or remove the rule.":["La regla sobre %(source)s no nombra nada con lo que coincidir. Elige un valor, o quita la regla."],"The rules could not be loaded.":["No se han podido cargar las reglas."],"The rules on %(field)s lead back to %(field)s itself, so nothing can decide whether to show it. Point one of them at another field.":["Las reglas de %(field)s vuelven al propio %(field)s, así que nada puede decidir si mostrarlo. Apunta una de ellas a otro campo."],"The same item was picked twice for %(field)s. Pick each item once.":["El mismo elemento se ha elegido dos veces para %(field)s. Elige cada elemento una sola vez."],"The server could not be reached, so nothing was changed.":["No se ha podido acceder al servidor, así que no se ha cambiado nada."],"The server could not be reached, so nothing was saved.":["No se ha podido acceder al servidor, así que no se ha guardado nada."],"The server could not be reached, so nothing was uploaded.":["No se ha podido acceder al servidor, así que no se ha subido nada."],"The setting %(setting)s cannot hold the value it was given. Check what this setting takes and try again.":["El ajuste %(setting)s no puede contener el valor que se le dio. Comprueba qué acepta este ajuste y prueba de nuevo."],"The setting %(setting)s falls outside the others. Keep min below max and the default inside the bounds.":["El ajuste %(setting)s queda fuera de los demás. Mantén min por debajo de max y el valor por defecto dentro de los límites."],"The settings could not be read, so nothing can be changed here yet.":["No se han podido leer los ajustes, así que todavía no se puede cambiar nada aquí."],"The site default":["El idioma por defecto del sitio"],"The site may already hold part of this file. Import it again to see what is left.":["Puede que el sitio ya tenga parte de este archivo. Impórtalo de nuevo para ver lo que queda."],"The source %(source)s does not offer %(operator)s. Pick one of the comparisons it does offer.":["La fuente %(source)s no ofrece %(operator)s. Elige una de las comparaciones que sí ofrece."],"The theme %(name)s carries no %(file)s, so Gophenberg cannot tell what it is. Put that file at the top level of the zip and package the theme again.":["El tema %(name)s no lleva ningún %(file)s, así que Gophenberg no puede saber qué es. Pon ese archivo en el primer nivel del zip y vuelve a empaquetar el tema."],"The theme %(name)s could not be read, so it cannot serve your site. Upload it again, or choose another theme.":["El tema %(name)s no se ha podido leer, así que no puede servir tu sitio. Vuelve a subirlo, o elige otro tema."],"The theme %(name)s did not start, so your site is still served by the theme it had. Ask whoever looks after your site to check the server log for what the theme reported.":["El tema %(name)s no ha arrancado, así que tu sitio lo sigue sirviendo el tema que tenía. Pide a quien gestiona tu sitio que mire en el registro del servidor para saber qué problema ha informado el tema."],"The theme %(name)s does not carry %(path)s as a file, so there is nothing to run. Package the built theme rather than its source.":["El tema %(name)s no lleva %(path)s como archivo, así que no hay nada que ejecutar. Empaqueta el tema ya construido, no su código fuente."],"The theme %(name)s does not carry %(path)s as a folder, so its styles and scripts are missing. Package the built theme rather than its source.":["El tema %(name)s no lleva %(path)s como carpeta, así que le faltan los estilos y los scripts. Empaqueta el tema ya construido, no su código fuente."],"The theme %(name)s holds a link to another file at %(path)s, and a theme may only carry real files. Replace it and package the theme again.":["El tema %(name)s lleva un enlace a otro archivo en %(path)s, y un tema solo puede llevar archivos de verdad. Sustitúyelo y vuelve a empaquetar el tema."],"The theme %(name)s is serving your site right now, so it cannot be replaced. Deactivate it first, or install this copy under another name.":["El tema %(name)s sirve tu sitio ahora mismo, así que no se puede sustituir. Desactívalo primero, o instala esta copia con otro nombre."],"The theme %(name)s is the one chosen, but it is not installed, so your site is served by the built-in renderer. Upload the theme again, or choose another one.":["El tema %(name)s es el elegido, pero no está instalado, así que el renderizador integrado está prestando servicio a tu sitio. Vuelve a subir el tema, o elige otro."],"The theme %(name)s was built on theme kit %(declared)s, and this site serves %(served)s. Build the theme again against a kit this site serves, then install it.":["El tema %(name)s se compiló con el kit de temas %(declared)s y este sitio sirve %(served)s. Compila el tema de nuevo con un kit que este sitio sirva y después instálalo."],"The trash could not be emptied.":["No se ha podido vaciar la papelera."],"The update failed before anything changed.":["La actualización ha fallado antes de cambiar nada."],"The update to %(to)s failed its start check, and Gophenberg cannot go back to %(from)s on its own.":["La actualización a %(to)s no ha superado su comprobación de arranque, y Gophenberg no puede volver a %(from)s por su cuenta."],"The update to %(to)s failed.":["La actualización a %(to)s ha fallado."],"The update to Gophenberg %(version)s failed to complete. Please attempt the update again now.":["No se ha podido completar la actualización a Gophenberg %(version)s. Por favor, vuelve a intentarlo."],"The updates could not be read, so nothing can be updated here yet.":["No se han podido leer las actualizaciones, así que todavía no se puede actualizar nada aquí."],"The user could not be created.":["No se ha podido crear el usuario."],"The values stored under it do not follow.":["Los valores guardados debajo no le siguen."],"Theme":["Tema"],"Themes":["Temas"],"Themes could not be loaded.":["No se han podido cargar los temas."],"There is no content type called %(value)s. Pick a type your site holds, or register it first.":["No existe ningún tipo de contenido llamado %(value)s. Elige un tipo que tenga tu sitio, o regístralo primero."],"There is no content type called %(value)s. Pick one of the types your site holds and try again.":["No existe ningún tipo de contenido llamado %(value)s. Elige uno de los tipos que tiene tu sitio e inténtalo de nuevo."],"There is no kind of field called %(value)s. Pick one of these instead: %(allowed)s.":["No existe ningún tipo de campo llamado %(value)s. Elige uno de estos: %(allowed)s."],"There is no page kind called %(value)s. Pick one of these instead: %(allowed)s.":["No existe ningún tipo de página llamado %(value)s. Elige uno de estos: %(allowed)s."],"There is no status called %(value)s. Pick one of these instead: %(allowed)s.":["No existe ningún estado llamado %(value)s. Elige uno de estos: %(allowed)s."],"There is nothing at this address. Check the link and try again.":["No hay nada en esta dirección. Comprueba el enlace e inténtalo de nuevo."],"There is nothing to roll back to, because your site has not been through a theme change yet. Install a theme first, then a rollback has somewhere to go.":["No hay nada a lo que retornar, porque tu sitio todavía no ha cambiado de tema. Instala un tema primero y así el retorno tendrá adónde ir."],"These files could not be read.":["No se han podido leer estos archivos."],"These were left alone, because nobody confirmed losing them.":["Estos se han dejado como estaban, porque nadie confirmó perderlos."],"This content type does not exist any more. Reload the page to see the types your site holds now.":["Este tipo de contenido ya no existe. Recarga la página para ver los tipos que tiene ahora tu sitio."],"This content type does not nest, so one of its items cannot sit inside another. Mark the type as Nests first.":["Este tipo de contenido no anida, así que uno de sus elementos no puede estar dentro de otro. Marca el tipo como Anida primero."],"This content type has no field called %(field)s. Check the name, or declare the field on the type first.":["Este tipo de contenido no tiene ningún campo llamado %(field)s. Comprueba el nombre, o declara antes el campo en el tipo."],"This content type is turned off, so its content is not served or edited. Activate it first.":["Este tipo de contenido está desactivado, así que su contenido ni se sirve ni se edita. Actívalo primero."],"This content type still holds content, so it cannot be deleted. Move or delete its items first.":["Este tipo de contenido todavía tiene contenido, así que no se puede borrar. Mueve o borra antes sus elementos."],"This definitions file is larger than the %(max)s bytes Gophenberg reads in one request. Split it, or raise the limit your site runs with.":["Este archivo de definiciones es mayor que los %(max)s bytes que Gophenberg lee en una petición. Divídelo, o sube el límite con el que funciona tu sitio."],"This field holds no layouts yet.":["Este campo todavía no tiene diseños."],"This field would stand inside too many containers. Put it nearer the top and try again.":["Este campo quedaría dentro de demasiados contenedores. Ponlo más cerca del nivel superior e inténtalo de nuevo."],"This file could not be opened as a zip. Package the theme again and upload the new file.":["Este archivo no se ha podido abrir como zip. Vuelve a empaquetar el tema y sube el archivo nuevo."],"This file is larger than the upload limit. Upload a smaller file.":["Este archivo es más grande que el límite de subida. Sube un archivo más pequeño."],"This file is named %(extension)s but it holds %(detected)s content. Upload it under a name that matches what is inside it.":["Este archivo se llama %(extension)s pero lleva contenido %(detected)s. Súbelo con un nombre que coincida con lo que lleva dentro."],"This file matches the site, so there is nothing to change.":["Este archivo coincide con el sitio, así que no hay nada que cambiar."],"This file says it was written in format %(declared)s, which is not a version Gophenberg can read. Export the definitions again from the site they came from.":["Este archivo dice estar escrito en el formato %(declared)s, que no es una versión que Gophenberg pueda leer. Vuelve a exportar las definiciones desde el sitio del que vinieron."],"This file was written in format %(declared)s, and this release reads %(served)s. Upgrade the site the file came from, or this one.":["Este archivo está escrito en el formato %(declared)s, y esta versión lee %(served)s. Actualiza el sitio del que viene el archivo, o este."],"This group holds no fields yet.":["Este grupo todavía no tiene campos."],"This install of Gophenberg has no install root, so it updates by hand.":["Esta instalación de Gophenberg no tiene raíz de instalación, así que se actualiza a mano."],"This install of Gophenberg updates by hand.":["Esta instalación de Gophenberg se actualiza a mano."],"This is a custom build of Gophenberg, so it updates by hand.":["Esta es una compilación propia de Gophenberg, así que se actualiza a mano."],"This item cannot go straight to that status from the one it holds now. Save it as a draft first, then try again.":["Este elemento no puede pasar directamente a ese estado desde el que tiene ahora. Guárdalo antes como borrador e inténtalo de nuevo."],"This item does not exist, and it may have been deleted. Go back to the list to see what is there.":["Este elemento no existe, y puede que se haya borrado. Vuelve a la lista para ver qué hay."],"This item is already in the trash. Restore it first to work on it again.":["Este elemento ya está en la papelera. Restáuralo primero para volver a trabajar en él."],"This item is in the trash. Restore it first to work on it again.":["Este elemento está en la papelera. Restáuralo primero para volver a trabajar en él."],"This item is not in the trash, so there is nothing to restore. Open it from the list to work on it as it is.":["Este elemento no está en la papelera, así que no hay nada que restaurar. Ábrelo desde la lista para trabajar en él tal como está."],"This item still holds items nested inside it. Move or delete those first.":["Este elemento todavía tiene elementos anidados dentro. Mueve o borra antes esos."],"This kind of field holds no fields inside it. Put the field in a section or a repeater instead.":["Este tipo de campo no contiene campos dentro. Pon el campo en una sección o en un repetidor."],"This media item is not in the library, and someone may have deleted it. Reload the page to see what is there now.":["Este medio no está en la biblioteca, y puede que alguien lo haya borrado. Recarga la página para ver qué hay ahora."],"This picture could not be read, so nothing was stored. The file may be damaged, so open it on your computer and upload it again.":["Esta imagen no se ha podido leer, así que no se ha guardado nada. Puede que el archivo esté dañado, así que ábrelo en tu ordenador y vuelve a subirlo."],"This picture is %(width)s by %(height)s pixels, over the limit of %(max)s pixels in all. Make it smaller and upload it again.":["Esta imagen tiene %(width)s por %(height)s píxeles, por encima del límite de %(max)s píxeles en total. Hazla más pequeña y vuelve a subirla."],"This post changed elsewhere. Reload before saving again.":["Esta entrada ha cambiado en otro sitio. Recarga antes de volver a guardar."],"This request came from a page on another site, so it was refused. Open the admin on this site and try again.":["Esta petición vino de una página de otro sitio, así que se rechazó. Abre la administración en este sitio e inténtalo de nuevo."],"This request carried %(attribute)s, which fields do not take. Reload the page so the admin and the server agree again.":["Esta petición llevaba %(attribute)s, que los campos no aceptan. Recarga la página para que la administración y el servidor vuelvan a coincidir."],"This request left out %(field)s, which Gophenberg needs. Reload the page and try again.":["En esta petición faltaba %(field)s, que Gophenberg necesita. Recarga la página e inténtalo de nuevo."],"This rule reads a source called %(source)s, and nothing on your site declares one. A plugin that added it may have been removed.":["Esta regla lee una fuente llamada %(source)s, y nada en tu sitio declara ninguna. Puede que se haya quitado un plugin que la añadía."],"This site cannot write to its themes folder, so no theme can be installed. Ask whoever looks after your site to make the folder that %(setting)s points at writable. A read-only mount is the usual cause.":["Este sitio no puede escribir en su carpeta de temas, así que no se puede instalar ninguno. Pide a quien gestione tu sitio que haga escribible la carpeta a la que apunta %(setting)s. La causa habitual es un montaje de solo lectura."],"This site does not check for updates on its own.":["Este sitio no busca actualizaciones por su cuenta."],"This site has nowhere to keep themes, so no theme can be installed. Ask whoever looks after your site to point %(setting)s at a folder the server can write to.":["Este sitio no tiene dónde guardar los temas, así que no se puede instalar ninguno. Pide a quien gestione tu sitio que apunte %(setting)s a una carpeta en la que el servidor pueda escribir."],"This site has nowhere to store uploads, so nothing can be uploaded. Ask whoever looks after your site to point %(setting)s at a folder the server can write to.":["Este sitio no tiene dónde guardar las subidas, así que no se puede subir nada. Pide a quien gestione tu sitio que apunte %(setting)s a una carpeta en la que el servidor pueda escribir."],"This site will not receive automatic updates for new versions of Gophenberg.":["Este sitio no recibirá actualizaciones automáticas de nuevas versiones de Gophenberg."],"This theme is over the limit of %(max)s bytes, packed or unpacked. Leave out what the theme does not need and package it again.":["Este tema pasa del límite de %(max)s bytes, comprimido o sin comprimir. Saca lo que el tema no necesite y vuelve a empaquetarlo."],"This type will answer under /%(word)s.":["Este tipo responderá como /%(word)s."],"This update needs a backup of the database, and the site stays down if the new version does not start.":["Esta actualización necesita una copia de seguridad de la base de datos, y el sitio deja de funcionar si la nueva versión no arranca."],"This zip holds %(entries)s files, more than the %(max)s a theme may carry. Package only the built theme.":["Este zip lleva %(entries)s archivos, más de los %(max)s que puede llevar un tema. Empaqueta solo el tema ya construido."],"Through":["A través de"],"Thumbnail":["Miniatura"],"Title":["Título"],"Two field groups in this file share the key %(key)s. Give one of them a different key and import again.":["Dos grupos de campos de este archivo comparten la clave %(key)s. Dale una clave distinta a uno de ellos e importa de nuevo."],"Two rule sources are registered under the name %(param)s. A plugin is declaring a source your site already holds.":["Hay dos fuentes de reglas registradas con el nombre %(param)s. Un plugin declara una fuente que tu sitio ya tiene."],"Type":["Tipo"],"Type a whole number in both boxes before saving.":["Escribe un número entero en las dos casillas antes de guardar."],"Undo":["Deshacer"],"Unpacking the update…":["Descomprimiendo la actualización…"],"Unsaved changes":["Cambios sin guardar"],"Update":["Actualizar"],"Update failed.":["No se ha podido actualizar."],"Update to Gophenberg %(version)s?":["¿Actualizar a Gophenberg %(version)s?"],"Update to version %(version)s":["Actualizar a la versión %(version)s"],"Updates":["Actualizaciones"],"Upload theme":["Subir tema"],"Uploaded %s file.":["%s archivo subido.","%s de archivos subidos.","%s archivos subidos."],"Users":["Usuarios"],"Users could not be loaded.":["No se han podido cargar los usuarios."],"Value":["Valor"],"Verifying the unpacked files…":["Verificando los archivos descomprimidos…"],"Version":["Versión"],"Videos":["Vídeos"],"Visit Site":["Visitar el sitio"],"Web address":["Dirección web"],"What each Linked from field reads":["Qué lee cada campo Enlazado desde"],"What it points at changed, so its stored values go with it.":["Aquello a lo que apunta ha cambiado, así que sus valores guardados se van con él."],"Where %(group)s appears":["Dónde aparece %(group)s"],"While your site is being updated, it keeps serving until Gophenberg restarts on the new version.":["Mientras tu sitio está siendo actualizado, sigue funcionando hasta que Gophenberg se reinicia con la nueva versión."],"Without a rule this field always shows.":["Sin ninguna regla este campo siempre se muestra."],"Without a rule this group appears nowhere.":["Sin una regla este grupo no aparece en ningún sitio."],"Yes":["Sí"],"Yes or no":["Sí o no"],"You can update from Gophenberg %(running)s to Gophenberg %(version)s manually:":["Puedes actualizar desde Gophenberg %(running)s a Gophenberg %(version)s manualmente:"],"You cannot change your own role.":["No puedes cambiar tu propio rol."],"You cannot update because Gophenberg %(version)s requires PostgreSQL version %(postgresql)s or higher.":["No puedes actualizar porque Gophenberg %(version)s necesita la versión %(postgresql)s o superior de PostgreSQL."],"You have the latest version of Gophenberg.":["Tienes la última versión de Gophenberg."],"Your language":["Tu idioma"],"Your role does not allow %(capability)s.":["Tu rol no permite %(capability)s."],"Your server pins the site to the theme %(name)s, so themes cannot be changed here. Ask whoever looks after your site to remove the pin.":["Tu servidor bloque el sitio al tema %(name)s, así que los temas no se pueden cambiar desde aquí. Pide a quien gestiona tu sitio que quite ese bloqueo."],"Your site always needs one default content type, so this one cannot be turned off or deleted. Make another type the default first.":["Tu sitio siempre necesita un tipo de contenido por defecto, así que este no se puede desactivar ni borrar. Haz antes que otro tipo sea el que está por defecto."],"a content type":["un tipo de contenido"],"account\u0004Role":["Rol"],"account\u0004Status":["Estado"],"action label\u0004Duplicate":["Duplicar"],"action label\u0004Duplicate…":["Duplicar…"],"address":["dirección"],"admin section\u0004Content Types":["Tipos de contenido"],"admin section\u0004Field Groups":["Grupos de campos"],"admin section\u0004Language":["Idioma"],"admin section\u0004Media":["Medios"],"admin section\u0004Settings":["Ajustes"],"admin section\u0004Themes":["Temas"],"column\u0004Date":["Fecha"],"content type\u0004\"%s\" permanently deleted.":["Se ha borrado permanentemente el tipo de contenido «%s»."],"content type\u0004\"%s\" successfully created.":["Se ha creado correctamente el tipo de contenido «%s»."],"content type\u0004Status":["Estado"],"field\u0004Name":["Nombre"],"field group\u0004Status":["Estado"],"field type\u0004Choice":["Elección"],"field type\u0004Color":["Color"],"field type\u0004Date":["Fecha"],"field type\u0004Flexible content":["Contenido flexible"],"field type\u0004Gallery":["Galería"],"field type\u0004Kind":["Tipo"],"field type\u0004Layout":["Diseño"],"field type\u0004Link":["Enlace"],"field type\u0004Media":["Medio"],"field type\u0004Range":["Rango"],"field type\u0004Repeater":["Repetidor"],"field type\u0004Section":["Sección"],"field type\u0004Select":["Desplegable"],"file size\u0004%1$s %2$s":["%1$s %2$s"],"file type group\u0004Archives":["Archivos"],"file type group\u0004Audio":["Audio"],"file type group\u0004Video":["Vídeo"],"holds":["contiene"],"holds anything":["contiene algo"],"https://www.w3.org/WAI/tutorials/images/decision-tree/":["https://www.w3.org/WAI/tutorials/images/decision-tree/"],"image dimensions\u0004%1$s × %2$s":["%1$s × %2$s"],"is":["es"],"is above":["es mayor que"],"is below":["es menor que"],"is empty":["está vacío"],"is not":["no es"],"panel button label\u0004Settings":["Ajustes"],"person\u0004Name":["Nombre"],"post\u0004%s (Copy)":["%s (copia)"],"post\u0004Status":["Estado"],"post status\u0004Draft":["Borrador"],"post status\u0004Published":["Publicada"],"post status\u0004Trash":["Papelera"],"post type general name\u0004Pages":["Páginas"],"post type general name\u0004Posts":["Entradas"],"post type singular name\u0004Page":["Página"],"post type singular name\u0004Post":["Entrada"],"relation target\u0004None":["Ninguno"],"role\u0004Administrator":["Administrador"],"role\u0004Author":["Autor"],"role\u0004Editor":["Editor"],"role\u0004Member":["Miembro"],"role\u0004No role":["Sin rol"],"status filter\u0004All":["Todo"],"taxonomy general name\u0004Categories":["Categorías"],"taxonomy singular name\u0004Category":["Categoría"],"theme\u0004Status":["Estado"],"trash\u0004Restore":["Restaurar"],"unit symbol\u0004B":["B"],"unit symbol\u0004EB":["EB"],"unit symbol\u0004GB":["GB"],"unit symbol\u0004KB":["KB"],"unit symbol\u0004MB":["MB"],"unit symbol\u0004PB":["PB"],"unit symbol\u0004TB":["TB"],"unit symbol\u0004YB":["YB"],"unit symbol\u0004ZB":["ZB"],"v%(version)s":["v%(version)s"],"verb\u0004Trash…":["Papelera…"],"verb\u0004View":["Ver"],"{day} {month} {year}":["{day} de {month} de {year}"]} diff --git a/frontend/src/languages/fr-FR.json b/frontend/src/languages/fr-FR.json index 89c8e8dd..2d9e2579 100644 --- a/frontend/src/languages/fr-FR.json +++ b/frontend/src/languages/fr-FR.json @@ -1 +1 @@ -{"":{"lang":"fr","plural-forms":"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"}," and ":[" et "]," or ":[" ou "],"\"%s\" activated.":["Type de contenu « %s » activé."],"\"%s\" deactivated.":["Type de contenu « %s » désactivé."],"\"%s\" has been restored.":["« %s » a été rétabli."],"\"%s\" moved to the trash.":["« %s » déplacé dans la corbeille."],"\"%s\" permanently deleted.":["Suppression définitive de « %s »."],"\"%s\" successfully created.":["« %s » créé avec succès."],"\"%s\" uploaded.":["« %s » téléversé."],"%(field)s address":["Adresse de %(field)s"],"%(field)s cannot move inside itself. Pick a container that is not one of its own.":["%(field)s ne peut pas être déplacé à l'intérieur de lui-même. Choisissez un conteneur qui n'est pas l'un des siens."],"%(field)s declared.":["%(field)s déclaré."],"%(field)s deleted.":["%(field)s supprimé."],"%(field)s does not match the format its field asks for. Check it and save again.":["%(field)s ne respecte pas le format demandé par son champ. Vérifiez-le et enregistrez de nouveau."],"%(field)s goes no higher than %(limit)s. Lower the value and save again.":["%(field)s ne dépasse pas %(limit)s. Baissez la valeur et enregistrez de nouveau."],"%(field)s goes no lower than %(limit)s. Raise the value and save again.":["%(field)s ne descend pas sous %(limit)s. Augmentez la valeur et enregistrez de nouveau."],"%(field)s holds no value of its own, so it cannot be required. Make it optional.":["%(field)s ne contient aucune valeur propre, il ne peut donc pas être obligatoire. Rendez-le facultatif."],"%(field)s is optional again.":["%(field)s est de nouveau facultatif."],"%(field)s is required now.":["%(field)s est maintenant obligatoire."],"%(field)s moved.":["%(field)s déplacé."],"%(field)s names the same one twice. Remove the repeat and save again.":["%(field)s nomme le même deux fois. Retirez la répétition et enregistrez de nouveau."],"%(field)s needs at least %(limit)s files. Add one and save again.":["%(field)s demande au moins %(limit)s fichiers. Ajoutez-en un et enregistrez."],"%(field)s needs at least %(limit)s rows. Add one and save again.":["%(field)s demande au moins %(limit)s lignes. Ajoutez-en une et enregistrez."],"%(field)s only takes one of its listed choices. Pick one and save again.":["%(field)s accepte uniquement un des choix de sa liste. Choisissez-en un et enregistrez de nouveau."],"%(field)s reads a relation field that is not there. Pick a group and a relation field it holds.":["%(field)s lit un champ de relation qui n'existe pas. Choisissez un groupe et un champ de relation qu'il contient."],"%(field)s reads a relation pointing at %(type)s, so it would list nothing here. Pick a relation pointing at the items this group is shown on.":["%(field)s lit une relation qui pointe vers %(type)s, elle n'afficherait donc rien ici. Choisissez une relation qui pointe vers les éléments où ce groupe s'affiche."],"%(field)s renamed.":["%(field)s renommé."],"%(field)s settled.":["%(field)s réglé."],"%(field)s shows by its rules now.":["%(field)s s'affiche désormais selon ses règles."],"%(field)s stands in the list.":["%(field)s figure dans la liste."],"%(field)s stays out of the list.":["%(field)s reste hors de la liste."],"%(field)s takes at most %(limit)s files. Remove one and save again.":["%(field)s accepte au plus %(limit)s fichiers. Retirez-en un et enregistrez."],"%(field)s takes at most %(limit)s letters. Shorten what you wrote and save again.":["%(field)s accepte au plus %(limit)s lettres. Raccourcissez ce que vous avez écrit et enregistrez de nouveau."],"%(field)s takes at most %(limit)s rows. Remove one and save again.":["%(field)s accepte au plus %(limit)s lignes. Retirez-en une et enregistrez."],"%(field)s title":["Titre de %(field)s"],"%(file)s is larger than one upload may be.":["%(file)s dépasse la taille maximale d'un téléversement."],"%(file)s is not a file this block accepts.":["%(file)s n'est pas un fichier que ce bloc accepte."],"%(file)s: %(reason)s":["%(file)s : %(reason)s"],"%(group)s created.":["%(group)s créé."],"%(group)s now appears where you said.":["%(group)s apparaît maintenant là où vous avez dit."],"%(group)s removed.":["%(group)s supprimé."],"%(group)s updated.":["%(group)s mis à jour."],"%(key)s is served by %(winner)s, so %(loser)s does not show it on %(where)s.":["%(key)s est servi par %(winner)s, donc %(loser)s ne le montre pas sur %(where)s."],"%(name)s %(version)s is serving the public site.":["%(name)s %(version)s sert le site public."],"%(name)s belongs to the site now.":["%(name)s appartient désormais au site."],"%(name)s came from the %(plugin)s plugin, which no longer declares it.":["%(name)s venait de l'extension %(plugin)s, qui ne le déclare plus."],"%(name)s cannot be used as a theme name. Name the zip file after the theme, with no dot at the start and no slashes in it.":["%(name)s ne peut pas servir de nom de thème. Nommez le fichier zip comme le thème, sans point au début et sans barre oblique."],"%(name)s moves to /%(word)s. Every address of both types changes.":["Le type %(name)s passe à /%(word)s. Toutes les adresses des deux types changent."],"%(name)s would move to /%(word)s, which Gophenberg keeps for itself. Change its plural name and try again.":["Le type %(name)s passerait à /%(word)s, que Gophenberg garde pour lui. Modifiez son nom au pluriel et réessayez."],"%(source)s is %(value)s":["%(source)s est %(value)s"],"%(theme)s failed to start, so the built-in renderer is serving.":["%(theme)s n'a pas pu démarrer, le moteur de rendu intégré sert donc le site."],"%(theme)s is now serving the public site.":["%(theme)s sert désormais le site public."],"%(theme)s is serving the public site.":["%(theme)s sert le site public."],"%(theme)s is still starting, so the built-in renderer is serving.":["%(theme)s démarre encore, le moteur de rendu intégré sert donc le site."],"%(theme)s was installed.":["%(theme)s a été installé."],"%(theme)s will not load, so the built-in renderer is serving.":["%(theme)s ne se charge pas, le moteur de rendu intégré sert donc le site."],"%(type)s answers on a new address, and stored links move with it.":["%(type)s répond à une nouvelle adresse, et les liens enregistrés la suivent."],"%(type)s becomes the type the site opens on, and the old one takes an address.":["%(type)s devient le type sur lequel le site ouvre, et l'ancien prend une adresse."],"%(type)s keeps nesting while %(items)s of its items sit inside another. Move those to the top level first, the ones in the trash included.":["%(type)s continue de s'imbriquer tant que %(items)s de ses éléments se trouvent dans un autre. Déplacez-les d'abord au niveau supérieur, ceux de la corbeille compris."],"%(type)s keeps nesting, because some of its items sit inside another.":["%(type)s continue de s'imbriquer, car certains de ses éléments se trouvent dans un autre."],"%(type)s will answer at the root.":["Le type %(type)s répondra à la racine."],"%s content type activated.":["%s type de contenu activé.","%s types de contenu activés.","%s types de contenu activés."],"%s content type could not be activated.":["%s type de contenu n'a pas pu être activé.","%s types de contenu n'ont pas pu être activés.","%s types de contenu n'ont pas pu être activés."],"%s content type could not be deactivated.":["%s type de contenu n'a pas pu être désactivé.","%s types de contenu n'ont pas pu être désactivés.","%s types de contenu n'ont pas pu être désactivés."],"%s content type could not be permanently deleted.":["%s type de contenu n'a pas pu être supprimé définitivement.","%s types de contenu n'ont pas pu être supprimés définitivement.","%s types de contenu n'ont pas pu être supprimés définitivement."],"%s content type deactivated.":["%s type de contenu désactivé.","%s types de contenu désactivés.","%s types de contenu désactivés."],"%s content type permanently deleted.":["%s type de contenu supprimé définitivement.","%s types de contenu supprimés définitivement.","%s types de contenu supprimés définitivement."],"%s item could not be moved to the trash.":["%s élément n'a pas pu être déplacé dans la corbeille.","%s éléments n'ont pas pu être déplacés dans la corbeille.","%s éléments n'ont pas pu être déplacés dans la corbeille."],"%s item could not be permanently deleted.":["%s élément n'a pas pu être supprimé définitivement.","%s éléments n'ont pas pu être supprimés définitivement.","%s éléments n'ont pas pu être supprimés définitivement."],"%s item could not be restored.":["%s élément n'a pas pu être rétabli.","%s éléments n'ont pas pu être rétablis.","%s éléments n'ont pas pu être rétablis."],"%s item moved to the trash.":["%s élément déplacé dans la corbeille.","%s éléments déplacés dans la corbeille.","%s éléments déplacés dans la corbeille."],"%s item permanently deleted.":["%s élément supprimé définitivement.","%s éléments supprimés définitivement.","%s éléments supprimés définitivement."],"%s item stays in the trash.":["%s élément reste dans la corbeille.","%s éléments restent dans la corbeille.","%s éléments restent dans la corbeille."],"%s page has been restored.":["%s page a été rétablie.","%s pages ont été rétablies.","%s pages ont été rétablies."],"%s post has been restored.":["%s article a été rétabli.","%s articles ont été rétablis.","%s articles ont été rétablis."],"(no title)":["(pas de titre)"],"A %(kind)s field does not take a setting called %(setting)s. Remove it and try again.":["Un champ %(kind)s n'accepte pas de réglage nommé %(setting)s. Retirez-le et réessayez."],"A Linked from field stands on its own, not inside a section or a repeater. Declare %(field)s beside the container.":["Un champ Lié depuis se place seul, ni dans une section ni dans un répéteur. Déclarez %(field)s à côté du conteneur."],"A content type needs a singular and a plural name, like Guide and Guides. Fill both in and try again.":["Un type de contenu a besoin d'un nom au singulier et d'un nom au pluriel, comme Guide et Guides. Remplissez les deux et réessayez."],"A descriptive summary of the content type.":["Un résumé descriptif du type de contenu."],"A field group key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Rename the group in the file so its key comes out in that shape.":["La clé d'un groupe de champs doit commencer par une lettre minuscule puis ne contenir que des lettres minuscules, des chiffres et des tirets. Renommez le groupe dans le fichier pour que sa clé prenne cette forme."],"A field key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Rename the field so its key comes out in that shape.":["La clé d'un champ doit commencer par une lettre minuscule et ne contenir ensuite que des lettres minuscules, des chiffres et des tirets. Renommez le champ pour que sa clé prenne cette forme."],"A field needs a name. Type one and try again.":["Un champ a besoin d'un nom. Saisissez-en un et réessayez."],"A field with that name already exists on the items this group reaches. Pick another name.":["Un champ portant ce nom existe déjà sur les éléments que ce groupe atteint. Choisissez un autre nom."],"A flexible content field holds layouts, and %(field)s is not one. Add a layout first, then declare the field inside that layout.":["Un champ de contenu flexible contient des dispositions, et %(field)s n'en est pas une. Ajoutez d'abord une disposition, puis déclarez le champ dans cette disposition."],"A higher quality stores larger files, and it applies to pictures uploaded from now on.":["Une qualité plus élevée stocke des fichiers plus grands, et elle s'applique aux images téléversées à partir de maintenant."],"A layout stands inside a flexible content field only. Put %(field)s inside one of those instead.":["Une disposition ne se place que dans un champ de contenu flexible. Placez %(field)s dans l'un d'eux."],"A layout stands inside a flexible content field, never on its own. Declare a flexible content field first, then add %(field)s inside it.":["Une disposition se place dans un champ de contenu flexible, jamais seule. Déclarez d'abord un champ de contenu flexible, puis ajoutez %(field)s dedans."],"A listing carries between 1 and %(max)s items, so %(value)s is not a size Gophenberg takes. Pick a number inside that range.":["Une liste affiche entre 1 et %(max)s éléments, donc %(value)s n'est pas une taille que Gophenberg accepte. Choisissez un nombre dans cet intervalle."],"A relation field has to say which content type it points at. Pick that type and try again.":["Un champ de relation doit indiquer le type de contenu qu'il vise. Choisissez ce type et réessayez."],"A reload shows the admin in the language you chose.":["Un rechargement affiche l'administration dans la langue que vous avez choisie."],"A route word has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Change it and try again.":["Un mot de route doit commencer par une lettre minuscule et ne contenir ensuite que des lettres minuscules, des chiffres et des tirets. Modifiez-le et réessayez."],"A row of %(field)s has to name the layout it takes. Pick a layout for the row, or remove the row.":["Une ligne de %(field)s doit nommer la disposition qu'elle prend. Choisissez une disposition pour la ligne, ou retirez la ligne."],"A row of %(field)s takes one layout and no more. Reload the page and build the row again.":["Une ligne de %(field)s prend une seule disposition. Rechargez la page et reconstruisez la ligne."],"A rule matching any %(source)s cannot be turned into an exclusion. Leave it as is, or name the ones to leave out instead.":["Une règle valable pour n'importe quel %(source)s ne peut pas devenir une exclusion. Laissez-la telle quelle, ou nommez ceux à écarter."],"A theme naming its own page size uses that instead.":["Un thème qui indique sa propre taille de page utilise celle-ci à la place."],"A type key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Change the key and try again.":["La clé d'un type doit commencer par une lettre minuscule et ne contenir ensuite que des lettres minuscules, des chiffres et des tirets. Modifiez la clé et réessayez."],"Actions":["Actions"],"Activate":["Activer"],"Activate %(theme)s":["Activer %(theme)s"],"Active":["Actif"],"Add":["Ajouter"],"Add %(layout)s":["Ajouter %(layout)s"],"Add %(name)s":["Ajouter %(name)s"],"Add %(type)s":["Ajouter %(type)s"],"Add Category":["Ajouter une catégorie"],"Add Content Type":["Ajouter un type de contenu"],"Add Field Group":["Ajouter un groupe de champs"],"Add Media File":["Ajouter un fichier média"],"Add Page":["Ajouter une page"],"Add Post":["Ajouter un article"],"Add User":["Ajouter un utilisateur"],"Add block":["Ajouter un bloc"],"Add choice":["Ajouter un choix"],"Add condition":["Ajouter une condition"],"Add field":["Ajouter un champ"],"Add field to %(field)s":["Ajouter un champ à %(field)s"],"Add layout":["Ajouter une disposition"],"Add layout to %(field)s":["Ajouter une disposition à %(field)s"],"Add one with %(button)s.":["Ajoutez un élément avec %(button)s."],"Add row":["Ajouter une ligne"],"Add rule set":["Ajouter un ensemble de règles"],"Add title":["Ajouter un titre"],"Add to %(field)s":["Ajouter à %(field)s"],"Address":["Adresse"],"Address updated.":["Adresse mise à jour."],"Adopt":["Adopter"],"Allow custom":["Autoriser les valeurs libres"],"Allow empty":["Autoriser le vide"],"Alt text":["Texte alternatif"],"An item cannot point at itself. Pick a different item for %(field)s.":["Un élément ne peut pas se viser lui-même. Choisissez un autre élément pour %(field)s."],"An item cannot sit inside itself, or inside one of the items nested under it. Pick a parent outside this branch.":["Un élément ne peut pas se trouver dans lui-même, ni dans un élément imbriqué sous lui. Choisissez un parent hors de cette branche."],"Another account wrote this, and only its author, an editor or an administrator may change it. You can still read it.":["Un autre compte a écrit ceci, et seuls son auteur, un éditeur ou un administrateur peuvent le modifier. Vous pouvez toujours le lire."],"Another account wrote this, so you are reading it rather than editing it.":["Un autre compte a écrit ceci, alors vous le lisez au lieu de le modifier."],"Another content type already answers under this route word. Pick a different word.":["Un autre type de contenu répond déjà sous ce mot de route. Choisissez un autre mot."],"Another content type already lives at the root of your site, and only one can. Give this type a route word, or hand the root over with Make default.":["Un autre type de contenu occupe déjà la racine de votre site, et un seul le peut. Donnez un mot de route à ce type, ou cédez la racine avec Rendre par défaut."],"Another content type already uses this key. Give this type a different name.":["Un autre type de contenu utilise déjà cette clé. Donnez un autre nom à ce type."],"Another item of this content type already uses that address. Pick a different slug and save again.":["Un autre élément de ce type de contenu utilise déjà cette adresse. Choisissez un autre slug et enregistrez de nouveau."],"Another update is currently in progress.":["Une autre mise à jour est actuellement en cours."],"Appears on":["Apparaît sur"],"Apply":["Appliquer"],"April":["avril"],"Are you sure you want to move \"%s\" to the trash?":["Voulez-vous vraiment déplacer « %s » dans la corbeille ?"],"Audio":["Audio"],"August":["août"],"Author":["Auteur/autrice"],"Back to %(type)s":["Retour aux %(type)s"],"Back to the latest posts":["Retour aux derniers articles"],"Block":["Bloc"],"Broken":["Cassé"],"Bundles of fields, shown where their rules place them.":["Ensembles de champs, affichés là où leurs règles les placent."],"Button group":["Groupe de boutons"],"Cancel":["Annuler"],"Caption":["Légende"],"Change %(name)s":["Modifier %(name)s"],"Change address":["Changer l'adresse"],"Change address…":["Changer l'adresse…"],"Change role":["Changer le rôle"],"Change the role of %(name)s":["Changer le rôle de %(name)s"],"Checkbox group":["Groupe de cases à cocher"],"Choices":["Choix"],"Choose %(field)s":["Choisir %(field)s"],"Choose how the site serves its content.":["Choisissez comment le site sert son contenu."],"Choose the language the admin reads in.":["Choisissez la langue dans laquelle se lit l'administration."],"Choose the role of %(name)s.":["Choisissez le rôle de %(name)s."],"Choose the version to update to.":["Choisissez la version vers laquelle mettre à jour."],"Clear %(field)s":["Vider %(field)s"],"Close":["Fermer"],"Close Settings":["Fermer les réglages"],"Closed":["Fermé"],"Condition":["Condition"],"Content":["Contenu"],"Content Types":["Types de contenu"],"Content nests at most %(max)s levels deep, and this item would sit deeper. Pick a parent closer to the top.":["Le contenu s'imbrique sur au plus %(max)s niveaux, et cet élément irait plus profond. Choisissez un parent plus proche du sommet."],"Content type":["Type de contenu"],"Content type updated.":["Type de contenu mis à jour."],"Could not load that post.":["Impossible de charger cet article."],"Could not save image. %s":["Impossible d’enregistrer le média. %s"],"Could not save media. %s":["Impossible d’enregistrer le média. %s"],"Could not save that post.":["Impossible d'enregistrer cet article."],"Create":["Créer"],"Create a field group":["Créer un groupe de champs"],"Create user":["Créer l'utilisateur"],"Created":["Date de création"],"Date added":["Date d’ajout"],"Date modified":["Date de modification"],"Deactivate":["Désactiver"],"Deactivate %(theme)s":["Désactiver %(theme)s"],"December":["décembre"],"Default":["Par défaut"],"Default content type updated.":["Type de contenu par défaut mis à jour."],"Definitions file":["Fichier de définitions"],"Delete":["Supprimer"],"Delete \"%(title)s\" for good? This cannot be undone.":["Supprimer « %(title)s » définitivement ? Cette action est irréversible."],"Delete %(field)s":["Supprimer %(field)s"],"Delete %(group)s":["Supprimer %(group)s"],"Delete %s content type for good? This cannot be undone.":["Supprimer %s type de contenu définitivement ? Cette action est irréversible.","Supprimer %s types de contenu définitivement ? Cette action est irréversible.","Supprimer %s types de contenu définitivement ? Cette action est irréversible."],"Delete %s item for good? This cannot be undone.":["Supprimer %s élément définitivement ? Cette action est irréversible.","Supprimer %s éléments définitivement ? Cette action est irréversible.","Supprimer %s éléments définitivement ? Cette action est irréversible."],"Delete permanently":["Supprimer définitivement"],"Delete the field":["Supprimer le champ"],"Delete the group":["Supprimer le groupe"],"Delete…":["Supprimer…"],"Describe":["Décrire"],"Describe the purpose of the image.":["Décrivez la fonction de l’image."],"Describe…":["Décrire…"],"Description":["Description"],"Description updated.":["Description mise à jour."],"Desktop":["Ordinateur"],"Destination":["Destination"],"Dimensions":["Dimensions"],"Disable":["Désactiver"],"Disable %(name)s":["Désactiver %(name)s"],"Disabled":["Désactivé"],"Dismiss":["Ignorer"],"Document":["Document"],"Documents":["Documents"],"Done. The site now holds what the file describes.":["Terminé. Le site contient maintenant ce que décrit le fichier."],"Draft saved.":["Brouillon enregistré."],"Drop files to upload":["Déposez vos fichiers pour les téléverser"],"Edit media":["Modifier le média"],"Edit…":["Modifier…"],"Email":["E-mail"],"Empty Trash":["Vider la corbeille"],"Empty trash":["Vider la corbeille"],"Enable":["Activer"],"Enable %(name)s":["Activer %(name)s"],"Every address of this type moves. Links kept elsewhere to the old addresses stop working.":["Toutes les adresses de ce type changent. Les liens conservés ailleurs vers les anciennes adresses cessent de fonctionner."],"Every content type":["Tous les types de contenu"],"Every field group needs a title. Give it a name and save again.":["Chaque groupe de champs a besoin d'un titre. Donnez-lui un nom et enregistrez à nouveau."],"Every item needs an author who exists. Pick one from the list and save again.":["Chaque élément a besoin d'un auteur existant. Choisissez-en un dans la liste et enregistrez de nouveau."],"Every kind of content this site holds.":["Toutes les sortes de contenu que ce site contient."],"Every value stored under this field goes with it, in every item the group reaches and in the revisions behind them.":["Toutes les valeurs enregistrées dans ce champ partent avec lui, dans chaque élément que le groupe atteint et dans les révisions qui les suivent."],"Excerpt":["Extrait"],"Export definitions":["Exporter les définitions"],"February":["février"],"Fewest files":["Minimum de fichiers"],"Fewest rows":["Minimum de lignes"],"Field":["Champ"],"Field Groups":["Groupes de champs"],"Field group":["Groupe de champs"],"Fields":["Champs"],"Fields of %(group)s":["Champs de %(group)s"],"File name":["Nom de fichier"],"File size":["Taille du fichier"],"File type":["Type de fichier"],"Filter by status":["Filtrer par état"],"Follow the browser":["Suivre le navigateur"],"From %(plugin)s":["De %(plugin)s"],"Full Size":["Taille originale"],"Gophenberg cannot start this update: %(reason)s":["Gophenberg ne peut pas lancer cette mise à jour : %(reason)s"],"Gophenberg checked for updates moments ago. Try again later.":["Gophenberg a cherché des mises à jour il y a un instant. Réessayez plus tard."],"Gophenberg could not read what your browser sent. Reload the page and try again, and tell whoever looks after your site if it keeps happening.":["Gophenberg n'a pas pu lire ce que votre navigateur a envoyé. Rechargez la page et réessayez, et prévenez la personne qui s'occupe de votre site si cela continue."],"Gophenberg could not read which item you picked as parent. Reload the page and pick it again.":["Gophenberg n'a pas pu lire quel élément vous avez choisi comme parent. Rechargez la page et choisissez-le de nouveau."],"Gophenberg does not accept %(extension)s files. Upload a picture, a video, an audio file, a PDF or a zip instead.":["Gophenberg n'accepte pas les fichiers %(extension)s. Téléversez plutôt une image, une vidéo, un fichier audio, un PDF ou un zip."],"Gophenberg does not answer in %(value)s. Pick one of the languages on the list.":["Gophenberg ne répond pas en %(value)s. Choisissez une des langues de la liste."],"Gophenberg has no autosave of yours for this item. Open the item to see the version that is stored.":["Gophenberg n'a aucun enregistrement automatique de vous pour cet élément. Ouvrez l'élément pour voir la version stockée."],"Gophenberg holds no kind of definition called %(subject)s, so nothing was taken over. Reload the page so the admin and the server agree again.":["Gophenberg ne connaît aucune sorte de définition nommée %(subject)s, rien n'a donc été repris. Rechargez la page pour que l'admin et le serveur se rejoignent à nouveau."],"Gophenberg keeps /%(path)s for itself or for another content type, so your content cannot answer there. Give the item a different slug.":["Gophenberg garde l'adresse /%(path)s pour lui ou pour un autre type de contenu, votre contenu ne peut donc pas y répondre. Donnez un autre slug à l'élément."],"Gophenberg keeps this word for itself, so no content type can answer under it. Pick a different route word.":["Gophenberg garde ce mot pour lui, aucun type de contenu ne peut donc répondre sous ce mot. Choisissez un autre mot de route."],"Group":["Groupe"],"Highest":["Maximum"],"Holds":["Contient"],"Images":["Images"],"Import definitions":["Importer les définitions"],"In list":["Dans la liste"],"Inactive":["Inactif"],"Installed":["Installé"],"Instructions":["Instructions"],"It moves here from another group and keeps its stored values.":["Il arrive ici depuis un autre groupe et garde ses valeurs enregistrées."],"It moves to another group and keeps its stored values.":["Il passe dans un autre groupe et garde ses valeurs enregistrées."],"It moves to another group, so its stored values do not follow.":["Il passe dans un autre groupe, donc ses valeurs enregistrées ne le suivent pas."],"It reads a relation inside a container, and only an import can point it elsewhere.":["Il lit une relation dans un conteneur, et seule une importation peut le faire pointer ailleurs."],"It starts on %(type)s, and the rules may be edited afterwards.":["Il commence sur %(type)s, et les règles peuvent être modifiées ensuite."],"Items could not be loaded.":["Les éléments n'ont pas pu être chargés."],"Its items sit inside one another, so it keeps nesting.":["Ses éléments se trouvent les uns dans les autres, donc il continue de s'imbriquer."],"Its kind changed, so its stored values go with it.":["Son type a changé, donc ses valeurs enregistrées partent avec lui."],"January":["janvier"],"July":["juillet"],"June":["juin"],"Keep %(field)s out of the list":["Garder %(field)s hors de la liste"],"Keep it":["Le conserver"],"Keep it here":["Le laisser ici"],"Key":["Clé"],"Label":["Libellé"],"Language":["Langue"],"Large":["Grande"],"Leave empty if decorative.":["Laissez vide si l’image est décorative"],"Let items nest":["Autoriser l'imbrication"],"Linked from":["Lié depuis"],"List view":["Vue en liste"],"Loading field groups.":["Chargement des groupes de champs."],"Loading the post.":["Chargement de l'article."],"Loading the screen.":["Chargement de l'écran."],"Loading themes.":["Chargement des thèmes."],"Loading users.":["Chargement des utilisateurs."],"Loading…":["Chargement…"],"Longest":["Longueur maximale"],"Lowest":["Minimum"],"Make %(field)s optional":["Rendre %(field)s facultatif"],"Make default":["Rendre par défaut"],"Make default…":["Rendre par défaut…"],"Make optional":["Rendre facultatif"],"Manage the categories on this site.":["Gérez les catégories de ce site."],"Manage the images and files this site holds.":["Gérez les images et les fichiers que ce site contient."],"Manage the items of this content type.":["Gérez les éléments de ce type de contenu."],"Manage the pages on this site.":["Gérez les pages de ce site."],"Manage the posts on this site.":["Gérez les articles de ce site."],"Many targets":["Plusieurs cibles"],"Many values":["Plusieurs valeurs"],"March":["mars"],"May":["mai"],"Media %(id)s":["Média %(id)s"],"Media Library":["Médiathèque"],"Media file updated.":["Fichier média mis à jour."],"Medium":["Moyenne"],"Mobile":["Mobile"],"Modified: %s":["Modifié : %s"],"Most files":["Maximum de fichiers"],"Most rows":["Maximum de lignes"],"Move":["Déplacer"],"Move \"%(title)s\" to the trash?":["Déplacer « %(title)s » dans la corbeille ?"],"Move %(field)s down":["Descendre %(field)s"],"Move %(field)s elsewhere":["Déplacer %(field)s ailleurs"],"Move %(field)s up":["Monter %(field)s"],"Move %(group)s down":["Descendre %(group)s"],"Move %(group)s up":["Monter %(group)s"],"Move %(name)s down":["Descendre %(name)s"],"Move %(name)s up":["Monter %(name)s"],"Move %s item to the trash?":["Déplacer %s élément dans la corbeille ?","Déplacer %s éléments dans la corbeille ?","Déplacer %s éléments dans la corbeille ?"],"Move every address":["Déplacer toutes les adresses"],"Move row down":["Descendre la ligne"],"Move row up":["Monter la ligne"],"Move the field":["Déplacer le champ"],"Move to trash":["Déplacer dans la corbeille"],"Name":["Nom"],"Name updated.":["Nom mis à jour."],"Nests":["Imbriqué"],"Newer posts":["Articles plus récents"],"No":["Non"],"No content types found.":["Aucun type de contenu trouvé."],"No description":["Aucune description"],"No file arrived with this upload. Choose a file and try again.":["Aucun fichier n'est arrivé avec ce téléversement. Choisissez un fichier et réessayez."],"No items found.":["Aucun élément trouvé."],"No items yet.":["Aucun élément pour l'instant."],"No media chosen":["Aucun média choisi"],"No media has been uploaded yet.":["Aucun média n'a encore été téléversé."],"No media items found.":["Aucun média n’a été trouvé."],"No media items yet.":["Aucun fichier média pour l’instant."],"No page lives at this address.":["Aucune page n'existe à cette adresse."],"No parent":["Pas de parent"],"No theme arrived with this upload. Choose a zip file and try again.":["Aucun thème n'est arrivé avec ce téléversement. Choisissez un fichier zip et réessayez."],"No themes are installed.":["Aucun thème n'est installé."],"No title":["Aucun titre"],"None":["Aucun"],"Not %(type)s":["Sauf %(type)s"],"Not found":["Introuvable"],"Not serving":["Hors service"],"Nothing declares that role.":["Rien ne déclare ce rôle."],"Nothing points here yet.":["Rien ne pointe encore ici."],"Nothing published here yet.":["Rien n'est encore publié ici."],"Nothing published yet.":["Rien n'est encore publié."],"November":["novembre"],"Nowhere":["Nulle part"],"Number":["Nombre"],"October":["octobre"],"Older posts":["Articles plus anciens"],"One frame of this animation holds more than %(max)s pixels, which is more than Gophenberg opens. Upload a smaller animation.":["Une image de cette animation dépasse %(max)s pixels, plus que ce que Gophenberg ouvre. Téléversez une animation plus petite."],"One of the filters on this list is not one Gophenberg understands. Clear the filters and try again.":["Un des filtres de cette liste n'est pas un filtre que Gophenberg comprend. Videz les filtres et réessayez."],"One of the items picked for %(field)s is not the kind of content that field points at. Reload the page and pick from the list the field offers.":["Un des éléments choisis pour %(field)s n'est pas le genre de contenu que vise ce champ. Rechargez la page et choisissez dans la liste que le champ propose."],"One of the items picked for %(field)s was not named in a way Gophenberg understands. Reload the page and pick the items again.":["Un des éléments choisis pour %(field)s n'était pas nommé d'une façon que Gophenberg comprend. Rechargez la page et choisissez de nouveau les éléments."],"One of the items picked no longer exists. Reload the page and pick again.":["Un des éléments choisis n'existe plus. Rechargez la page et choisissez de nouveau."],"One target":["Une cible"],"Only a relation field points at another content type or holds many items. Pick the Relation kind, or leave the target and the many option empty.":["Seul un champ de relation vise un autre type de contenu ou contient plusieurs éléments. Choisissez le genre Relation, ou laissez vides la cible et l'option plusieurs."],"Only one file may be placed here.":["Un seul fichier peut être placé ici."],"Only the content type at the root of your site may go without a route word. Give this type one and try again.":["Seul le type de contenu à la racine de votre site peut se passer de mot de route. Donnez-en un à ce type et réessayez."],"Open %(field)s in a new tab":["Ouvrir %(field)s dans un nouvel onglet"],"Order stored.":["Ordre enregistré."],"Other":["Autre"],"Out of list":["Hors de la liste"],"Parent":["Parent"],"Password":["Mot de passe"],"Pending":["En attente"],"Pending Review":["En attente de relecture"],"Permanently delete…":["Supprimer définitivement…"],"Picture quality":["Qualité d'image"],"Picture quality runs from 1 to %(max)s, so %(value)s is not a quality Gophenberg stores at. Pick a number inside that range.":["La qualité d'image va de 1 à %(max)s, donc %(value)s n'est pas une qualité avec laquelle Gophenberg enregistre. Choisissez un nombre dans cet intervalle."],"Placeholder":["Texte indicatif"],"Plural name":["Nom au pluriel"],"Points at":["Vise"],"Post published.":["Article publié."],"Posts per page":["Articles par page"],"Preview":["Prévisualiser"],"Private":["Privé"],"Publish":["Publier"],"Published: %s":["Publié : %s"],"Radio group":["Groupe de boutons radio"],"Reads from":["Lit depuis"],"Redo":["Rétablir"],"Relation":["Relation"],"Remove":["Retirer"],"Remove %(name)s":["Retirer %(name)s"],"Remove %(title)s":["Retirer %(title)s"],"Remove row":["Retirer la ligne"],"Rename":["Renommer"],"Rename %(field)s":["Renommer %(field)s"],"Rename…":["Renommer…"],"Require":["Rendre obligatoire"],"Require %(field)s":["Rendre %(field)s obligatoire"],"Required":["Obligatoire"],"Restore":["Rétablir"],"Role changed.":["Rôle modifié."],"Roll back to %(theme)s":["Revenir à %(theme)s"],"Roll back to the built-in renderer":["Revenir au moteur de rendu intégré"],"Route word":["Mot de route"],"Rule %(number)s of set %(set)s":["Règle %(number)s de l'ensemble %(set)s"],"Rule set %(number)s":["Ensemble de règles %(number)s"],"Rules":["Règles"],"Rules showing %(field)s":["Règles affichant %(field)s"],"Save":["Enregistrer"],"Save draft":["Enregistrer le brouillon"],"Save rules":["Enregistrer les règles"],"Save settings":["Enregistrer les réglages"],"Saved":["Enregistré"],"Saving":["Enregistrement"],"Scheduled":["Planifié"],"Scheduled: %s":["Planifié : %s"],"Search %(type)s…":["Rechercher des %(type)s…"],"Search audio":["Rechercher un audio"],"Search images":["Rechercher des images"],"Search media":["Rechercher des médias"],"Search videos":["Rechercher des vidéos"],"Select":["Sélectionner"],"September":["septembre"],"Serving":["En service"],"Settings":["Réglages"],"Settings of %(field)s":["Réglages de %(field)s"],"Shadowed":["Masqué"],"Show %(field)s in the list":["Afficher %(field)s dans la liste"],"Showing %(held)s of %(total)s.":["Affichage de %(held)s sur %(total)s."],"Singular name":["Nom au singulier"],"Slug":["Slug"],"Somebody must be able to manage users.":["Quelqu'un doit pouvoir gérer les utilisateurs."],"Someone else changed this media item while you were editing it. Reload the page and make your change again.":["Quelqu'un d'autre a modifié ce média pendant que vous le modifiiez. Rechargez la page et refaites votre modification."],"Someone else saved changes to this item while you were editing, so yours were not saved. Copy your text somewhere safe, then reload the item and put your changes back in.":["Quelqu'un d'autre a enregistré des modifications sur cet élément pendant que vous éditiez, les vôtres n'ont donc pas été enregistrées. Copiez votre texte en lieu sûr, puis rechargez l'élément et remettez vos modifications."],"Something went wrong inside Gophenberg. Try again in a moment, and tell whoever looks after your site if it keeps happening.":["Quelque chose a mal tourné dans Gophenberg. Réessayez dans un instant, et prévenez la personne qui s'occupe de votre site si cela continue."],"Something went wrong.":["Quelque chose a mal tourné."],"Something went wrong. Try again.":["Quelque chose a mal tourné. Réessayez."],"Sorry, you are not allowed to access this page.":["Désolé, vous n’avez pas l’autorisation d’accéder à cette page."],"Source":["Source"],"Steps of":["Pas de"],"Stop nesting":["Arrêter l'imbrication"],"Tablet":["Tablette"],"Text":["Texte"],"Text area":["Zone de texte"],"That email is already in use.":["Cet e-mail est déjà utilisé."],"That field group no longer exists. Reload the page to see the groups your site holds now.":["Ce groupe de champs n'existe plus. Rechargez la page pour voir les groupes que votre site contient maintenant."],"That field is not on this content type any more. Reload the page to see the fields it has now.":["Ce champ n'est plus sur ce type de contenu. Rechargez la page pour voir les champs qu'il possède maintenant."],"That revision does not exist, and older ones drop off once a type holds more than it keeps. Open the item to see which revisions are left.":["Cette révision n'existe pas, et les plus anciennes disparaissent quand un type en détient plus qu'il n'en conserve. Ouvrez l'élément pour voir les révisions restantes."],"That role holds more than your own.":["Ce rôle va au-delà du vôtre."],"That web address does not name a media item Gophenberg can look up. Open the media library and pick the item from there.":["Cette adresse web ne désigne aucun média que Gophenberg puisse trouver. Ouvrez la bibliothèque de médias et choisissez l'élément depuis là."],"That web address does not name a revision Gophenberg can look up. Open the item and pick a revision from its history.":["Cette adresse web ne désigne aucune révision que Gophenberg puisse trouver. Ouvrez l'élément et choisissez une révision dans son historique."],"That web address does not name an item Gophenberg can look up. Go back to the list and open the item from there.":["Cette adresse web ne désigne aucun élément que Gophenberg puisse trouver. Revenez à la liste et ouvrez l'élément depuis là."],"The %(count)s item in the trash is deleted for good. This cannot be undone.":["%(count)s élément de la corbeille est supprimé définitivement. Cette action est irréversible.","Les %(count)s éléments de la corbeille sont supprimés définitivement. Cette action est irréversible.","Les %(count)s éléments de la corbeille sont supprimés définitivement. Cette action est irréversible."],"The %(file)s calls this theme %(declared)s, but it is being installed as %(installed)s. Rename the zip file to match, or change the name inside %(file)s.":["Le fichier %(file)s appelle ce thème %(declared)s, mais il s'installe sous %(installed)s. Renommez le fichier zip pour qu'ils correspondent, ou changez le nom dans %(file)s."],"The %(file)s inside %(name)s is not valid JSON, so it could not be read. Fix that file and package the theme again.":["Le fichier %(file)s dans %(name)s n'est pas du JSON valide, il n'a donc pas pu être lu. Corrigez ce fichier et réempaquetez le thème."],"The %(file)s inside %(name)s names its theme kit as %(declared)s, which is not a version number. Build the theme again, and the build will fill that in.":["Le %(file)s dans %(name)s indique son kit de thèmes comme %(declared)s, ce qui n'est pas un numéro de version. Compilez le thème à nouveau et la compilation le renseignera."],"The %(origin)s plugin declared this, so it can only be changed in that plugin. Turning it off is still yours to do.":["L'extension %(origin)s l'a déclaré, donc il ne peut être modifié que dans cette extension. Le désactiver reste entre vos mains."],"The %(plugin)s plugin also declares %(name)s, and the site keeps the key.":["L'extension %(plugin)s déclare aussi %(name)s, et le site garde la clé."],"The %(plugin)s plugin declared these fields, so they change only in its code.":["L'extension %(plugin)s a déclaré ces champs, donc ils ne changent que dans son code."],"The %(plugin)s plugin declares %(name)s flat, and the site keeps it nesting while its items sit inside another.":["L'extension %(plugin)s déclare %(name)s sans imbrication, et le site continue de l'imbriquer tant que ses éléments se trouvent dans un autre."],"The browser kept an unsaved version of this post.":["Le navigateur a gardé une version non enregistrée de cet article."],"The built-in renderer is now serving the public site.":["Le moteur de rendu intégré sert désormais le site public."],"The built-in renderer is serving the public site.":["Le moteur de rendu intégré sert le site public."],"The content type this field points at is not named in a shape Gophenberg accepts. Give it a key that starts with a lowercase letter and then holds only lowercase letters, numbers and hyphens.":["Le type de contenu que vise ce champ n'est pas nommé sous une forme que Gophenberg accepte. Donnez-lui une clé qui commence par une lettre minuscule et ne contient ensuite que des lettres minuscules, des chiffres et des tirets."],"The content types could not be loaded, so where these groups appear and which fields they shadow are not shown.":["Les types de contenu n'ont pas pu être chargés, donc où ces groupes apparaissent et quels champs ils masquent ne sont pas affichés."],"The content types could not be loaded.":["Les types de contenu n'ont pas pu être chargés."],"The content types could not be refreshed, so where these groups appear and what they shadow may be out of date.":["Les types de contenu n'ont pas pu être actualisés, donc où ces groupes apparaissent et ce qu'ils masquent peut être obsolète."],"The draft could not be created.":["Le brouillon n'a pas pu être créé."],"The entry %(entry)s in this zip would be written outside the theme folder, so nothing was installed. Package the theme again.":["L'entrée %(entry)s de ce zip s'écrirait hors du dossier du thème, rien n'a donc été installé. Réempaquetez le thème."],"The field %(field)s cannot go, because %(by)s reads it. Change %(by)s first.":["Le champ %(field)s ne peut pas être retiré, car %(by)s le lit. Modifiez d'abord %(by)s."],"The field %(field)s cannot hold the value it was given. Check what kind of field it is and enter a value that matches.":["Le champ %(field)s ne peut pas contenir la valeur qui lui a été donnée. Vérifiez de quel genre de champ il s'agit et saisissez une valeur qui convient."],"The field %(field)s has to hold a value before this item can be published. Fill it in, or leave the item as a draft.":["Le champ %(field)s doit contenir une valeur avant que cet élément puisse être publié. Remplissez-le, ou laissez l'élément en brouillon."],"The field %(field)s in %(group)s still points at this content type. Delete that field first, then delete this type.":["Le champ %(field)s dans %(group)s vise encore ce type de contenu. Supprimez d'abord ce champ, puis supprimez ce type."],"The field %(field)s is hidden by its own rules right now, so it cannot hold a value. Show it again before filling it in.":["Le champ %(field)s est masqué par ses propres règles pour le moment, il ne peut donc contenir aucune valeur. Affichez-le de nouveau avant de le remplir."],"The field %(field)s points at one item only. Remove the extra choices and keep one.":["Le champ %(field)s ne vise qu'un seul élément. Retirez les choix en trop et gardez-en un."],"The field %(field)s points at other items, so it does not take a plain value. Pick the items it points at instead.":["Le champ %(field)s vise d'autres éléments, il n'accepte donc pas une valeur simple. Choisissez plutôt les éléments qu'il vise."],"The field %(field)s takes a list of items, and what arrived was not a list. Reload the page and pick the items again.":["Le champ %(field)s attend une liste d'éléments, et ce qui est arrivé n'était pas une liste. Rechargez la page et choisissez de nouveau les éléments."],"The field %(source)s cannot hold the value %(value)s, so no rule can compare it. Write a value of the kind %(source)s stores.":["Le champ %(source)s ne peut pas contenir la valeur %(value)s, aucune règle ne peut donc la comparer. Écrivez une valeur du type que %(source)s enregistre."],"The field groups could not be loaded.":["Les groupes de champs n'ont pas pu être chargés."],"The field groups could not be reached.":["Les groupes de champs n'ont pas pu être joints."],"The field keeps its values on the content both groups reach.":["Le champ garde ses valeurs sur le contenu que les deux groupes atteignent."],"The fields this group holds go with it, and so do the values every item stored in them.":["Les champs que ce groupe contient partent avec lui, ainsi que les valeurs que chaque élément y a enregistrées."],"The groups were reordered.":["Les groupes ont été réordonnés."],"The item could not be duplicated.":["L'élément n'a pas pu être dupliqué."],"The item could not be moved to the trash.":["L'élément n'a pas pu être déplacé dans la corbeille."],"The item could not be permanently deleted.":["L'élément n'a pas pu être supprimé définitivement."],"The item could not be restored.":["L'élément n'a pas pu être rétabli."],"The item you picked as parent holds another kind of content. Pick a parent of the same content type as this item.":["L'élément que vous avez choisi comme parent contient un autre genre de contenu. Choisissez un parent du même type de contenu que cet élément."],"The item you picked as parent is in the trash. Restore it, or pick another parent.":["L'élément que vous avez choisi comme parent est dans la corbeille. Rétablissez-le, ou choisissez un autre parent."],"The item you picked as parent no longer exists. Reload the page and pick another parent.":["L'élément que vous avez choisi comme parent n'existe plus. Rechargez la page et choisissez un autre parent."],"The media library could not be loaded.":["La bibliothèque de médias n'a pas pu être chargée."],"The name changes. Nothing stored under this field moves.":["Le nom change. Rien de ce qui est stocké sous ce champ ne bouge."],"The name could not be updated.":["Le nom n'a pas pu être mis à jour."],"The new order has to name every field group exactly once. Reload the page and move the groups again.":["Le nouvel ordre doit nommer chaque groupe de champs exactement une fois. Rechargez la page et déplacez les groupes à nouveau."],"The new order has to name every field of this content type exactly once. Reload the page and move the fields again.":["Le nouvel ordre doit nommer chaque champ de ce type de contenu exactement une fois. Rechargez la page et déplacez les champs à nouveau."],"The number of revisions to keep has to be a whole number, and it cannot be negative. Enter a different number.":["Le nombre de révisions à conserver doit être un nombre entier, et il ne peut pas être négatif. Saisissez un autre nombre."],"The registry could not be reached.":["Le registre n'a pas pu être joint."],"The role could not be changed.":["Le rôle n'a pas pu être modifié."],"The rule on %(source)s names nothing to match. Pick a value, or remove the rule.":["La règle sur %(source)s ne nomme rien à faire correspondre. Choisissez une valeur, ou retirez la règle."],"The rules could not be loaded.":["Les règles n'ont pas pu être chargées."],"The rules on %(field)s lead back to %(field)s itself, so nothing can decide whether to show it. Point one of them at another field.":["Les règles de %(field)s reviennent à %(field)s lui-même, rien ne peut donc décider de l'afficher. Faites pointer l'une d'elles vers un autre champ."],"The same item was picked twice for %(field)s. Pick each item once.":["Le même élément a été choisi deux fois pour %(field)s. Choisissez chaque élément une seule fois."],"The server could not be reached, so nothing was changed.":["Le serveur n'a pas pu être joint, rien n'a donc été changé."],"The server could not be reached, so nothing was saved.":["Le serveur n'a pas pu être joint, rien n'a donc été enregistré."],"The server could not be reached, so nothing was uploaded.":["Le serveur n'a pas pu être joint, rien n'a donc été téléversé."],"The setting %(setting)s cannot hold the value it was given. Check what this setting takes and try again.":["Le réglage %(setting)s ne peut pas contenir la valeur donnée. Vérifiez ce que ce réglage accepte et réessayez."],"The setting %(setting)s falls outside the others. Keep min below max and the default inside the bounds.":["Le réglage %(setting)s sort des autres. Gardez min sous max et la valeur par défaut dans les limites."],"The settings could not be read, so nothing can be changed here yet.":["Les réglages n'ont pas pu être lus, donc rien ne peut encore être modifié ici."],"The site default":["La langue par défaut du site"],"The site may already hold part of this file. Import it again to see what is left.":["Le site contient peut-être déjà une partie de ce fichier. Importez-le à nouveau pour voir ce qu'il reste."],"The source %(source)s does not offer %(operator)s. Pick one of the comparisons it does offer.":["La source %(source)s n'offre pas %(operator)s. Choisissez une des comparaisons qu'elle offre."],"The theme %(name)s carries no %(file)s, so Gophenberg cannot tell what it is. Put that file at the top level of the zip and package the theme again.":["Le thème %(name)s ne contient aucun %(file)s, Gophenberg ne peut donc pas savoir ce que c'est. Placez ce fichier au premier niveau du zip et réempaquetez le thème."],"The theme %(name)s could not be read, so it cannot serve your site. Upload it again, or choose another theme.":["Le thème %(name)s n'a pas pu être lu, il ne peut donc pas servir votre site. Téléversez-le de nouveau, ou choisissez un autre thème."],"The theme %(name)s did not start, so your site is still served by the theme it had. Ask whoever looks after your site to check the server log for what the theme reported.":["Le thème %(name)s n'a pas démarré, votre site est donc toujours servi par le thème qu'il avait. Demandez à la personne qui s'occupe de votre site de regarder ce que le thème a signalé dans le journal du serveur."],"The theme %(name)s does not carry %(path)s as a file, so there is nothing to run. Package the built theme rather than its source.":["Le thème %(name)s ne contient pas %(path)s comme fichier, il n'y a donc rien à exécuter. Empaquetez le thème construit plutôt que sa source."],"The theme %(name)s does not carry %(path)s as a folder, so its styles and scripts are missing. Package the built theme rather than its source.":["Le thème %(name)s ne contient pas %(path)s comme dossier, ses styles et ses scripts manquent donc. Empaquetez le thème construit plutôt que sa source."],"The theme %(name)s holds a link to another file at %(path)s, and a theme may only carry real files. Replace it and package the theme again.":["Le thème %(name)s contient un lien vers un autre fichier à %(path)s, et un thème ne peut contenir que de vrais fichiers. Remplacez-le et réempaquetez le thème."],"The theme %(name)s is serving your site right now, so it cannot be replaced. Deactivate it first, or install this copy under another name.":["Le thème %(name)s sert votre site en ce moment, il ne peut donc pas être remplacé. Désactivez-le d'abord, ou installez cette copie sous un autre nom."],"The theme %(name)s is the one chosen, but it is not installed, so your site is served by the built-in renderer. Upload the theme again, or choose another one.":["Le thème %(name)s est celui choisi, mais il n'est pas installé, votre site est donc servi par le moteur de rendu intégré. Téléversez de nouveau le thème, ou choisissez-en un autre."],"The theme %(name)s was built on theme kit %(declared)s, and this site serves %(served)s. Build the theme again against a kit this site serves, then install it.":["Le thème %(name)s a été compilé avec le kit de thèmes %(declared)s, et ce site sert %(served)s. Compilez le thème à nouveau avec un kit que ce site sert, puis installez-le."],"The trash could not be emptied.":["La corbeille n'a pas pu être vidée."],"The user could not be created.":["L'utilisateur n'a pas pu être créé."],"The values stored under it do not follow.":["Les valeurs enregistrées dessous ne le suivent pas."],"Theme":["Thème"],"Themes":["Thèmes"],"Themes could not be loaded.":["Les thèmes n'ont pas pu être chargés."],"There is no content type called %(value)s. Pick a type your site holds, or register it first.":["Il n'existe aucun type de contenu appelé %(value)s. Choisissez un type que votre site possède, ou déclarez-le d'abord."],"There is no content type called %(value)s. Pick one of the types your site holds and try again.":["Il n'existe aucun type de contenu appelé %(value)s. Choisissez un des types que votre site possède et réessayez."],"There is no kind of field called %(value)s. Pick one of these instead: %(allowed)s.":["Il n'existe aucun genre de champ appelé %(value)s. Choisissez plutôt parmi ceux-ci : %(allowed)s."],"There is no page kind called %(value)s. Pick one of these instead: %(allowed)s.":["Il n'existe aucun genre de page appelé %(value)s. Choisissez plutôt parmi ceux-ci : %(allowed)s."],"There is no status called %(value)s. Pick one of these instead: %(allowed)s.":["Il n'existe aucun état appelé %(value)s. Choisissez plutôt parmi ceux-ci : %(allowed)s."],"There is nothing at this address. Check the link and try again.":["Il n'y a rien à cette adresse. Vérifiez le lien et réessayez."],"There is nothing to roll back to, because your site has not been through a theme change yet. Install a theme first, then a rollback has somewhere to go.":["Il n'y a rien vers quoi revenir, car votre site n'a pas encore changé de thème. Installez d'abord un thème, et le retour aura alors une destination."],"These files could not be read.":["Ces fichiers n'ont pas pu être lus."],"These were left alone, because nobody confirmed losing them.":["Ceux-ci ont été laissés tels quels, car personne n'a confirmé leur perte."],"This content type does not exist any more. Reload the page to see the types your site holds now.":["Ce type de contenu n'existe plus. Rechargez la page pour voir les types que votre site possède maintenant."],"This content type does not nest, so one of its items cannot sit inside another. Mark the type as Nests first.":["Ce type de contenu ne s'imbrique pas, un de ses éléments ne peut donc pas se trouver dans un autre. Marquez d'abord le type comme Imbriqué."],"This content type has no field called %(field)s. Check the name, or declare the field on the type first.":["Ce type de contenu n'a aucun champ appelé %(field)s. Vérifiez le nom, ou déclarez d'abord le champ sur le type."],"This content type is turned off, so its content is not served or edited. Activate it first.":["Ce type de contenu est désactivé, son contenu n'est donc ni servi ni modifié. Activez-le d'abord."],"This content type still holds content, so it cannot be deleted. Move or delete its items first.":["Ce type de contenu contient encore du contenu, il ne peut donc pas être supprimé. Déplacez ou supprimez d'abord ses éléments."],"This definitions file is larger than the %(max)s bytes Gophenberg reads in one request. Split it, or raise the limit your site runs with.":["Ce fichier de définitions dépasse les %(max)s octets que Gophenberg lit en une requête. Divisez-le, ou relevez la limite de votre site."],"This field holds no layouts yet.":["Ce champ ne contient pas encore de dispositions."],"This field would stand inside too many containers. Put it nearer the top and try again.":["Ce champ se trouverait dans trop de conteneurs. Placez-le plus près du niveau supérieur et réessayez."],"This file could not be opened as a zip. Package the theme again and upload the new file.":["Ce fichier n'a pas pu être ouvert comme zip. Réempaquetez le thème et téléversez le nouveau fichier."],"This file is larger than the upload limit. Upload a smaller file.":["Ce fichier dépasse la limite de téléversement. Téléversez un fichier plus petit."],"This file is named %(extension)s but it holds %(detected)s content. Upload it under a name that matches what is inside it.":["Ce fichier est nommé %(extension)s mais il contient du %(detected)s. Téléversez-le sous un nom qui correspond à ce qu'il contient."],"This file matches the site, so there is nothing to change.":["Ce fichier correspond au site, il n'y a donc rien à changer."],"This file says it was written in format %(declared)s, which is not a version Gophenberg can read. Export the definitions again from the site they came from.":["Ce fichier indique le format %(declared)s, qui n'est pas une version que Gophenberg sait lire. Exportez à nouveau les définitions depuis le site d'origine."],"This file was written in format %(declared)s, and this release reads %(served)s. Upgrade the site the file came from, or this one.":["Ce fichier est écrit au format %(declared)s, et cette version lit %(served)s. Mettez à jour le site d'origine du fichier, ou celui-ci."],"This group holds no fields yet.":["Ce groupe ne contient pas encore de champs."],"This install of Gophenberg has no install root, so it updates by hand.":["Cette installation de Gophenberg n'a pas de racine d'installation, elle se met donc à jour à la main."],"This is a custom build of Gophenberg, so it updates by hand.":["Il s'agit d'une version compilée sur mesure de Gophenberg, elle se met donc à jour à la main."],"This item cannot go straight to that status from the one it holds now. Save it as a draft first, then try again.":["Cet élément ne peut pas passer directement à cet état depuis celui qu'il a maintenant. Enregistrez-le d'abord comme brouillon, puis réessayez."],"This item does not exist, and it may have been deleted. Go back to the list to see what is there.":["Cet élément n'existe pas, et il a peut-être été supprimé. Revenez à la liste pour voir ce qui s'y trouve."],"This item is already in the trash. Restore it first to work on it again.":["Cet élément est déjà dans la corbeille. Rétablissez-le d'abord pour y retravailler."],"This item is in the trash. Restore it first to work on it again.":["Cet élément est dans la corbeille. Rétablissez-le d'abord pour y retravailler."],"This item is not in the trash, so there is nothing to restore. Open it from the list to work on it as it is.":["Cet élément n'est pas dans la corbeille, il n'y a donc rien à rétablir. Ouvrez-le depuis la liste pour travailler dessus tel quel."],"This item still holds items nested inside it. Move or delete those first.":["Cet élément contient encore des éléments imbriqués. Déplacez-les ou supprimez-les d'abord."],"This kind of field holds no fields inside it. Put the field in a section or a repeater instead.":["Ce type de champ ne contient aucun champ. Placez le champ dans une section ou dans un répéteur."],"This media item is not in the library, and someone may have deleted it. Reload the page to see what is there now.":["Ce média n'est pas dans la bibliothèque, et quelqu'un l'a peut-être supprimé. Rechargez la page pour voir ce qui s'y trouve maintenant."],"This picture could not be read, so nothing was stored. The file may be damaged, so open it on your computer and upload it again.":["Cette image n'a pas pu être lue, rien n'a donc été stocké. Le fichier est peut-être endommagé, ouvrez-le sur votre ordinateur et téléversez-le de nouveau."],"This picture is %(width)s by %(height)s pixels, over the limit of %(max)s pixels in all. Make it smaller and upload it again.":["Cette image fait %(width)s par %(height)s pixels, au-delà de la limite de %(max)s pixels au total. Réduisez-la et téléversez-la de nouveau."],"This post changed elsewhere. Reload before saving again.":["Cet article a changé ailleurs. Rechargez avant d'enregistrer de nouveau."],"This request came from a page on another site, so it was refused. Open the admin on this site and try again.":["Cette requête vient d'une page d'un autre site, elle a donc été refusée. Ouvrez l'administration sur ce site et réessayez."],"This request carried %(attribute)s, which fields do not take. Reload the page so the admin and the server agree again.":["Cette requête portait %(attribute)s, que les champs n'acceptent pas. Rechargez la page pour que l'administration et le serveur concordent à nouveau."],"This request left out %(field)s, which Gophenberg needs. Reload the page and try again.":["Cette requête a omis %(field)s, dont Gophenberg a besoin. Rechargez la page et réessayez."],"This rule reads a source called %(source)s, and nothing on your site declares one. A plugin that added it may have been removed.":["Cette règle lit une source nommée %(source)s, et rien sur votre site n'en déclare. Une extension qui l'ajoutait a pu être retirée."],"This site cannot write to its themes folder, so no theme can be installed. Ask whoever looks after your site to make the folder that %(setting)s points at writable. A read-only mount is the usual cause.":["Ce site ne peut pas écrire dans son dossier de thèmes, aucun thème ne peut donc être installé. Demandez à la personne qui s'occupe de votre site de rendre accessible en écriture le dossier vers lequel pointe %(setting)s. Un montage en lecture seule en est la cause habituelle."],"This site has nowhere to keep themes, so no theme can be installed. Ask whoever looks after your site to point %(setting)s at a folder the server can write to.":["Ce site n'a nulle part où garder les thèmes, aucun thème ne peut donc être installé. Demandez à la personne qui s'occupe de votre site de faire pointer %(setting)s vers un dossier où le serveur peut écrire."],"This site has nowhere to store uploads, so nothing can be uploaded. Ask whoever looks after your site to point %(setting)s at a folder the server can write to.":["Ce site n'a nulle part où stocker les téléversements, rien ne peut donc être téléversé. Demandez à la personne qui s'occupe de votre site de faire pointer %(setting)s vers un dossier où le serveur peut écrire."],"This theme is over the limit of %(max)s bytes, packed or unpacked. Leave out what the theme does not need and package it again.":["Ce thème dépasse la limite de %(max)s octets, compressé ou non. Retirez ce dont le thème n'a pas besoin et réempaquetez-le."],"This type will answer under /%(word)s.":["Ce type répondra sous /%(word)s."],"This zip holds %(entries)s files, more than the %(max)s a theme may carry. Package only the built theme.":["Ce zip contient %(entries)s fichiers, plus que les %(max)s qu'un thème peut contenir. Empaquetez seulement le thème construit."],"Through":["Via"],"Thumbnail":["Miniature"],"Title":["Titre"],"Two field groups in this file share the key %(key)s. Give one of them a different key and import again.":["Deux groupes de champs de ce fichier partagent la clé %(key)s. Donnez une clé différente à l'un d'eux et importez à nouveau."],"Two rule sources are registered under the name %(param)s. A plugin is declaring a source your site already holds.":["Deux sources de règles sont enregistrées sous le nom %(param)s. Une extension déclare une source que votre site possède déjà."],"Type":["Type"],"Type a whole number in both boxes before saving.":["Saisissez un nombre entier dans les deux cases avant d'enregistrer."],"Undo":["Annuler"],"Unsaved changes":["Modifications non enregistrées"],"Update":["Mettre à jour"],"Update failed.":["La mise à jour a échoué."],"Upload theme":["Téléverser un thème"],"Uploaded %s file.":["%s fichier téléversé.","%s fichiers téléversés.","%s fichiers téléversés."],"Users":["Utilisateurs"],"Users could not be loaded.":["Les utilisateurs n'ont pas pu être chargés."],"Value":["Valeur"],"Version":["Version"],"Videos":["Vidéos"],"Visit Site":["Aller sur le site"],"Web address":["Adresse web"],"What each Linked from field reads":["Ce que lit chaque champ Lié depuis"],"What it points at changed, so its stored values go with it.":["Ce qu'il vise a changé, donc ses valeurs enregistrées partent avec lui."],"Where %(group)s appears":["Où apparaît %(group)s"],"Without a rule this field always shows.":["Sans aucune règle ce champ s'affiche toujours."],"Without a rule this group appears nowhere.":["Sans une règle ce groupe n'apparaît nulle part."],"Yes":["Oui"],"Yes or no":["Oui ou non"],"You cannot change your own role.":["Vous ne pouvez pas changer votre propre rôle."],"Your language":["Votre langue"],"Your role does not allow %(capability)s.":["Votre rôle ne permet pas %(capability)s."],"Your server pins the site to the theme %(name)s, so themes cannot be changed here. Ask whoever looks after your site to remove the pin.":["Votre serveur fixe le site au thème %(name)s, les thèmes ne peuvent donc pas être changés ici. Demandez à la personne qui s'occupe de votre site de retirer cette fixation."],"Your site always needs one default content type, so this one cannot be turned off or deleted. Make another type the default first.":["Votre site a toujours besoin d'un type de contenu par défaut, celui-ci ne peut donc être ni désactivé ni supprimé. Rendez d'abord un autre type par défaut."],"a content type":["un type de contenu"],"account\u0004Role":["Rôle"],"account\u0004Status":["État"],"action label\u0004Duplicate":["Dupliquer"],"action label\u0004Duplicate…":["Dupliquer…"],"address":["adresse"],"admin section\u0004Content Types":["Types de contenu"],"admin section\u0004Field Groups":["Groupes de champs"],"admin section\u0004Language":["Langue"],"admin section\u0004Media":["Médias"],"admin section\u0004Settings":["Réglages"],"admin section\u0004Themes":["Thèmes"],"column\u0004Date":["Date"],"content type\u0004\"%s\" permanently deleted.":["Type de contenu « %s » supprimé définitivement."],"content type\u0004\"%s\" successfully created.":["Type de contenu « %s » créé avec succès."],"content type\u0004Status":["État"],"field\u0004Name":["Nom"],"field group\u0004Status":["Statut"],"field type\u0004Choice":["Choix"],"field type\u0004Color":["Couleur"],"field type\u0004Date":["Date"],"field type\u0004Flexible content":["Contenu flexible"],"field type\u0004Gallery":["Galerie"],"field type\u0004Kind":["Genre"],"field type\u0004Layout":["Disposition"],"field type\u0004Link":["Lien"],"field type\u0004Media":["Média"],"field type\u0004Range":["Plage"],"field type\u0004Repeater":["Répéteur"],"field type\u0004Section":["Section"],"field type\u0004Select":["Liste déroulante"],"file size\u0004%1$s %2$s":["%1$s %2$s"],"file type group\u0004Archives":["Archives"],"file type group\u0004Audio":["Sons"],"file type group\u0004Video":["Vidéos"],"holds":["contient"],"holds anything":["contient quelque chose"],"https://www.w3.org/WAI/tutorials/images/decision-tree/":["https://www.w3.org/WAI/tutorials/images/decision-tree/"],"image dimensions\u0004%1$s × %2$s":["%1$s par %2$s"],"is":["est"],"is above":["est supérieur à"],"is below":["est inférieur à"],"is empty":["est vide"],"is not":["n'est pas"],"panel button label\u0004Settings":["Réglages"],"person\u0004Name":["Nom"],"post\u0004%s (Copy)":["%s (copie)"],"post\u0004Status":["État"],"post status\u0004Draft":["Brouillon"],"post status\u0004Published":["Publié"],"post status\u0004Trash":["Corbeille"],"post type general name\u0004Pages":["Pages"],"post type general name\u0004Posts":["Articles"],"post type singular name\u0004Page":["Page"],"post type singular name\u0004Post":["Article"],"relation target\u0004None":["Aucun"],"role\u0004Administrator":["Administrateur"],"role\u0004Author":["Auteur"],"role\u0004Editor":["Éditeur"],"role\u0004Member":["Membre"],"role\u0004No role":["Sans rôle"],"status filter\u0004All":["Tout"],"taxonomy general name\u0004Categories":["Catégories"],"taxonomy singular name\u0004Category":["Catégorie"],"theme\u0004Status":["État"],"trash\u0004Restore":["Rétablir"],"unit symbol\u0004B":["o"],"unit symbol\u0004EB":["Eo"],"unit symbol\u0004GB":["Go"],"unit symbol\u0004KB":["Ko"],"unit symbol\u0004MB":["Mo"],"unit symbol\u0004PB":["Po"],"unit symbol\u0004TB":["To"],"unit symbol\u0004YB":["Yo"],"unit symbol\u0004ZB":["Zo"],"v%(version)s":["v%(version)s"],"verb\u0004Trash…":["Mettre à la corbeille…"],"verb\u0004View":["Voir"],"{day} {month} {year}":["{day} {month} {year}"]} +{"":{"lang":"fr","plural-forms":"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"}," and ":[" et "]," or ":[" ou "],"\"%s\" activated.":["Type de contenu « %s » activé."],"\"%s\" deactivated.":["Type de contenu « %s » désactivé."],"\"%s\" has been restored.":["« %s » a été rétabli."],"\"%s\" moved to the trash.":["« %s » déplacé dans la corbeille."],"\"%s\" permanently deleted.":["Suppression définitive de « %s »."],"\"%s\" successfully created.":["« %s » créé avec succès."],"\"%s\" uploaded.":["« %s » téléversé."],"%(field)s address":["Adresse de %(field)s"],"%(field)s cannot move inside itself. Pick a container that is not one of its own.":["%(field)s ne peut pas être déplacé à l'intérieur de lui-même. Choisissez un conteneur qui n'est pas l'un des siens."],"%(field)s declared.":["%(field)s déclaré."],"%(field)s deleted.":["%(field)s supprimé."],"%(field)s does not match the format its field asks for. Check it and save again.":["%(field)s ne respecte pas le format demandé par son champ. Vérifiez-le et enregistrez de nouveau."],"%(field)s goes no higher than %(limit)s. Lower the value and save again.":["%(field)s ne dépasse pas %(limit)s. Baissez la valeur et enregistrez de nouveau."],"%(field)s goes no lower than %(limit)s. Raise the value and save again.":["%(field)s ne descend pas sous %(limit)s. Augmentez la valeur et enregistrez de nouveau."],"%(field)s holds no value of its own, so it cannot be required. Make it optional.":["%(field)s ne contient aucune valeur propre, il ne peut donc pas être obligatoire. Rendez-le facultatif."],"%(field)s is optional again.":["%(field)s est de nouveau facultatif."],"%(field)s is required now.":["%(field)s est maintenant obligatoire."],"%(field)s moved.":["%(field)s déplacé."],"%(field)s names the same one twice. Remove the repeat and save again.":["%(field)s nomme le même deux fois. Retirez la répétition et enregistrez de nouveau."],"%(field)s needs at least %(limit)s files. Add one and save again.":["%(field)s demande au moins %(limit)s fichiers. Ajoutez-en un et enregistrez."],"%(field)s needs at least %(limit)s rows. Add one and save again.":["%(field)s demande au moins %(limit)s lignes. Ajoutez-en une et enregistrez."],"%(field)s only takes one of its listed choices. Pick one and save again.":["%(field)s accepte uniquement un des choix de sa liste. Choisissez-en un et enregistrez de nouveau."],"%(field)s reads a relation field that is not there. Pick a group and a relation field it holds.":["%(field)s lit un champ de relation qui n'existe pas. Choisissez un groupe et un champ de relation qu'il contient."],"%(field)s reads a relation pointing at %(type)s, so it would list nothing here. Pick a relation pointing at the items this group is shown on.":["%(field)s lit une relation qui pointe vers %(type)s, elle n'afficherait donc rien ici. Choisissez une relation qui pointe vers les éléments où ce groupe s'affiche."],"%(field)s renamed.":["%(field)s renommé."],"%(field)s settled.":["%(field)s réglé."],"%(field)s shows by its rules now.":["%(field)s s'affiche désormais selon ses règles."],"%(field)s stands in the list.":["%(field)s figure dans la liste."],"%(field)s stays out of the list.":["%(field)s reste hors de la liste."],"%(field)s takes at most %(limit)s files. Remove one and save again.":["%(field)s accepte au plus %(limit)s fichiers. Retirez-en un et enregistrez."],"%(field)s takes at most %(limit)s letters. Shorten what you wrote and save again.":["%(field)s accepte au plus %(limit)s lettres. Raccourcissez ce que vous avez écrit et enregistrez de nouveau."],"%(field)s takes at most %(limit)s rows. Remove one and save again.":["%(field)s accepte au plus %(limit)s lignes. Retirez-en une et enregistrez."],"%(field)s title":["Titre de %(field)s"],"%(file)s is larger than one upload may be.":["%(file)s dépasse la taille maximale d'un téléversement."],"%(file)s is not a file this block accepts.":["%(file)s n'est pas un fichier que ce bloc accepte."],"%(file)s: %(reason)s":["%(file)s : %(reason)s"],"%(group)s created.":["%(group)s créé."],"%(group)s now appears where you said.":["%(group)s apparaît maintenant là où vous avez dit."],"%(group)s removed.":["%(group)s supprimé."],"%(group)s updated.":["%(group)s mis à jour."],"%(key)s is served by %(winner)s, so %(loser)s does not show it on %(where)s.":["%(key)s est servi par %(winner)s, donc %(loser)s ne le montre pas sur %(where)s."],"%(name)s %(version)s is serving the public site.":["%(name)s %(version)s sert le site public."],"%(name)s belongs to the site now.":["%(name)s appartient désormais au site."],"%(name)s came from the %(plugin)s plugin, which no longer declares it.":["%(name)s venait de l'extension %(plugin)s, qui ne le déclare plus."],"%(name)s cannot be used as a theme name. Name the zip file after the theme, with no dot at the start and no slashes in it.":["%(name)s ne peut pas servir de nom de thème. Nommez le fichier zip comme le thème, sans point au début et sans barre oblique."],"%(name)s moves to /%(word)s. Every address of both types changes.":["Le type %(name)s passe à /%(word)s. Toutes les adresses des deux types changent."],"%(name)s would move to /%(word)s, which Gophenberg keeps for itself. Change its plural name and try again.":["Le type %(name)s passerait à /%(word)s, que Gophenberg garde pour lui. Modifiez son nom au pluriel et réessayez."],"%(source)s is %(value)s":["%(source)s est %(value)s"],"%(theme)s failed to start, so the built-in renderer is serving.":["%(theme)s n'a pas pu démarrer, le moteur de rendu intégré sert donc le site."],"%(theme)s is now serving the public site.":["%(theme)s sert désormais le site public."],"%(theme)s is serving the public site.":["%(theme)s sert le site public."],"%(theme)s is still starting, so the built-in renderer is serving.":["%(theme)s démarre encore, le moteur de rendu intégré sert donc le site."],"%(theme)s was installed.":["%(theme)s a été installé."],"%(theme)s will not load, so the built-in renderer is serving.":["%(theme)s ne se charge pas, le moteur de rendu intégré sert donc le site."],"%(type)s answers on a new address, and stored links move with it.":["%(type)s répond à une nouvelle adresse, et les liens enregistrés la suivent."],"%(type)s becomes the type the site opens on, and the old one takes an address.":["%(type)s devient le type sur lequel le site ouvre, et l'ancien prend une adresse."],"%(type)s keeps nesting while %(items)s of its items sit inside another. Move those to the top level first, the ones in the trash included.":["%(type)s continue de s'imbriquer tant que %(items)s de ses éléments se trouvent dans un autre. Déplacez-les d'abord au niveau supérieur, ceux de la corbeille compris."],"%(type)s keeps nesting, because some of its items sit inside another.":["%(type)s continue de s'imbriquer, car certains de ses éléments se trouvent dans un autre."],"%(type)s will answer at the root.":["Le type %(type)s répondra à la racine."],"%s content type activated.":["%s type de contenu activé.","%s types de contenu activés.","%s types de contenu activés."],"%s content type could not be activated.":["%s type de contenu n'a pas pu être activé.","%s types de contenu n'ont pas pu être activés.","%s types de contenu n'ont pas pu être activés."],"%s content type could not be deactivated.":["%s type de contenu n'a pas pu être désactivé.","%s types de contenu n'ont pas pu être désactivés.","%s types de contenu n'ont pas pu être désactivés."],"%s content type could not be permanently deleted.":["%s type de contenu n'a pas pu être supprimé définitivement.","%s types de contenu n'ont pas pu être supprimés définitivement.","%s types de contenu n'ont pas pu être supprimés définitivement."],"%s content type deactivated.":["%s type de contenu désactivé.","%s types de contenu désactivés.","%s types de contenu désactivés."],"%s content type permanently deleted.":["%s type de contenu supprimé définitivement.","%s types de contenu supprimés définitivement.","%s types de contenu supprimés définitivement."],"%s day":["%s jour","%s jours","%s jours"],"%s hour":["%s heure","%s heures","%s heures"],"%s item could not be moved to the trash.":["%s élément n'a pas pu être déplacé dans la corbeille.","%s éléments n'ont pas pu être déplacés dans la corbeille.","%s éléments n'ont pas pu être déplacés dans la corbeille."],"%s item could not be permanently deleted.":["%s élément n'a pas pu être supprimé définitivement.","%s éléments n'ont pas pu être supprimés définitivement.","%s éléments n'ont pas pu être supprimés définitivement."],"%s item could not be restored.":["%s élément n'a pas pu être rétabli.","%s éléments n'ont pas pu être rétablis.","%s éléments n'ont pas pu être rétablis."],"%s item moved to the trash.":["%s élément déplacé dans la corbeille.","%s éléments déplacés dans la corbeille.","%s éléments déplacés dans la corbeille."],"%s item permanently deleted.":["%s élément supprimé définitivement.","%s éléments supprimés définitivement.","%s éléments supprimés définitivement."],"%s item stays in the trash.":["%s élément reste dans la corbeille.","%s éléments restent dans la corbeille.","%s éléments restent dans la corbeille."],"%s minute":["%s minute","%s minutes","%s minutes"],"%s page has been restored.":["%s page a été rétablie.","%s pages ont été rétablies.","%s pages ont été rétablies."],"%s post has been restored.":["%s article a été rétabli.","%s articles ont été rétablis.","%s articles ont été rétablis."],"%s update available":["%s mise à jour disponible","%s mises à jour disponibles","%s mises à jour disponibles"],"(no title)":["(pas de titre)"],"Gophenberg %(version)s is available! Please update now.":["Gophenberg %(version)s est disponible ! Veuillez faire la mise à jour maintenant."],"Important: Before updating, please back up your database and files. For help with updates, visit the Updating Gophenberg documentation page.":["Important : avant de mettre à jour, veuillez sauvegarder votre base de données et vos fichiers. Pour obtenir de l'aide sur les mises à jour, consultez la page de documentation Mettre à jour Gophenberg."],"A %(kind)s field does not take a setting called %(setting)s. Remove it and try again.":["Un champ %(kind)s n'accepte pas de réglage nommé %(setting)s. Retirez-le et réessayez."],"A Linked from field stands on its own, not inside a section or a repeater. Declare %(field)s beside the container.":["Un champ Lié depuis se place seul, ni dans une section ni dans un répéteur. Déclarez %(field)s à côté du conteneur."],"A backup of the database is taken first, and Gophenberg goes back to %(running)s on its own if the new version does not start.":["Une sauvegarde de la base de données est faite d'abord, et Gophenberg revient de lui-même à %(running)s si la nouvelle version ne démarre pas."],"A backup of the database is taken first, and the site stays down until you restore it if the new version does not start.":["Une sauvegarde de la base de données est faite d'abord, et le site reste hors service jusqu'à ce que vous la restauriez si la nouvelle version ne démarre pas."],"A content type needs a singular and a plural name, like Guide and Guides. Fill both in and try again.":["Un type de contenu a besoin d'un nom au singulier et d'un nom au pluriel, comme Guide et Guides. Remplissez les deux et réessayez."],"A descriptive summary of the content type.":["Un résumé descriptif du type de contenu."],"A field group key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Rename the group in the file so its key comes out in that shape.":["La clé d'un groupe de champs doit commencer par une lettre minuscule puis ne contenir que des lettres minuscules, des chiffres et des tirets. Renommez le groupe dans le fichier pour que sa clé prenne cette forme."],"A field key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Rename the field so its key comes out in that shape.":["La clé d'un champ doit commencer par une lettre minuscule et ne contenir ensuite que des lettres minuscules, des chiffres et des tirets. Renommez le champ pour que sa clé prenne cette forme."],"A field needs a name. Type one and try again.":["Un champ a besoin d'un nom. Saisissez-en un et réessayez."],"A field with that name already exists on the items this group reaches. Pick another name.":["Un champ portant ce nom existe déjà sur les éléments que ce groupe atteint. Choisissez un autre nom."],"A flexible content field holds layouts, and %(field)s is not one. Add a layout first, then declare the field inside that layout.":["Un champ de contenu flexible contient des dispositions, et %(field)s n'en est pas une. Ajoutez d'abord une disposition, puis déclarez le champ dans cette disposition."],"A higher quality stores larger files, and it applies to pictures uploaded from now on.":["Une qualité plus élevée stocke des fichiers plus grands, et elle s'applique aux images téléversées à partir de maintenant."],"A layout stands inside a flexible content field only. Put %(field)s inside one of those instead.":["Une disposition ne se place que dans un champ de contenu flexible. Placez %(field)s dans l'un d'eux."],"A layout stands inside a flexible content field, never on its own. Declare a flexible content field first, then add %(field)s inside it.":["Une disposition se place dans un champ de contenu flexible, jamais seule. Déclarez d'abord un champ de contenu flexible, puis ajoutez %(field)s dedans."],"A listing carries between 1 and %(max)s items, so %(value)s is not a size Gophenberg takes. Pick a number inside that range.":["Une liste affiche entre 1 et %(max)s éléments, donc %(value)s n'est pas une taille que Gophenberg accepte. Choisissez un nombre dans cet intervalle."],"A relation field has to say which content type it points at. Pick that type and try again.":["Un champ de relation doit indiquer le type de contenu qu'il vise. Choisissez ce type et réessayez."],"A reload shows the admin in the language you chose.":["Un rechargement affiche l'administration dans la langue que vous avez choisie."],"A route word has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Change it and try again.":["Un mot de route doit commencer par une lettre minuscule et ne contenir ensuite que des lettres minuscules, des chiffres et des tirets. Modifiez-le et réessayez."],"A row of %(field)s has to name the layout it takes. Pick a layout for the row, or remove the row.":["Une ligne de %(field)s doit nommer la disposition qu'elle prend. Choisissez une disposition pour la ligne, ou retirez la ligne."],"A row of %(field)s takes one layout and no more. Reload the page and build the row again.":["Une ligne de %(field)s prend une seule disposition. Rechargez la page et reconstruisez la ligne."],"A rule matching any %(source)s cannot be turned into an exclusion. Leave it as is, or name the ones to leave out instead.":["Une règle valable pour n'importe quel %(source)s ne peut pas devenir une exclusion. Laissez-la telle quelle, ou nommez ceux à écarter."],"A theme naming its own page size uses that instead.":["Un thème qui indique sa propre taille de page utilise celle-ci à la place."],"A type key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Change the key and try again.":["La clé d'un type doit commencer par une lettre minuscule et ne contenir ensuite que des lettres minuscules, des chiffres et des tirets. Modifiez la clé et réessayez."],"Actions":["Actions"],"Activate":["Activer"],"Activate %(theme)s":["Activer %(theme)s"],"Active":["Actif"],"Add":["Ajouter"],"Add %(layout)s":["Ajouter %(layout)s"],"Add %(name)s":["Ajouter %(name)s"],"Add %(type)s":["Ajouter %(type)s"],"Add Category":["Ajouter une catégorie"],"Add Content Type":["Ajouter un type de contenu"],"Add Field Group":["Ajouter un groupe de champs"],"Add Media File":["Ajouter un fichier média"],"Add Page":["Ajouter une page"],"Add Post":["Ajouter un article"],"Add User":["Ajouter un utilisateur"],"Add block":["Ajouter un bloc"],"Add choice":["Ajouter un choix"],"Add condition":["Ajouter une condition"],"Add field":["Ajouter un champ"],"Add field to %(field)s":["Ajouter un champ à %(field)s"],"Add layout":["Ajouter une disposition"],"Add layout to %(field)s":["Ajouter une disposition à %(field)s"],"Add one with %(button)s.":["Ajoutez un élément avec %(button)s."],"Add row":["Ajouter une ligne"],"Add rule set":["Ajouter un ensemble de règles"],"Add title":["Ajouter un titre"],"Add to %(field)s":["Ajouter à %(field)s"],"Address":["Adresse"],"Address updated.":["Adresse mise à jour."],"Adopt":["Adopter"],"Allow custom":["Autoriser les valeurs libres"],"Allow empty":["Autoriser le vide"],"Alt text":["Texte alternatif"],"An item cannot point at itself. Pick a different item for %(field)s.":["Un élément ne peut pas se viser lui-même. Choisissez un autre élément pour %(field)s."],"An item cannot sit inside itself, or inside one of the items nested under it. Pick a parent outside this branch.":["Un élément ne peut pas se trouver dans lui-même, ni dans un élément imbriqué sous lui. Choisissez un parent hors de cette branche."],"An updated version of Gophenberg is available.":["Une version mise à jour de Gophenberg est disponible."],"Another account wrote this, and only its author, an editor or an administrator may change it. You can still read it.":["Un autre compte a écrit ceci, et seuls son auteur, un éditeur ou un administrateur peuvent le modifier. Vous pouvez toujours le lire."],"Another account wrote this, so you are reading it rather than editing it.":["Un autre compte a écrit ceci, alors vous le lisez au lieu de le modifier."],"Another content type already answers under this route word. Pick a different word.":["Un autre type de contenu répond déjà sous ce mot de route. Choisissez un autre mot."],"Another content type already lives at the root of your site, and only one can. Give this type a route word, or hand the root over with Make default.":["Un autre type de contenu occupe déjà la racine de votre site, et un seul le peut. Donnez un mot de route à ce type, ou cédez la racine avec Rendre par défaut."],"Another content type already uses this key. Give this type a different name.":["Un autre type de contenu utilise déjà cette clé. Donnez un autre nom à ce type."],"Another item of this content type already uses that address. Pick a different slug and save again.":["Un autre élément de ce type de contenu utilise déjà cette adresse. Choisissez un autre slug et enregistrez de nouveau."],"Another update is currently in progress.":["Une autre mise à jour est actuellement en cours."],"Appears on":["Apparaît sur"],"Apply":["Appliquer"],"April":["avril"],"Are you sure you want to move \"%s\" to the trash?":["Voulez-vous vraiment déplacer « %s » dans la corbeille ?"],"Audio":["Audio"],"August":["août"],"Author":["Auteur/autrice"],"Back to %(type)s":["Retour aux %(type)s"],"Back to the latest posts":["Retour aux derniers articles"],"Backing up the database…":["Sauvegarde de la base de données…"],"Backups kept: %(kept)s of %(limit)s, taken on %(date)s at %(time)s.":["Sauvegardes conservées : %(kept)s sur %(limit)s, faite le %(date)s à %(time)s.","Sauvegardes conservées : %(kept)s sur %(limit)s, la plus récente le %(date)s à %(time)s.","Sauvegardes conservées : %(kept)s sur %(limit)s, la plus récente le %(date)s à %(time)s."],"Block":["Bloc"],"Broken":["Cassé"],"Bundles of fields, shown where their rules place them.":["Ensembles de champs, affichés là où leurs règles les placent."],"Button group":["Groupe de boutons"],"Cancel":["Annuler"],"Caption":["Légende"],"Change %(name)s":["Modifier %(name)s"],"Change address":["Changer l'adresse"],"Change address…":["Changer l'adresse…"],"Change role":["Changer le rôle"],"Change the role of %(name)s":["Changer le rôle de %(name)s"],"Check again.":["Vérifier à nouveau."],"Check now.":["Vérifier maintenant."],"Checkbox group":["Groupe de cases à cocher"],"Checking the new version…":["Vérification de la nouvelle version…"],"Choices":["Choix"],"Choose %(field)s":["Choisir %(field)s"],"Choose how the site serves its content.":["Choisissez comment le site sert son contenu."],"Choose the language the admin reads in.":["Choisissez la langue dans laquelle se lit l'administration."],"Choose the role of %(name)s.":["Choisissez le rôle de %(name)s."],"Choose the version to update to.":["Choisissez la version vers laquelle mettre à jour."],"Clear %(field)s":["Vider %(field)s"],"Close":["Fermer"],"Close Settings":["Fermer les réglages"],"Closed":["Fermé"],"Condition":["Condition"],"Content":["Contenu"],"Content Types":["Types de contenu"],"Content nests at most %(max)s levels deep, and this item would sit deeper. Pick a parent closer to the top.":["Le contenu s'imbrique sur au plus %(max)s niveaux, et cet élément irait plus profond. Choisissez un parent plus proche du sommet."],"Content type":["Type de contenu"],"Content type updated.":["Type de contenu mis à jour."],"Could not load that post.":["Impossible de charger cet article."],"Could not save image. %s":["Impossible d’enregistrer le média. %s"],"Could not save media. %s":["Impossible d’enregistrer le média. %s"],"Could not save that post.":["Impossible d'enregistrer cet article."],"Create":["Créer"],"Create a field group":["Créer un groupe de champs"],"Create user":["Créer l'utilisateur"],"Created":["Date de création"],"Current version: %(version)s":["Version actuelle : %(version)s"],"Date added":["Date d’ajout"],"Date modified":["Date de modification"],"Deactivate":["Désactiver"],"Deactivate %(theme)s":["Désactiver %(theme)s"],"December":["décembre"],"Default":["Par défaut"],"Default content type updated.":["Type de contenu par défaut mis à jour."],"Definitions file":["Fichier de définitions"],"Delete":["Supprimer"],"Delete \"%(title)s\" for good? This cannot be undone.":["Supprimer « %(title)s » définitivement ? Cette action est irréversible."],"Delete %(field)s":["Supprimer %(field)s"],"Delete %(group)s":["Supprimer %(group)s"],"Delete %s content type for good? This cannot be undone.":["Supprimer %s type de contenu définitivement ? Cette action est irréversible.","Supprimer %s types de contenu définitivement ? Cette action est irréversible.","Supprimer %s types de contenu définitivement ? Cette action est irréversible."],"Delete %s item for good? This cannot be undone.":["Supprimer %s élément définitivement ? Cette action est irréversible.","Supprimer %s éléments définitivement ? Cette action est irréversible.","Supprimer %s éléments définitivement ? Cette action est irréversible."],"Delete permanently":["Supprimer définitivement"],"Delete the field":["Supprimer le champ"],"Delete the group":["Supprimer le groupe"],"Delete…":["Supprimer…"],"Describe":["Décrire"],"Describe the purpose of the image.":["Décrivez la fonction de l’image."],"Describe…":["Décrire…"],"Description":["Description"],"Description updated.":["Description mise à jour."],"Desktop":["Ordinateur"],"Destination":["Destination"],"Dimensions":["Dimensions"],"Disable":["Désactiver"],"Disable %(name)s":["Désactiver %(name)s"],"Disabled":["Désactivé"],"Dismiss":["Ignorer"],"Document":["Document"],"Documents":["Documents"],"Done. The site now holds what the file describes.":["Terminé. Le site contient maintenant ce que décrit le fichier."],"Downloading Gophenberg %(version)s…":["Téléchargement de Gophenberg %(version)s…"],"Draft saved.":["Brouillon enregistré."],"Drop files to upload":["Déposez vos fichiers pour les téléverser"],"Edit media":["Modifier le média"],"Edit…":["Modifier…"],"Email":["E-mail"],"Empty Trash":["Vider la corbeille"],"Empty trash":["Vider la corbeille"],"Enable":["Activer"],"Enable %(name)s":["Activer %(name)s"],"Every address of this type moves. Links kept elsewhere to the old addresses stop working.":["Toutes les adresses de ce type changent. Les liens conservés ailleurs vers les anciennes adresses cessent de fonctionner."],"Every content type":["Tous les types de contenu"],"Every field group needs a title. Give it a name and save again.":["Chaque groupe de champs a besoin d'un titre. Donnez-lui un nom et enregistrez à nouveau."],"Every item needs an author who exists. Pick one from the list and save again.":["Chaque élément a besoin d'un auteur existant. Choisissez-en un dans la liste et enregistrez de nouveau."],"Every kind of content this site holds.":["Toutes les sortes de contenu que ce site contient."],"Every value stored under this field goes with it, in every item the group reaches and in the revisions behind them.":["Toutes les valeurs enregistrées dans ce champ partent avec lui, dans chaque élément que le groupe atteint et dans les révisions qui les suivent."],"Excerpt":["Extrait"],"Export definitions":["Exporter les définitions"],"February":["février"],"Fewest files":["Minimum de fichiers"],"Fewest rows":["Minimum de lignes"],"Field":["Champ"],"Field Groups":["Groupes de champs"],"Field group":["Groupe de champs"],"Fields":["Champs"],"Fields of %(group)s":["Champs de %(group)s"],"File name":["Nom de fichier"],"File size":["Taille du fichier"],"File type":["Type de fichier"],"Filter by status":["Filtrer par état"],"Follow the browser":["Suivre le navigateur"],"Follow the steps on the Updating Gophenberg documentation page to update by hand.":["Suivez les étapes de la page de documentation Mettre à jour Gophenberg pour mettre à jour à la main."],"From %(plugin)s":["De %(plugin)s"],"Full Size":["Taille originale"],"Gophenberg %(version)s failed its start check on this site. Fix what failed before you try it again.":["Gophenberg %(version)s a échoué à sa vérification de démarrage sur ce site. Corrigez ce qui a échoué avant de réessayer."],"Gophenberg Updates":["Mises à jour de Gophenberg"],"Gophenberg cannot start this update: %(reason)s":["Gophenberg ne peut pas lancer cette mise à jour : %(reason)s"],"Gophenberg checked for updates moments ago. Try again later.":["Gophenberg a cherché des mises à jour il y a un instant. Réessayez plus tard."],"Gophenberg could not read what your browser sent. Reload the page and try again, and tell whoever looks after your site if it keeps happening.":["Gophenberg n'a pas pu lire ce que votre navigateur a envoyé. Rechargez la page et réessayez, et prévenez la personne qui s'occupe de votre site si cela continue."],"Gophenberg could not read which item you picked as parent. Reload the page and pick it again.":["Gophenberg n'a pas pu lire quel élément vous avez choisi comme parent. Rechargez la page et choisissez-le de nouveau."],"Gophenberg does not accept %(extension)s files. Upload a picture, a video, an audio file, a PDF or a zip instead.":["Gophenberg n'accepte pas les fichiers %(extension)s. Téléversez plutôt une image, une vidéo, un fichier audio, un PDF ou un zip."],"Gophenberg does not answer in %(value)s. Pick one of the languages on the list.":["Gophenberg ne répond pas en %(value)s. Choisissez une des langues de la liste."],"Gophenberg has no autosave of yours for this item. Open the item to see the version that is stored.":["Gophenberg n'a aucun enregistrement automatique de vous pour cet élément. Ouvrez l'élément pour voir la version stockée."],"Gophenberg has not checked for updates yet.":["Gophenberg n'a pas encore recherché de mises à jour."],"Gophenberg has not come back yet.":["Gophenberg n'est pas encore revenu."],"Gophenberg holds no kind of definition called %(subject)s, so nothing was taken over. Reload the page so the admin and the server agree again.":["Gophenberg ne connaît aucune sorte de définition nommée %(subject)s, rien n'a donc été repris. Rechargez la page pour que l'admin et le serveur se rejoignent à nouveau."],"Gophenberg keeps /%(path)s for itself or for another content type, so your content cannot answer there. Give the item a different slug.":["Gophenberg garde l'adresse /%(path)s pour lui ou pour un autre type de contenu, votre contenu ne peut donc pas y répondre. Donnez un autre slug à l'élément."],"Gophenberg keeps this word for itself, so no content type can answer under it. Pick a different route word.":["Gophenberg garde ce mot pour lui, aucun type de contenu ne peut donc répondre sous ce mot. Choisissez un autre mot de route."],"Gophenberg stopped after the switch so that its service manager, such as systemd, starts the new version. Check that the service manager starts it again after exit code 75, and run update:status on the server to see where the update stands.":["Gophenberg s'est arrêté après le changement pour que son gestionnaire de services, comme systemd, démarre la nouvelle version. Vérifiez que le gestionnaire de services le redémarre après le code de sortie 75, et lancez update:status sur le serveur pour voir où en est la mise à jour."],"Gophenberg updated successfully.":["Gophenberg a été mis à jour avec succès."],"Gophenberg went back to %(from)s and is running normally.":["Gophenberg est revenu à %(from)s et fonctionne normalement."],"Group":["Groupe"],"Highest":["Maximum"],"Holds":["Contient"],"Images":["Images"],"Import definitions":["Importer les définitions"],"In list":["Dans la liste"],"Inactive":["Inactif"],"Installed":["Installé"],"Instructions":["Instructions"],"It moves here from another group and keeps its stored values.":["Il arrive ici depuis un autre groupe et garde ses valeurs enregistrées."],"It moves to another group and keeps its stored values.":["Il passe dans un autre groupe et garde ses valeurs enregistrées."],"It moves to another group, so its stored values do not follow.":["Il passe dans un autre groupe, donc ses valeurs enregistrées ne le suivent pas."],"It reads a relation inside a container, and only an import can point it elsewhere.":["Il lit une relation dans un conteneur, et seule une importation peut le faire pointer ailleurs."],"It starts on %(type)s, and the rules may be edited afterwards.":["Il commence sur %(type)s, et les règles peuvent être modifiées ensuite."],"Items could not be loaded.":["Les éléments n'ont pas pu être chargés."],"Its items sit inside one another, so it keeps nesting.":["Ses éléments se trouvent les uns dans les autres, donc il continue de s'imbriquer."],"Its kind changed, so its stored values go with it.":["Son type a changé, donc ses valeurs enregistrées partent avec lui."],"January":["janvier"],"July":["juillet"],"June":["juin"],"Keep %(field)s out of the list":["Garder %(field)s hors de la liste"],"Keep it":["Le conserver"],"Keep it here":["Le laisser ici"],"Key":["Clé"],"Label":["Libellé"],"Language":["Langue"],"Large":["Grande"],"Last checked on %(date)s at %(time)s.":["Dernière vérification le %(date)s à %(time)s."],"Leave empty if decorative.":["Laissez vide si l’image est décorative"],"Let items nest":["Autoriser l'imbrication"],"Linked from":["Lié depuis"],"List view":["Vue en liste"],"Loading field groups.":["Chargement des groupes de champs."],"Loading the post.":["Chargement de l'article."],"Loading the screen.":["Chargement de l'écran."],"Loading themes.":["Chargement des thèmes."],"Loading users.":["Chargement des utilisateurs."],"Loading…":["Chargement…"],"Longest":["Longueur maximale"],"Lowest":["Minimum"],"Make %(field)s optional":["Rendre %(field)s facultatif"],"Make default":["Rendre par défaut"],"Make default…":["Rendre par défaut…"],"Make optional":["Rendre facultatif"],"Manage the categories on this site.":["Gérez les catégories de ce site."],"Manage the images and files this site holds.":["Gérez les images et les fichiers que ce site contient."],"Manage the items of this content type.":["Gérez les éléments de ce type de contenu."],"Manage the pages on this site.":["Gérez les pages de ce site."],"Manage the posts on this site.":["Gérez les articles de ce site."],"Many targets":["Plusieurs cibles"],"Many values":["Plusieurs valeurs"],"March":["mars"],"May":["mai"],"Media %(id)s":["Média %(id)s"],"Media Library":["Médiathèque"],"Media file updated.":["Fichier média mis à jour."],"Medium":["Moyenne"],"Mobile":["Mobile"],"Modified: %s":["Modifié : %s"],"Most files":["Maximum de fichiers"],"Most rows":["Maximum de lignes"],"Move":["Déplacer"],"Move \"%(title)s\" to the trash?":["Déplacer « %(title)s » dans la corbeille ?"],"Move %(field)s down":["Descendre %(field)s"],"Move %(field)s elsewhere":["Déplacer %(field)s ailleurs"],"Move %(field)s up":["Monter %(field)s"],"Move %(group)s down":["Descendre %(group)s"],"Move %(group)s up":["Monter %(group)s"],"Move %(name)s down":["Descendre %(name)s"],"Move %(name)s up":["Monter %(name)s"],"Move %s item to the trash?":["Déplacer %s élément dans la corbeille ?","Déplacer %s éléments dans la corbeille ?","Déplacer %s éléments dans la corbeille ?"],"Move every address":["Déplacer toutes les adresses"],"Move row down":["Descendre la ligne"],"Move row up":["Monter la ligne"],"Move the field":["Déplacer le champ"],"Move to trash":["Déplacer dans la corbeille"],"Name":["Nom"],"Name updated.":["Nom mis à jour."],"Nests":["Imbriqué"],"Newer posts":["Articles plus récents"],"No":["Non"],"No content types found.":["Aucun type de contenu trouvé."],"No description":["Aucune description"],"No file arrived with this upload. Choose a file and try again.":["Aucun fichier n'est arrivé avec ce téléversement. Choisissez un fichier et réessayez."],"No items found.":["Aucun élément trouvé."],"No items yet.":["Aucun élément pour l'instant."],"No media chosen":["Aucun média choisi"],"No media has been uploaded yet.":["Aucun média n'a encore été téléversé."],"No media items found.":["Aucun média n’a été trouvé."],"No media items yet.":["Aucun fichier média pour l’instant."],"No new updates found.":["Aucune nouvelle mise à jour trouvée."],"No page lives at this address.":["Aucune page n'existe à cette adresse."],"No parent":["Pas de parent"],"No theme arrived with this upload. Choose a zip file and try again.":["Aucun thème n'est arrivé avec ce téléversement. Choisissez un fichier zip et réessayez."],"No themes are installed.":["Aucun thème n'est installé."],"No title":["Aucun titre"],"None":["Aucun"],"Not %(type)s":["Sauf %(type)s"],"Not found":["Introuvable"],"Not serving":["Hors service"],"Nothing declares that role.":["Rien ne déclare ce rôle."],"Nothing points here yet.":["Rien ne pointe encore ici."],"Nothing published here yet.":["Rien n'est encore publié ici."],"Nothing published yet.":["Rien n'est encore publié."],"November":["novembre"],"Nowhere":["Nulle part"],"Number":["Nombre"],"October":["octobre"],"Older posts":["Articles plus anciens"],"One frame of this animation holds more than %(max)s pixels, which is more than Gophenberg opens. Upload a smaller animation.":["Une image de cette animation dépasse %(max)s pixels, plus que ce que Gophenberg ouvre. Téléversez une animation plus petite."],"One of the filters on this list is not one Gophenberg understands. Clear the filters and try again.":["Un des filtres de cette liste n'est pas un filtre que Gophenberg comprend. Videz les filtres et réessayez."],"One of the items picked for %(field)s is not the kind of content that field points at. Reload the page and pick from the list the field offers.":["Un des éléments choisis pour %(field)s n'est pas le genre de contenu que vise ce champ. Rechargez la page et choisissez dans la liste que le champ propose."],"One of the items picked for %(field)s was not named in a way Gophenberg understands. Reload the page and pick the items again.":["Un des éléments choisis pour %(field)s n'était pas nommé d'une façon que Gophenberg comprend. Rechargez la page et choisissez de nouveau les éléments."],"One of the items picked no longer exists. Reload the page and pick again.":["Un des éléments choisis n'existe plus. Rechargez la page et choisissez de nouveau."],"One target":["Une cible"],"Only a relation field points at another content type or holds many items. Pick the Relation kind, or leave the target and the many option empty.":["Seul un champ de relation vise un autre type de contenu ou contient plusieurs éléments. Choisissez le genre Relation, ou laissez vides la cible et l'option plusieurs."],"Only one file may be placed here.":["Un seul fichier peut être placé ici."],"Only the content type at the root of your site may go without a route word. Give this type one and try again.":["Seul le type de contenu à la racine de votre site peut se passer de mot de route. Donnez-en un à ce type et réessayez."],"Open %(field)s in a new tab":["Ouvrir %(field)s dans un nouvel onglet"],"Order stored.":["Ordre enregistré."],"Other":["Autre"],"Out of list":["Hors de la liste"],"Parent":["Parent"],"Password":["Mot de passe"],"Pending":["En attente"],"Pending Review":["En attente de relecture"],"Permanently delete…":["Supprimer définitivement…"],"Picture quality":["Qualité d'image"],"Picture quality runs from 1 to %(max)s, so %(value)s is not a quality Gophenberg stores at. Pick a number inside that range.":["La qualité d'image va de 1 à %(max)s, donc %(value)s n'est pas une qualité avec laquelle Gophenberg enregistre. Choisissez un nombre dans cet intervalle."],"Placeholder":["Texte indicatif"],"Plural name":["Nom au pluriel"],"Points at":["Vise"],"Post published.":["Article publié."],"Posts per page":["Articles par page"],"Preview":["Prévisualiser"],"Private":["Privé"],"Publish":["Publier"],"Published: %s":["Publié : %s"],"Radio group":["Groupe de boutons radio"],"Re-install version %(version)s":["Réinstaller la version %(version)s"],"Reads from":["Lit depuis"],"Redo":["Rétablir"],"Relation":["Relation"],"Reload the admin":["Recharger l'administration"],"Remove":["Retirer"],"Remove %(name)s":["Retirer %(name)s"],"Remove %(title)s":["Retirer %(title)s"],"Remove row":["Retirer la ligne"],"Rename":["Renommer"],"Rename %(field)s":["Renommer %(field)s"],"Rename…":["Renommer…"],"Require":["Rendre obligatoire"],"Require %(field)s":["Rendre %(field)s obligatoire"],"Required":["Obligatoire"],"Restarting Gophenberg…":["Redémarrage de Gophenberg…"],"Restore":["Rétablir"],"Role changed.":["Rôle modifié."],"Roll back to %(theme)s":["Revenir à %(theme)s"],"Roll back to the built-in renderer":["Revenir au moteur de rendu intégré"],"Route word":["Mot de route"],"Rule %(number)s of set %(set)s":["Règle %(number)s de l'ensemble %(set)s"],"Rule set %(number)s":["Ensemble de règles %(number)s"],"Rules":["Règles"],"Rules showing %(field)s":["Règles affichant %(field)s"],"Run update:status on the server to see the backup taken before the update. Then restore that backup, or fix what failed and start Gophenberg again.":["Exécutez update:status sur le serveur pour voir la sauvegarde faite avant la mise à jour. Ensuite, restaurez cette sauvegarde, ou corrigez ce qui a échoué et redémarrez Gophenberg."],"Save":["Enregistrer"],"Save draft":["Enregistrer le brouillon"],"Save rules":["Enregistrer les règles"],"Save settings":["Enregistrer les réglages"],"Saved":["Enregistré"],"Saving":["Enregistrement"],"Scheduled":["Planifié"],"Scheduled: %s":["Planifié : %s"],"Search %(type)s…":["Rechercher des %(type)s…"],"Search audio":["Rechercher un audio"],"Search images":["Rechercher des images"],"Search media":["Rechercher des médias"],"Search videos":["Rechercher des vidéos"],"Select":["Sélectionner"],"September":["septembre"],"Serving":["En service"],"Settings":["Réglages"],"Settings of %(field)s":["Réglages de %(field)s"],"Shadowed":["Masqué"],"Show %(field)s in the list":["Afficher %(field)s dans la liste"],"Showing %(held)s of %(total)s.":["Affichage de %(held)s sur %(total)s."],"Singular name":["Nom au singulier"],"Slug":["Slug"],"Somebody must be able to manage users.":["Quelqu'un doit pouvoir gérer les utilisateurs."],"Someone else changed this media item while you were editing it. Reload the page and make your change again.":["Quelqu'un d'autre a modifié ce média pendant que vous le modifiiez. Rechargez la page et refaites votre modification."],"Someone else saved changes to this item while you were editing, so yours were not saved. Copy your text somewhere safe, then reload the item and put your changes back in.":["Quelqu'un d'autre a enregistré des modifications sur cet élément pendant que vous éditiez, les vôtres n'ont donc pas été enregistrées. Copiez votre texte en lieu sûr, puis rechargez l'élément et remettez vos modifications."],"Something went wrong inside Gophenberg. Try again in a moment, and tell whoever looks after your site if it keeps happening.":["Quelque chose a mal tourné dans Gophenberg. Réessayez dans un instant, et prévenez la personne qui s'occupe de votre site si cela continue."],"Something went wrong.":["Quelque chose a mal tourné."],"Something went wrong. Try again.":["Quelque chose a mal tourné. Réessayez."],"Sorry, you are not allowed to access this page.":["Désolé, vous n’avez pas l’autorisation d’accéder à cette page."],"Source":["Source"],"Steps of":["Pas de"],"Stop nesting":["Arrêter l'imbrication"],"Tablet":["Tablette"],"Text":["Texte"],"Text area":["Zone de texte"],"That email is already in use.":["Cet e-mail est déjà utilisé."],"That field group no longer exists. Reload the page to see the groups your site holds now.":["Ce groupe de champs n'existe plus. Rechargez la page pour voir les groupes que votre site contient maintenant."],"That field is not on this content type any more. Reload the page to see the fields it has now.":["Ce champ n'est plus sur ce type de contenu. Rechargez la page pour voir les champs qu'il possède maintenant."],"That revision does not exist, and older ones drop off once a type holds more than it keeps. Open the item to see which revisions are left.":["Cette révision n'existe pas, et les plus anciennes disparaissent quand un type en détient plus qu'il n'en conserve. Ouvrez l'élément pour voir les révisions restantes."],"That role holds more than your own.":["Ce rôle va au-delà du vôtre."],"That web address does not name a media item Gophenberg can look up. Open the media library and pick the item from there.":["Cette adresse web ne désigne aucun média que Gophenberg puisse trouver. Ouvrez la bibliothèque de médias et choisissez l'élément depuis là."],"That web address does not name a revision Gophenberg can look up. Open the item and pick a revision from its history.":["Cette adresse web ne désigne aucune révision que Gophenberg puisse trouver. Ouvrez l'élément et choisissez une révision dans son historique."],"That web address does not name an item Gophenberg can look up. Go back to the list and open the item from there.":["Cette adresse web ne désigne aucun élément que Gophenberg puisse trouver. Revenez à la liste et ouvrez l'élément depuis là."],"The %(count)s item in the trash is deleted for good. This cannot be undone.":["%(count)s élément de la corbeille est supprimé définitivement. Cette action est irréversible.","Les %(count)s éléments de la corbeille sont supprimés définitivement. Cette action est irréversible.","Les %(count)s éléments de la corbeille sont supprimés définitivement. Cette action est irréversible."],"The %(file)s calls this theme %(declared)s, but it is being installed as %(installed)s. Rename the zip file to match, or change the name inside %(file)s.":["Le fichier %(file)s appelle ce thème %(declared)s, mais il s'installe sous %(installed)s. Renommez le fichier zip pour qu'ils correspondent, ou changez le nom dans %(file)s."],"The %(file)s inside %(name)s is not valid JSON, so it could not be read. Fix that file and package the theme again.":["Le fichier %(file)s dans %(name)s n'est pas du JSON valide, il n'a donc pas pu être lu. Corrigez ce fichier et réempaquetez le thème."],"The %(file)s inside %(name)s names its theme kit as %(declared)s, which is not a version number. Build the theme again, and the build will fill that in.":["Le %(file)s dans %(name)s indique son kit de thèmes comme %(declared)s, ce qui n'est pas un numéro de version. Compilez le thème à nouveau et la compilation le renseignera."],"The %(origin)s plugin declared this, so it can only be changed in that plugin. Turning it off is still yours to do.":["L'extension %(origin)s l'a déclaré, donc il ne peut être modifié que dans cette extension. Le désactiver reste entre vos mains."],"The %(plugin)s plugin also declares %(name)s, and the site keeps the key.":["L'extension %(plugin)s déclare aussi %(name)s, et le site garde la clé."],"The %(plugin)s plugin declared these fields, so they change only in its code.":["L'extension %(plugin)s a déclaré ces champs, donc ils ne changent que dans son code."],"The %(plugin)s plugin declares %(name)s flat, and the site keeps it nesting while its items sit inside another.":["L'extension %(plugin)s déclare %(name)s sans imbrication, et le site continue de l'imbriquer tant que ses éléments se trouvent dans un autre."],"The browser kept an unsaved version of this post.":["Le navigateur a gardé une version non enregistrée de cet article."],"The built-in renderer is now serving the public site.":["Le moteur de rendu intégré sert désormais le site public."],"The built-in renderer is serving the public site.":["Le moteur de rendu intégré sert le site public."],"The check on %(date)s at %(time)s failed: %(error)s":["La vérification du %(date)s à %(time)s a échoué : %(error)s"],"The content type this field points at is not named in a shape Gophenberg accepts. Give it a key that starts with a lowercase letter and then holds only lowercase letters, numbers and hyphens.":["Le type de contenu que vise ce champ n'est pas nommé sous une forme que Gophenberg accepte. Donnez-lui une clé qui commence par une lettre minuscule et ne contient ensuite que des lettres minuscules, des chiffres et des tirets."],"The content types could not be loaded, so where these groups appear and which fields they shadow are not shown.":["Les types de contenu n'ont pas pu être chargés, donc où ces groupes apparaissent et quels champs ils masquent ne sont pas affichés."],"The content types could not be loaded.":["Les types de contenu n'ont pas pu être chargés."],"The content types could not be refreshed, so where these groups appear and what they shadow may be out of date.":["Les types de contenu n'ont pas pu être actualisés, donc où ces groupes apparaissent et ce qu'ils masquent peut être obsolète."],"The draft could not be created.":["Le brouillon n'a pas pu être créé."],"The entry %(entry)s in this zip would be written outside the theme folder, so nothing was installed. Package the theme again.":["L'entrée %(entry)s de ce zip s'écrirait hors du dossier du thème, rien n'a donc été installé. Réempaquetez le thème."],"The field %(field)s cannot go, because %(by)s reads it. Change %(by)s first.":["Le champ %(field)s ne peut pas être retiré, car %(by)s le lit. Modifiez d'abord %(by)s."],"The field %(field)s cannot hold the value it was given. Check what kind of field it is and enter a value that matches.":["Le champ %(field)s ne peut pas contenir la valeur qui lui a été donnée. Vérifiez de quel genre de champ il s'agit et saisissez une valeur qui convient."],"The field %(field)s has to hold a value before this item can be published. Fill it in, or leave the item as a draft.":["Le champ %(field)s doit contenir une valeur avant que cet élément puisse être publié. Remplissez-le, ou laissez l'élément en brouillon."],"The field %(field)s in %(group)s still points at this content type. Delete that field first, then delete this type.":["Le champ %(field)s dans %(group)s vise encore ce type de contenu. Supprimez d'abord ce champ, puis supprimez ce type."],"The field %(field)s is hidden by its own rules right now, so it cannot hold a value. Show it again before filling it in.":["Le champ %(field)s est masqué par ses propres règles pour le moment, il ne peut donc contenir aucune valeur. Affichez-le de nouveau avant de le remplir."],"The field %(field)s points at one item only. Remove the extra choices and keep one.":["Le champ %(field)s ne vise qu'un seul élément. Retirez les choix en trop et gardez-en un."],"The field %(field)s points at other items, so it does not take a plain value. Pick the items it points at instead.":["Le champ %(field)s vise d'autres éléments, il n'accepte donc pas une valeur simple. Choisissez plutôt les éléments qu'il vise."],"The field %(field)s takes a list of items, and what arrived was not a list. Reload the page and pick the items again.":["Le champ %(field)s attend une liste d'éléments, et ce qui est arrivé n'était pas une liste. Rechargez la page et choisissez de nouveau les éléments."],"The field %(source)s cannot hold the value %(value)s, so no rule can compare it. Write a value of the kind %(source)s stores.":["Le champ %(source)s ne peut pas contenir la valeur %(value)s, aucune règle ne peut donc la comparer. Écrivez une valeur du type que %(source)s enregistre."],"The field groups could not be loaded.":["Les groupes de champs n'ont pas pu être chargés."],"The field groups could not be reached.":["Les groupes de champs n'ont pas pu être joints."],"The field keeps its values on the content both groups reach.":["Le champ garde ses valeurs sur le contenu que les deux groupes atteignent."],"The fields this group holds go with it, and so do the values every item stored in them.":["Les champs que ce groupe contient partent avec lui, ainsi que les valeurs que chaque élément y a enregistrées."],"The groups were reordered.":["Les groupes ont été réordonnés."],"The item could not be duplicated.":["L'élément n'a pas pu être dupliqué."],"The item could not be moved to the trash.":["L'élément n'a pas pu être déplacé dans la corbeille."],"The item could not be permanently deleted.":["L'élément n'a pas pu être supprimé définitivement."],"The item could not be restored.":["L'élément n'a pas pu être rétabli."],"The item you picked as parent holds another kind of content. Pick a parent of the same content type as this item.":["L'élément que vous avez choisi comme parent contient un autre genre de contenu. Choisissez un parent du même type de contenu que cet élément."],"The item you picked as parent is in the trash. Restore it, or pick another parent.":["L'élément que vous avez choisi comme parent est dans la corbeille. Rétablissez-le, ou choisissez un autre parent."],"The item you picked as parent no longer exists. Reload the page and pick another parent.":["L'élément que vous avez choisi comme parent n'existe plus. Rechargez la page et choisissez un autre parent."],"The media library could not be loaded.":["La bibliothèque de médias n'a pas pu être chargée."],"The name changes. Nothing stored under this field moves.":["Le nom change. Rien de ce qui est stocké sous ce champ ne bouge."],"The name could not be updated.":["Le nom n'a pas pu être mis à jour."],"The new order has to name every field group exactly once. Reload the page and move the groups again.":["Le nouvel ordre doit nommer chaque groupe de champs exactement une fois. Rechargez la page et déplacez les groupes à nouveau."],"The new order has to name every field of this content type exactly once. Reload the page and move the fields again.":["Le nouvel ordre doit nommer chaque champ de ce type de contenu exactement une fois. Rechargez la page et déplacez les champs à nouveau."],"The next check runs in %(time)s.":["La prochaine vérification aura lieu dans %(time)s."],"The number of revisions to keep has to be a whole number, and it cannot be negative. Enter a different number.":["Le nombre de révisions à conserver doit être un nombre entier, et il ne peut pas être négatif. Saisissez un autre nombre."],"The registry could not be reached.":["Le registre n'a pas pu être joint."],"The role could not be changed.":["Le rôle n'a pas pu être modifié."],"The rule on %(source)s names nothing to match. Pick a value, or remove the rule.":["La règle sur %(source)s ne nomme rien à faire correspondre. Choisissez une valeur, ou retirez la règle."],"The rules could not be loaded.":["Les règles n'ont pas pu être chargées."],"The rules on %(field)s lead back to %(field)s itself, so nothing can decide whether to show it. Point one of them at another field.":["Les règles de %(field)s reviennent à %(field)s lui-même, rien ne peut donc décider de l'afficher. Faites pointer l'une d'elles vers un autre champ."],"The same item was picked twice for %(field)s. Pick each item once.":["Le même élément a été choisi deux fois pour %(field)s. Choisissez chaque élément une seule fois."],"The server could not be reached, so nothing was changed.":["Le serveur n'a pas pu être joint, rien n'a donc été changé."],"The server could not be reached, so nothing was saved.":["Le serveur n'a pas pu être joint, rien n'a donc été enregistré."],"The server could not be reached, so nothing was uploaded.":["Le serveur n'a pas pu être joint, rien n'a donc été téléversé."],"The setting %(setting)s cannot hold the value it was given. Check what this setting takes and try again.":["Le réglage %(setting)s ne peut pas contenir la valeur donnée. Vérifiez ce que ce réglage accepte et réessayez."],"The setting %(setting)s falls outside the others. Keep min below max and the default inside the bounds.":["Le réglage %(setting)s sort des autres. Gardez min sous max et la valeur par défaut dans les limites."],"The settings could not be read, so nothing can be changed here yet.":["Les réglages n'ont pas pu être lus, donc rien ne peut encore être modifié ici."],"The site default":["La langue par défaut du site"],"The site may already hold part of this file. Import it again to see what is left.":["Le site contient peut-être déjà une partie de ce fichier. Importez-le à nouveau pour voir ce qu'il reste."],"The source %(source)s does not offer %(operator)s. Pick one of the comparisons it does offer.":["La source %(source)s n'offre pas %(operator)s. Choisissez une des comparaisons qu'elle offre."],"The theme %(name)s carries no %(file)s, so Gophenberg cannot tell what it is. Put that file at the top level of the zip and package the theme again.":["Le thème %(name)s ne contient aucun %(file)s, Gophenberg ne peut donc pas savoir ce que c'est. Placez ce fichier au premier niveau du zip et réempaquetez le thème."],"The theme %(name)s could not be read, so it cannot serve your site. Upload it again, or choose another theme.":["Le thème %(name)s n'a pas pu être lu, il ne peut donc pas servir votre site. Téléversez-le de nouveau, ou choisissez un autre thème."],"The theme %(name)s did not start, so your site is still served by the theme it had. Ask whoever looks after your site to check the server log for what the theme reported.":["Le thème %(name)s n'a pas démarré, votre site est donc toujours servi par le thème qu'il avait. Demandez à la personne qui s'occupe de votre site de regarder ce que le thème a signalé dans le journal du serveur."],"The theme %(name)s does not carry %(path)s as a file, so there is nothing to run. Package the built theme rather than its source.":["Le thème %(name)s ne contient pas %(path)s comme fichier, il n'y a donc rien à exécuter. Empaquetez le thème construit plutôt que sa source."],"The theme %(name)s does not carry %(path)s as a folder, so its styles and scripts are missing. Package the built theme rather than its source.":["Le thème %(name)s ne contient pas %(path)s comme dossier, ses styles et ses scripts manquent donc. Empaquetez le thème construit plutôt que sa source."],"The theme %(name)s holds a link to another file at %(path)s, and a theme may only carry real files. Replace it and package the theme again.":["Le thème %(name)s contient un lien vers un autre fichier à %(path)s, et un thème ne peut contenir que de vrais fichiers. Remplacez-le et réempaquetez le thème."],"The theme %(name)s is serving your site right now, so it cannot be replaced. Deactivate it first, or install this copy under another name.":["Le thème %(name)s sert votre site en ce moment, il ne peut donc pas être remplacé. Désactivez-le d'abord, ou installez cette copie sous un autre nom."],"The theme %(name)s is the one chosen, but it is not installed, so your site is served by the built-in renderer. Upload the theme again, or choose another one.":["Le thème %(name)s est celui choisi, mais il n'est pas installé, votre site est donc servi par le moteur de rendu intégré. Téléversez de nouveau le thème, ou choisissez-en un autre."],"The theme %(name)s was built on theme kit %(declared)s, and this site serves %(served)s. Build the theme again against a kit this site serves, then install it.":["Le thème %(name)s a été compilé avec le kit de thèmes %(declared)s, et ce site sert %(served)s. Compilez le thème à nouveau avec un kit que ce site sert, puis installez-le."],"The trash could not be emptied.":["La corbeille n'a pas pu être vidée."],"The update failed before anything changed.":["La mise à jour a échoué avant que quoi que ce soit ne change."],"The update to %(to)s failed its start check, and Gophenberg cannot go back to %(from)s on its own.":["La mise à jour vers %(to)s a échoué à sa vérification de démarrage, et Gophenberg ne peut pas revenir à %(from)s de lui-même."],"The update to %(to)s failed.":["La mise à jour vers %(to)s a échoué."],"The update to Gophenberg %(version)s failed to complete. Please attempt the update again now.":["La mise à jour vers Gophenberg %(version)s n'a pas pu aboutir. Veuillez relancer la mise à jour maintenant."],"The updates could not be read, so nothing can be updated here yet.":["Les mises à jour n'ont pas pu être lues, donc rien ne peut encore être mis à jour ici."],"The user could not be created.":["L'utilisateur n'a pas pu être créé."],"The values stored under it do not follow.":["Les valeurs enregistrées dessous ne le suivent pas."],"Theme":["Thème"],"Themes":["Thèmes"],"Themes could not be loaded.":["Les thèmes n'ont pas pu être chargés."],"There is no content type called %(value)s. Pick a type your site holds, or register it first.":["Il n'existe aucun type de contenu appelé %(value)s. Choisissez un type que votre site possède, ou déclarez-le d'abord."],"There is no content type called %(value)s. Pick one of the types your site holds and try again.":["Il n'existe aucun type de contenu appelé %(value)s. Choisissez un des types que votre site possède et réessayez."],"There is no kind of field called %(value)s. Pick one of these instead: %(allowed)s.":["Il n'existe aucun genre de champ appelé %(value)s. Choisissez plutôt parmi ceux-ci : %(allowed)s."],"There is no page kind called %(value)s. Pick one of these instead: %(allowed)s.":["Il n'existe aucun genre de page appelé %(value)s. Choisissez plutôt parmi ceux-ci : %(allowed)s."],"There is no status called %(value)s. Pick one of these instead: %(allowed)s.":["Il n'existe aucun état appelé %(value)s. Choisissez plutôt parmi ceux-ci : %(allowed)s."],"There is nothing at this address. Check the link and try again.":["Il n'y a rien à cette adresse. Vérifiez le lien et réessayez."],"There is nothing to roll back to, because your site has not been through a theme change yet. Install a theme first, then a rollback has somewhere to go.":["Il n'y a rien vers quoi revenir, car votre site n'a pas encore changé de thème. Installez d'abord un thème, et le retour aura alors une destination."],"These files could not be read.":["Ces fichiers n'ont pas pu être lus."],"These were left alone, because nobody confirmed losing them.":["Ceux-ci ont été laissés tels quels, car personne n'a confirmé leur perte."],"This content type does not exist any more. Reload the page to see the types your site holds now.":["Ce type de contenu n'existe plus. Rechargez la page pour voir les types que votre site possède maintenant."],"This content type does not nest, so one of its items cannot sit inside another. Mark the type as Nests first.":["Ce type de contenu ne s'imbrique pas, un de ses éléments ne peut donc pas se trouver dans un autre. Marquez d'abord le type comme Imbriqué."],"This content type has no field called %(field)s. Check the name, or declare the field on the type first.":["Ce type de contenu n'a aucun champ appelé %(field)s. Vérifiez le nom, ou déclarez d'abord le champ sur le type."],"This content type is turned off, so its content is not served or edited. Activate it first.":["Ce type de contenu est désactivé, son contenu n'est donc ni servi ni modifié. Activez-le d'abord."],"This content type still holds content, so it cannot be deleted. Move or delete its items first.":["Ce type de contenu contient encore du contenu, il ne peut donc pas être supprimé. Déplacez ou supprimez d'abord ses éléments."],"This definitions file is larger than the %(max)s bytes Gophenberg reads in one request. Split it, or raise the limit your site runs with.":["Ce fichier de définitions dépasse les %(max)s octets que Gophenberg lit en une requête. Divisez-le, ou relevez la limite de votre site."],"This field holds no layouts yet.":["Ce champ ne contient pas encore de dispositions."],"This field would stand inside too many containers. Put it nearer the top and try again.":["Ce champ se trouverait dans trop de conteneurs. Placez-le plus près du niveau supérieur et réessayez."],"This file could not be opened as a zip. Package the theme again and upload the new file.":["Ce fichier n'a pas pu être ouvert comme zip. Réempaquetez le thème et téléversez le nouveau fichier."],"This file is larger than the upload limit. Upload a smaller file.":["Ce fichier dépasse la limite de téléversement. Téléversez un fichier plus petit."],"This file is named %(extension)s but it holds %(detected)s content. Upload it under a name that matches what is inside it.":["Ce fichier est nommé %(extension)s mais il contient du %(detected)s. Téléversez-le sous un nom qui correspond à ce qu'il contient."],"This file matches the site, so there is nothing to change.":["Ce fichier correspond au site, il n'y a donc rien à changer."],"This file says it was written in format %(declared)s, which is not a version Gophenberg can read. Export the definitions again from the site they came from.":["Ce fichier indique le format %(declared)s, qui n'est pas une version que Gophenberg sait lire. Exportez à nouveau les définitions depuis le site d'origine."],"This file was written in format %(declared)s, and this release reads %(served)s. Upgrade the site the file came from, or this one.":["Ce fichier est écrit au format %(declared)s, et cette version lit %(served)s. Mettez à jour le site d'origine du fichier, ou celui-ci."],"This group holds no fields yet.":["Ce groupe ne contient pas encore de champs."],"This install of Gophenberg has no install root, so it updates by hand.":["Cette installation de Gophenberg n'a pas de racine d'installation, elle se met donc à jour à la main."],"This install of Gophenberg updates by hand.":["Cette installation de Gophenberg se met à jour à la main."],"This is a custom build of Gophenberg, so it updates by hand.":["Il s'agit d'une version compilée sur mesure de Gophenberg, elle se met donc à jour à la main."],"This item cannot go straight to that status from the one it holds now. Save it as a draft first, then try again.":["Cet élément ne peut pas passer directement à cet état depuis celui qu'il a maintenant. Enregistrez-le d'abord comme brouillon, puis réessayez."],"This item does not exist, and it may have been deleted. Go back to the list to see what is there.":["Cet élément n'existe pas, et il a peut-être été supprimé. Revenez à la liste pour voir ce qui s'y trouve."],"This item is already in the trash. Restore it first to work on it again.":["Cet élément est déjà dans la corbeille. Rétablissez-le d'abord pour y retravailler."],"This item is in the trash. Restore it first to work on it again.":["Cet élément est dans la corbeille. Rétablissez-le d'abord pour y retravailler."],"This item is not in the trash, so there is nothing to restore. Open it from the list to work on it as it is.":["Cet élément n'est pas dans la corbeille, il n'y a donc rien à rétablir. Ouvrez-le depuis la liste pour travailler dessus tel quel."],"This item still holds items nested inside it. Move or delete those first.":["Cet élément contient encore des éléments imbriqués. Déplacez-les ou supprimez-les d'abord."],"This kind of field holds no fields inside it. Put the field in a section or a repeater instead.":["Ce type de champ ne contient aucun champ. Placez le champ dans une section ou dans un répéteur."],"This media item is not in the library, and someone may have deleted it. Reload the page to see what is there now.":["Ce média n'est pas dans la bibliothèque, et quelqu'un l'a peut-être supprimé. Rechargez la page pour voir ce qui s'y trouve maintenant."],"This picture could not be read, so nothing was stored. The file may be damaged, so open it on your computer and upload it again.":["Cette image n'a pas pu être lue, rien n'a donc été stocké. Le fichier est peut-être endommagé, ouvrez-le sur votre ordinateur et téléversez-le de nouveau."],"This picture is %(width)s by %(height)s pixels, over the limit of %(max)s pixels in all. Make it smaller and upload it again.":["Cette image fait %(width)s par %(height)s pixels, au-delà de la limite de %(max)s pixels au total. Réduisez-la et téléversez-la de nouveau."],"This post changed elsewhere. Reload before saving again.":["Cet article a changé ailleurs. Rechargez avant d'enregistrer de nouveau."],"This request came from a page on another site, so it was refused. Open the admin on this site and try again.":["Cette requête vient d'une page d'un autre site, elle a donc été refusée. Ouvrez l'administration sur ce site et réessayez."],"This request carried %(attribute)s, which fields do not take. Reload the page so the admin and the server agree again.":["Cette requête portait %(attribute)s, que les champs n'acceptent pas. Rechargez la page pour que l'administration et le serveur concordent à nouveau."],"This request left out %(field)s, which Gophenberg needs. Reload the page and try again.":["Cette requête a omis %(field)s, dont Gophenberg a besoin. Rechargez la page et réessayez."],"This rule reads a source called %(source)s, and nothing on your site declares one. A plugin that added it may have been removed.":["Cette règle lit une source nommée %(source)s, et rien sur votre site n'en déclare. Une extension qui l'ajoutait a pu être retirée."],"This site cannot write to its themes folder, so no theme can be installed. Ask whoever looks after your site to make the folder that %(setting)s points at writable. A read-only mount is the usual cause.":["Ce site ne peut pas écrire dans son dossier de thèmes, aucun thème ne peut donc être installé. Demandez à la personne qui s'occupe de votre site de rendre accessible en écriture le dossier vers lequel pointe %(setting)s. Un montage en lecture seule en est la cause habituelle."],"This site does not check for updates on its own.":["Ce site ne recherche pas de mises à jour de lui-même."],"This site has nowhere to keep themes, so no theme can be installed. Ask whoever looks after your site to point %(setting)s at a folder the server can write to.":["Ce site n'a nulle part où garder les thèmes, aucun thème ne peut donc être installé. Demandez à la personne qui s'occupe de votre site de faire pointer %(setting)s vers un dossier où le serveur peut écrire."],"This site has nowhere to store uploads, so nothing can be uploaded. Ask whoever looks after your site to point %(setting)s at a folder the server can write to.":["Ce site n'a nulle part où stocker les téléversements, rien ne peut donc être téléversé. Demandez à la personne qui s'occupe de votre site de faire pointer %(setting)s vers un dossier où le serveur peut écrire."],"This site will not receive automatic updates for new versions of Gophenberg.":["Ce site ne recevra pas de mises à jour automatiques pour les nouvelles versions de Gophenberg."],"This theme is over the limit of %(max)s bytes, packed or unpacked. Leave out what the theme does not need and package it again.":["Ce thème dépasse la limite de %(max)s octets, compressé ou non. Retirez ce dont le thème n'a pas besoin et réempaquetez-le."],"This type will answer under /%(word)s.":["Ce type répondra sous /%(word)s."],"This update needs a backup of the database, and the site stays down if the new version does not start.":["Cette mise à jour nécessite une sauvegarde de la base de données, et le site reste hors service si la nouvelle version ne démarre pas."],"This zip holds %(entries)s files, more than the %(max)s a theme may carry. Package only the built theme.":["Ce zip contient %(entries)s fichiers, plus que les %(max)s qu'un thème peut contenir. Empaquetez seulement le thème construit."],"Through":["Via"],"Thumbnail":["Miniature"],"Title":["Titre"],"Two field groups in this file share the key %(key)s. Give one of them a different key and import again.":["Deux groupes de champs de ce fichier partagent la clé %(key)s. Donnez une clé différente à l'un d'eux et importez à nouveau."],"Two rule sources are registered under the name %(param)s. A plugin is declaring a source your site already holds.":["Deux sources de règles sont enregistrées sous le nom %(param)s. Une extension déclare une source que votre site possède déjà."],"Type":["Type"],"Type a whole number in both boxes before saving.":["Saisissez un nombre entier dans les deux cases avant d'enregistrer."],"Undo":["Annuler"],"Unpacking the update…":["Décompression de la mise à jour…"],"Unsaved changes":["Modifications non enregistrées"],"Update":["Mettre à jour"],"Update failed.":["La mise à jour a échoué."],"Update to Gophenberg %(version)s?":["Mettre à jour vers Gophenberg %(version)s ?"],"Update to version %(version)s":["Mettre à jour vers la version %(version)s"],"Updates":["Mises à jour"],"Upload theme":["Téléverser un thème"],"Uploaded %s file.":["%s fichier téléversé.","%s fichiers téléversés.","%s fichiers téléversés."],"Users":["Utilisateurs"],"Users could not be loaded.":["Les utilisateurs n'ont pas pu être chargés."],"Value":["Valeur"],"Verifying the unpacked files…":["Vérification des fichiers décompressés…"],"Version":["Version"],"Videos":["Vidéos"],"Visit Site":["Aller sur le site"],"Web address":["Adresse web"],"What each Linked from field reads":["Ce que lit chaque champ Lié depuis"],"What it points at changed, so its stored values go with it.":["Ce qu'il vise a changé, donc ses valeurs enregistrées partent avec lui."],"Where %(group)s appears":["Où apparaît %(group)s"],"While your site is being updated, it keeps serving until Gophenberg restarts on the new version.":["Pendant la mise à jour, votre site reste en ligne jusqu'au redémarrage de Gophenberg sur la nouvelle version."],"Without a rule this field always shows.":["Sans aucune règle ce champ s'affiche toujours."],"Without a rule this group appears nowhere.":["Sans une règle ce groupe n'apparaît nulle part."],"Yes":["Oui"],"Yes or no":["Oui ou non"],"You can update from Gophenberg %(running)s to Gophenberg %(version)s manually:":["Vous pouvez mettre à jour de Gophenberg %(running)s vers Gophenberg %(version)s manuellement :"],"You cannot change your own role.":["Vous ne pouvez pas changer votre propre rôle."],"You cannot update because Gophenberg %(version)s requires PostgreSQL version %(postgresql)s or higher.":["Vous ne pouvez pas mettre à jour car Gophenberg %(version)s nécessite la version %(postgresql)s de PostgreSQL ou une version ultérieure."],"You have the latest version of Gophenberg.":["Vous avez la dernière version de Gophenberg."],"Your language":["Votre langue"],"Your role does not allow %(capability)s.":["Votre rôle ne permet pas %(capability)s."],"Your server pins the site to the theme %(name)s, so themes cannot be changed here. Ask whoever looks after your site to remove the pin.":["Votre serveur fixe le site au thème %(name)s, les thèmes ne peuvent donc pas être changés ici. Demandez à la personne qui s'occupe de votre site de retirer cette fixation."],"Your site always needs one default content type, so this one cannot be turned off or deleted. Make another type the default first.":["Votre site a toujours besoin d'un type de contenu par défaut, celui-ci ne peut donc être ni désactivé ni supprimé. Rendez d'abord un autre type par défaut."],"a content type":["un type de contenu"],"account\u0004Role":["Rôle"],"account\u0004Status":["État"],"action label\u0004Duplicate":["Dupliquer"],"action label\u0004Duplicate…":["Dupliquer…"],"address":["adresse"],"admin section\u0004Content Types":["Types de contenu"],"admin section\u0004Field Groups":["Groupes de champs"],"admin section\u0004Language":["Langue"],"admin section\u0004Media":["Médias"],"admin section\u0004Settings":["Réglages"],"admin section\u0004Themes":["Thèmes"],"column\u0004Date":["Date"],"content type\u0004\"%s\" permanently deleted.":["Type de contenu « %s » supprimé définitivement."],"content type\u0004\"%s\" successfully created.":["Type de contenu « %s » créé avec succès."],"content type\u0004Status":["État"],"field\u0004Name":["Nom"],"field group\u0004Status":["Statut"],"field type\u0004Choice":["Choix"],"field type\u0004Color":["Couleur"],"field type\u0004Date":["Date"],"field type\u0004Flexible content":["Contenu flexible"],"field type\u0004Gallery":["Galerie"],"field type\u0004Kind":["Genre"],"field type\u0004Layout":["Disposition"],"field type\u0004Link":["Lien"],"field type\u0004Media":["Média"],"field type\u0004Range":["Plage"],"field type\u0004Repeater":["Répéteur"],"field type\u0004Section":["Section"],"field type\u0004Select":["Liste déroulante"],"file size\u0004%1$s %2$s":["%1$s %2$s"],"file type group\u0004Archives":["Archives"],"file type group\u0004Audio":["Sons"],"file type group\u0004Video":["Vidéos"],"holds":["contient"],"holds anything":["contient quelque chose"],"https://www.w3.org/WAI/tutorials/images/decision-tree/":["https://www.w3.org/WAI/tutorials/images/decision-tree/"],"image dimensions\u0004%1$s × %2$s":["%1$s par %2$s"],"is":["est"],"is above":["est supérieur à"],"is below":["est inférieur à"],"is empty":["est vide"],"is not":["n'est pas"],"panel button label\u0004Settings":["Réglages"],"person\u0004Name":["Nom"],"post\u0004%s (Copy)":["%s (copie)"],"post\u0004Status":["État"],"post status\u0004Draft":["Brouillon"],"post status\u0004Published":["Publié"],"post status\u0004Trash":["Corbeille"],"post type general name\u0004Pages":["Pages"],"post type general name\u0004Posts":["Articles"],"post type singular name\u0004Page":["Page"],"post type singular name\u0004Post":["Article"],"relation target\u0004None":["Aucun"],"role\u0004Administrator":["Administrateur"],"role\u0004Author":["Auteur"],"role\u0004Editor":["Éditeur"],"role\u0004Member":["Membre"],"role\u0004No role":["Sans rôle"],"status filter\u0004All":["Tout"],"taxonomy general name\u0004Categories":["Catégories"],"taxonomy singular name\u0004Category":["Catégorie"],"theme\u0004Status":["État"],"trash\u0004Restore":["Rétablir"],"unit symbol\u0004B":["o"],"unit symbol\u0004EB":["Eo"],"unit symbol\u0004GB":["Go"],"unit symbol\u0004KB":["Ko"],"unit symbol\u0004MB":["Mo"],"unit symbol\u0004PB":["Po"],"unit symbol\u0004TB":["To"],"unit symbol\u0004YB":["Yo"],"unit symbol\u0004ZB":["Zo"],"v%(version)s":["v%(version)s"],"verb\u0004Trash…":["Mettre à la corbeille…"],"verb\u0004View":["Voir"],"{day} {month} {year}":["{day} {month} {year}"]} diff --git a/frontend/src/router.tsx b/frontend/src/router.tsx index 40ac5de0..4ce931ba 100644 --- a/frontend/src/router.tsx +++ b/frontend/src/router.tsx @@ -12,7 +12,7 @@ import { import type { RouterHistory } from '@tanstack/react-router' import { __ } from '@wordpress/i18n' -import { MANAGE_SETTINGS, MANAGE_THEMES, MANAGE_TYPES, MANAGE_USERS } from '@gophenberg/frontend-sdk' +import { MANAGE_SETTINGS, MANAGE_THEMES, MANAGE_TYPES, MANAGE_USERS, UPDATE_CORE } from '@gophenberg/frontend-sdk' import { adminBasepath } from './basepath' import { CapabilityGate } from './CapabilityGate' @@ -123,6 +123,13 @@ const settingsRoute = createRoute({ component: lazyRouteComponent(() => import('./settings/SettingsScreen'), 'SettingsScreen'), }) +const updatesRoute = createRoute({ + getParentRoute: () => adminRoute, + path: '/update-core', + staticData: { capability: UPDATE_CORE }, + component: lazyRouteComponent(() => import('./updates/UpdatesScreen'), 'UpdatesScreen'), +}) + const editorRoute = createRoute({ getParentRoute: () => rootRoute, path: '/content/$typeKey/$postId/edit', @@ -142,6 +149,7 @@ const routeTree = rootRoute.addChildren([ newUserRoute, themesRoute, settingsRoute, + updatesRoute, ]), ...plugins.flatMap((plugin) => plugin.routes(framedRoute)), ]), diff --git a/frontend/src/settings/api.ts b/frontend/src/settings/api.ts index 64d9765b..34ffdf69 100644 --- a/frontend/src/settings/api.ts +++ b/frontend/src/settings/api.ts @@ -17,6 +17,8 @@ const listSettingsSchema = z.object({ toast_milliseconds: z.number(), toast_name_length: z.number(), format_locale: z.string(), + updates_progress_milliseconds: z.number(), + updates_restart_wait_milliseconds: z.number(), }) const errorSchema = z.object({ @@ -31,7 +33,7 @@ export type SiteSettings = z.infer /** The settings a request asks the site to store. */ export type SettingsAsked = Partial -/** The settings every list follows, as the server's environment names them. */ +/** The settings every list and the Updates screen follow, as the server's environment names them. */ export type ListSettings = z.infer /** diff --git a/frontend/src/test/classes.ts b/frontend/src/test/classes.ts new file mode 100644 index 00000000..ffcccbd4 --- /dev/null +++ b/frontend/src/test/classes.ts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { render } from '@testing-library/react' +import type { ReactElement } from 'react' + +/** + * Returns the classes WPDS draws an element with when it renders on its own. + * @param element - The element to render. + * @returns The class attribute of the rendered element. + */ +export function classesOf(element: ReactElement): string { + const { container, unmount } = render(element) + const classes = (container.firstElementChild as HTMLElement).className + unmount() + return classes +} diff --git a/frontend/src/test/navigation-items.test.tsx b/frontend/src/test/navigation-items.test.tsx index 33249ebb..57947f66 100644 --- a/frontend/src/test/navigation-items.test.tsx +++ b/frontend/src/test/navigation-items.test.tsx @@ -10,6 +10,7 @@ import { pageIcon, postIcon, settingsIcon, + updateIcon, } from '@gophenberg/frontend-sdk' import { http, HttpResponse, server } from '@gophenberg/frontend-sdk/testing' import { render, screen, within } from '@testing-library/react' @@ -75,6 +76,7 @@ test('lists every sidebar row as an item of one list, the types first', async () 'Users', 'Language', 'Settings', + 'Updates', ]) }) @@ -97,6 +99,7 @@ test('draws each sidebar row with the glyph WordPress draws for it, other types ['Users', people], ['Language', languageIcon], ['Settings', settingsIcon], + ['Updates', updateIcon], ] for (const [name, glyph] of glyphs) { expect(drawingOf(sidebar.getByRole('link', { name })), name).toBe(drawingOf(glyph)) diff --git a/frontend/src/test/outline.test.tsx b/frontend/src/test/outline.test.tsx index ec6b137d..6dc4614d 100644 --- a/frontend/src/test/outline.test.tsx +++ b/frontend/src/test/outline.test.tsx @@ -20,6 +20,7 @@ const TITLES: Record = { '/themes': 'Themes', '/language': 'Language', '/settings': 'Settings', + '/update-core': 'Gophenberg Updates', } const FRAMED = Object.keys(TITLES) diff --git a/frontend/src/test/render.tsx b/frontend/src/test/render.tsx index ae69e9bd..e745add9 100644 --- a/frontend/src/test/render.tsx +++ b/frontend/src/test/render.tsx @@ -7,6 +7,7 @@ import { MANAGE_THEMES, MANAGE_TYPES, MANAGE_USERS, + UPDATE_CORE, } from '@gophenberg/frontend-sdk' import { createAuthQueryClient } from '@gopherium/react-auth' import type { User } from '@gopherium/react-auth' @@ -29,6 +30,7 @@ export const adminCapabilities = [ MANAGE_TYPES, MANAGE_SETTINGS, CHANGE_OTHERS_WORK, + UPDATE_CORE, ] /** The account tests render as, an administrator unless a test names another role. */ diff --git a/frontend/src/test/role-navigation.test.tsx b/frontend/src/test/role-navigation.test.tsx index 98108b5e..0e1b18f8 100644 --- a/frontend/src/test/role-navigation.test.tsx +++ b/frontend/src/test/role-navigation.test.tsx @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 -import { CHANGE_OTHERS_WORK, MANAGE_THEMES } from '@gophenberg/frontend-sdk' +import { CHANGE_OTHERS_WORK, MANAGE_THEMES, UPDATE_CORE } from '@gophenberg/frontend-sdk' import { http, HttpResponse, server } from '@gophenberg/frontend-sdk/testing' import { defaultUser } from '@gopherium/react-auth/testing' import { screen, waitFor } from '@testing-library/react' @@ -12,7 +12,7 @@ import { warmPostsScreen } from './warm' warmPostsScreen() /** The gated screens, each behind the capability it asks for. */ -const GATED = ['Users', 'Themes', 'Content Types', 'Settings'] +const GATED = ['Users', 'Themes', 'Content Types', 'Settings', 'Updates'] /** The screens every signed in role reaches. */ const OPEN = ['Media', 'Language'] @@ -120,3 +120,27 @@ test('leaves an administrator on the gated screen it asked for', async () => { expect(await screen.findByRole('heading', { name: 'Users' })).toBeInTheDocument() }) + +test('shows a role carrying only the update capability the Updates screen alone', async () => { + renderAt('/', holding('maintainer', [UPDATE_CORE])) + + await screen.findByRole('link', { name: 'Media' }) + + expect(screen.getByRole('link', { name: 'Updates' })).toHaveAttribute('href', '/admin/update-core') + for (const label of GATED.filter((gated) => gated !== 'Updates')) { + expect(screen.queryByRole('link', { name: label })).toBeNull() + } +}) + +test('leaves a role carrying the update capability on the Updates screen it asked for', async () => { + renderAt('/update-core', holding('maintainer', [UPDATE_CORE])) + + expect(await screen.findByRole('heading', { level: 2, name: 'Gophenberg Updates' })).toBeInTheDocument() +}) + +test('answers a deep link into the Updates screen without update_core by opening the default list', async () => { + renderAt('/update-core', holding('editor', [CHANGE_OTHERS_WORK])) + + expect(await screen.findByRole('heading', { name: 'Posts', level: 2 })).toBeInTheDocument() + await waitFor(() => expect(screen.queryByRole('heading', { name: 'Gophenberg Updates' })).toBeNull()) +}) diff --git a/frontend/src/test/router.test.tsx b/frontend/src/test/router.test.tsx index 97ae1fd0..590e51e4 100644 --- a/frontend/src/test/router.test.tsx +++ b/frontend/src/test/router.test.tsx @@ -131,8 +131,9 @@ test('renders a navigation entry for every active type, core and plugin section' const nav = await screen.findByRole('region', { name: 'Navigation' }) await within(nav).findByRole('link', { name: 'Posts' }) + await within(nav).findByRole('link', { name: 'Updates' }) expect(within(nav).queryAllByRole('link')).toHaveLength( - 1 + coreNav.length + plugins.flatMap((plugin) => plugin.nav).length, + 1 + coreNav.length + 1 + plugins.flatMap((plugin) => plugin.nav).length, ) }) diff --git a/frontend/src/test/settings-api.test.ts b/frontend/src/test/settings-api.test.ts index 0abd8636..df9c4aff 100644 --- a/frontend/src/test/settings-api.test.ts +++ b/frontend/src/test/settings-api.test.ts @@ -13,6 +13,8 @@ const LIST_SETTINGS = { toast_milliseconds: 6000, toast_name_length: 45, format_locale: 'de-DE', + updates_progress_milliseconds: 2000, + updates_restart_wait_milliseconds: 300000, } test('reads the settings every list follows, as the server names them', async () => { diff --git a/frontend/src/test/setup.ts b/frontend/src/test/setup.ts index 14e42a28..e0fa2a24 100644 --- a/frontend/src/test/setup.ts +++ b/frontend/src/test/setup.ts @@ -10,6 +10,7 @@ import { afterAll, beforeEach } from 'vitest' import { DEFAULT_LOCALE } from '../i18n/catalog' import { DOMAIN } from '../i18n/start' import { siteSettings } from './siteSettings' +import { upToDate } from './updatesOverview' installTestEnvironment() configure({ asyncUtilTimeout: 2000 }) @@ -38,6 +39,7 @@ beforeEach(() => { server.use(http.get('/api/types', () => HttpResponse.json({ items: [builtInType] }))) server.use(http.get('/api/groups', () => HttpResponse.json({ items: [] }))) server.use(http.get('/api/groups/params', () => HttpResponse.json({ items: [] }))) + server.use(http.get('/api/updates', () => HttpResponse.json(upToDate))) server.use(http.get('/api/content/:id/autosave', () => HttpResponse.json({}, { status: 404 }))) server.use( http.post('/api/content/:id/autosave', async ({ request, params }) => diff --git a/frontend/src/test/siteSettings.ts b/frontend/src/test/siteSettings.ts index 84cf1d20..781d8756 100644 --- a/frontend/src/test/siteSettings.ts +++ b/frontend/src/test/siteSettings.ts @@ -11,4 +11,6 @@ export const siteSettings = { toast_milliseconds: 6000, toast_name_length: 45, format_locale: 'es-ES', + updates_progress_milliseconds: 2000, + updates_restart_wait_milliseconds: 300000, } diff --git a/frontend/src/test/update-nag.test.tsx b/frontend/src/test/update-nag.test.tsx new file mode 100644 index 00000000..854abbe3 --- /dev/null +++ b/frontend/src/test/update-nag.test.tsx @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { ACCESS_ADMIN, CHANGE_OTHERS_WORK } from '@gophenberg/frontend-sdk' +import { http, HttpResponse, server } from '@gophenberg/frontend-sdk/testing' +import { defaultUser, seedSession } from '@gopherium/react-auth/testing' +import { act, screen, waitFor, within } from '@testing-library/react' +import { resetLocaleData, setLocaleData } from '@wordpress/i18n' +import { beforeEach, expect, onTestFinished, test } from 'vitest' + +import { catalogFor } from '../i18n/catalog' +import { adminUser, renderAt } from './render' +import { patchFailed, patchOffer, patchWaiting, serveUpdates, updatesAnswered } from './updatesOverview' +import { warmPostsScreen } from './warm' + +warmPostsScreen() + +beforeEach(() => server.use(http.get('/api/content', () => HttpResponse.json({ items: [], total: 0 })))) + +/** + * Returns the band of notices holding the link of the given name. + * @param name - The name of a link the band holds. + * @returns The band element. + */ +async function bandHolding(name: string): Promise { + const link = await screen.findByRole('link', { name }) + const band = link.closest('.godmin-layout__notices') + expect(band).not.toBeNull() + return band as HTMLElement +} + +/** + * Returns the band of notices when it holds a notice. + * @returns The band element, or null while it stands empty or absent. + */ +function filledBand(): Element | null { + return document.querySelector('.godmin-layout__notices:not(:empty)') +} + +test('warns an update_core holder above the screen that the patch release is available', async () => { + serveUpdates(patchWaiting) + renderAt('/content/post') + + const band = await bandHolding('Please update now') + const heading = await screen.findByRole('heading', { level: 2, name: 'Posts' }) + + expect(band).toHaveTextContent('Gophenberg 0.20.1 is available! Please update now.') + expect(within(band).getByRole('link', { name: 'Gophenberg 0.20.1' })).toHaveAttribute( + 'href', + 'https://example.com/releases/0.20.1', + ) + expect(screen.getByRole('main')).toContainElement(band) + expect(band.compareDocumentPosition(heading) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy() +}) + +test('names the update link by the words it shows, so a spoken command naming them reaches it', async () => { + serveUpdates(patchWaiting) + renderAt('/content/post') + + const band = await bandHolding('Please update now') + + expect(within(band).getByRole('link', { name: 'Please update now' })).toHaveAttribute('href', '/admin/update-core') +}) + +test('leaves the update nag without a button to dismiss it', async () => { + serveUpdates(patchWaiting) + renderAt('/content/post') + + const band = await bandHolding('Please update now') + + expect(within(band).queryByRole('button')).toBeNull() +}) + +test('warns on the settings screen as on every other admin screen', async () => { + serveUpdates(patchWaiting) + renderAt('/settings') + + expect(await bandHolding('Please update now')).toHaveTextContent('Gophenberg 0.20.1 is available!') +}) + +test('keeps the nag off the Updates screen', async () => { + serveUpdates(patchWaiting) + const client = renderAt('/update-core') + + expect(await screen.findByRole('heading', { level: 2, name: 'Gophenberg Updates' })).toBeInTheDocument() + await updatesAnswered(client) + + expect(screen.queryByRole('link', { name: 'Please update now' })).toBeNull() +}) + +test.each([ + ['no release notes', ''], + ['release notes away from the web', 'ftp://example.com/releases/0.20.1'], +])('names the version without a link when the offer carries %s, keeping it on one line', async (_condition, notes) => { + serveUpdates({ ...patchWaiting, offer: { ...patchOffer, notes } }) + renderAt('/content/post') + + const band = await bandHolding('Please update now') + + expect(band).toHaveTextContent('Gophenberg 0.20.1 is available! Please update now.') + expect(within(band).queryByRole('link', { name: 'Gophenberg 0.20.1' })).toBeNull() + expect(within(band).getByText('Gophenberg 0.20.1')).toHaveClass('gophenberg-updates__version') +}) + +test('names the version the failed update went to and links to try again while the job holds a failure', async () => { + serveUpdates(patchFailed) + renderAt('/content/post') + + const band = await bandHolding('Please attempt the update again now') + + expect(band).toHaveTextContent( + 'The update to Gophenberg 0.20.1 failed to complete. Please attempt the update again now.', + ) + expect(within(band).getByRole('link', { name: 'Please attempt the update again now' })).toHaveAttribute( + 'href', + '/admin/update-core', + ) + expect(within(band).queryByRole('button')).toBeNull() +}) + +test('shows only the failure nag while the failure names the version on offer', async () => { + serveUpdates(patchFailed) + renderAt('/content/post') + + const band = await bandHolding('Please attempt the update again now') + + expect(band).toHaveTextContent( + /^The update to Gophenberg 0\.20\.1 failed to complete\. Please attempt the update again now\.$/, + ) + expect(within(band).queryByRole('link', { name: 'Please update now' })).toBeNull() +}) + +test('warns of a newer update before the failure of the last one, as WordPress orders its nags', async () => { + serveUpdates({ ...patchFailed, offer: { ...patchOffer, version: '0.20.2', notes: '' } }) + renderAt('/content/post') + + const band = await bandHolding('Please attempt the update again now') + const retry = within(band).getByRole('link', { name: 'Please attempt the update again now' }) + const update = within(band).getByRole('link', { name: 'Please update now' }) + + expect(band).toHaveTextContent('Gophenberg 0.20.2 is available!') + expect(band).toHaveTextContent('The update to Gophenberg 0.20.1 failed to complete.') + expect(update.compareDocumentPosition(retry) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy() +}) + +test('says the update failed once the failed version is no longer on offer', async () => { + serveUpdates({ ...patchFailed, offer: null }) + renderAt('/content/post') + + expect(await bandHolding('Please attempt the update again now')).toHaveTextContent( + 'The update to Gophenberg 0.20.1 failed to complete.', + ) +}) + +test('says nothing while no update waits', async () => { + const client = renderAt('/content/post') + + expect(await screen.findByRole('heading', { level: 2, name: 'Posts' })).toBeInTheDocument() + await updatesAnswered(client) + + expect(filledBand()).toBeNull() +}) + +test('says nothing while the offer names a version this site refused', async () => { + serveUpdates({ ...patchWaiting, refused: [patchOffer.version] }) + const client = renderAt('/content/post') + + expect(await screen.findByRole('heading', { level: 2, name: 'Posts' })).toBeInTheDocument() + await updatesAnswered(client) + + expect(filledBand()).toBeNull() +}) + +test('says nothing while the overview of the updates cannot be read', async () => { + server.use(http.get('/api/updates', () => HttpResponse.json({ error: 'boom' }, { status: 500 }))) + const client = renderAt('/content/post') + + expect(await screen.findByRole('heading', { level: 2, name: 'Posts' })).toBeInTheDocument() + await updatesAnswered(client, 'error') + + expect(filledBand()).toBeNull() + expect(screen.getByRole('link', { name: 'Updates' })).toBeInTheDocument() +}) + +test('says nothing about updates to a reader without update_core', async () => { + let asked = false + server.use( + http.get('/api/updates', () => { + asked = true + return HttpResponse.json(patchFailed) + }), + ) + renderAt('/content/post', { ...defaultUser, role: 'editor', capabilities: [CHANGE_OTHERS_WORK] }) + + expect(await screen.findByRole('heading', { level: 2, name: 'Posts' })).toBeInTheDocument() + + expect(filledBand()).toBeNull() + expect(asked).toBe(false) +}) + +test('stops warning a reader whose role loses update_core while the admin stays open', async () => { + serveUpdates(patchWaiting) + const client = renderAt('/content/post') + + await bandHolding('Please update now') + act(() => seedSession(client, { ...adminUser, role: 'editor', capabilities: [ACCESS_ADMIN, CHANGE_OTHERS_WORK] })) + + await waitFor(() => expect(filledBand()).toBeNull()) +}) + +test('warns a Spanish reader in the words of WordPress es_ES', async () => { + setLocaleData(await catalogFor('es-ES'), 'gophenberg') + onTestFinished(() => resetLocaleData({}, 'gophenberg')) + serveUpdates(patchWaiting) + renderAt('/content/post') + + const band = await bandHolding('Por favor, actualiza ahora') + + expect(band).toHaveTextContent('¡Ya está disponible Gophenberg 0.20.1! Por favor, actualiza ahora.') +}) + +test('tells a Spanish reader the update failed, asking for the retry in the words of WordPress es_ES', async () => { + setLocaleData(await catalogFor('es-ES'), 'gophenberg') + onTestFinished(() => resetLocaleData({}, 'gophenberg')) + serveUpdates(patchFailed) + renderAt('/content/post') + + const band = await bandHolding('vuelve a intentarlo') + + expect(band).toHaveTextContent( + 'No se ha podido completar la actualización a Gophenberg 0.20.1. Por favor, vuelve a intentarlo.', + ) +}) diff --git a/frontend/src/test/updates-check.test.tsx b/frontend/src/test/updates-check.test.tsx new file mode 100644 index 00000000..4e6f492a --- /dev/null +++ b/frontend/src/test/updates-check.test.tsx @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { http, HttpResponse, server } from '@gophenberg/frontend-sdk/testing' +import { screen, waitFor } from '@testing-library/react' +import userEvent from '@testing-library/user-event' +import { beforeAll, expect, test } from 'vitest' + +import { renderAt } from './render' +import { checkFinding, patchWaiting, upToDate } from './updatesOverview' + +beforeAll(async () => { + await import('../updates/UpdatesScreen') +}, 120000) + +/** + * Serves a site whose overview turns into the one a check leaves, and counts the checks it answers. + * @param before - The overview the site answers before a check. + * @param after - The overview the site answers once a check ran. + * @param found - What the check answers. + * @returns The count of checks so far. + */ +function siteChecking(before: object, after: object, found: object): () => number { + let overview = before + let checks = 0 + server.use( + http.get('/api/updates', () => HttpResponse.json(overview)), + http.post('/api/updates/check', () => { + overview = after + checks += 1 + return HttpResponse.json(found) + }), + ) + return () => checks +} + +/** + * Presses the control that checks for updates once the screen shows it. + * @param name - The words the control shows. + */ +async function checkAgain(name = 'Check again.') { + await userEvent.click(await screen.findByRole('button', { name })) +} + +test('checks again and shows the update the check found in place', async () => { + const checks = siteChecking(upToDate, patchWaiting, checkFinding(patchWaiting)) + renderAt('/update-core') + + await checkAgain() + + expect( + await screen.findByRole('heading', { level: 3, name: 'An updated version of Gophenberg is available.' }), + ).toBeInTheDocument() + expect(checks()).toBe(1) + expect(screen.queryByText('No new updates found.')).toBeNull() +}) + +test('says no new update was found when the check finds nothing', async () => { + siteChecking(upToDate, upToDate, checkFinding(upToDate)) + renderAt('/update-core') + + await checkAgain() + + expect(await screen.findByText('No new updates found.', { selector: '.godmin-toast' })).toBeInTheDocument() +}) + +test('says no new update was found when the check finds the update already on offer', async () => { + siteChecking(patchWaiting, patchWaiting, checkFinding(patchWaiting)) + renderAt('/update-core') + + await checkAgain() + + expect(await screen.findByText('No new updates found.', { selector: '.godmin-toast' })).toBeInTheDocument() +}) + +test('runs the first check of a site that never checked', async () => { + const checks = siteChecking({ ...upToDate, checked_at: null }, upToDate, checkFinding(upToDate)) + renderAt('/update-core') + + await checkAgain('Check now.') + + await waitFor(() => expect(checks()).toBe(1)) + expect(await screen.findByText(/Last checked on/)).toBeInTheDocument() +}) + +test('asks a reader to wait after a check that ran moments ago', async () => { + server.use( + http.post('/api/updates/check', () => + HttpResponse.json( + { + error: 'the last check is too recent, so try again later', + code: 'check_too_soon', + meta: { retry_after: 42 }, + }, + { status: 429 }, + ), + ), + ) + renderAt('/update-core') + + await checkAgain() + + expect(await screen.findByRole('alert')).toHaveTextContent( + 'Gophenberg checked for updates moments ago. Try again later.', + ) +}) + +test('says something went wrong when the server refuses a check without saying why', async () => { + server.use(http.post('/api/updates/check', () => new HttpResponse('Bad Gateway', { status: 502 }))) + renderAt('/update-core') + + await checkAgain() + + expect(await screen.findByRole('alert')).toHaveTextContent('Something went wrong. Try again.') +}) + +test('shows a check that failed in place and toasts nothing', async () => { + const failed = { failed_at: '2026-10-22T09:30:00Z', error: 'the update site did not answer' } + siteChecking(upToDate, { ...upToDate, ...failed }, { ...checkFinding(upToDate), ...failed }) + renderAt('/update-core') + + await checkAgain() + + expect( + await screen.findByText('The check on 22/10/2026 at 09:30 failed: the update site did not answer'), + ).toBeInTheDocument() + expect(screen.queryByText('No new updates found.')).toBeNull() +}) diff --git a/frontend/src/test/updates-menu.test.tsx b/frontend/src/test/updates-menu.test.tsx new file mode 100644 index 00000000..d40cdd3d --- /dev/null +++ b/frontend/src/test/updates-menu.test.tsx @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { CHANGE_OTHERS_WORK } from '@gophenberg/frontend-sdk' +import { http, HttpResponse, server } from '@gophenberg/frontend-sdk/testing' +import { LIST_CHROME_DOMAIN, listChromeCatalogFor } from '@gopherium/godmin' +import { defaultUser } from '@gopherium/react-auth/testing' +import { screen, within } from '@testing-library/react' +import { resetLocaleData, setLocaleData } from '@wordpress/i18n' +import { beforeEach, expect, onTestFinished, test } from 'vitest' + +import { catalogFor } from '../i18n/catalog' +import { renderAt } from './render' +import { patchOffer, patchWaiting, serveUpdates, updatesAnswered } from './updatesOverview' +import { warmPostsScreen } from './warm' + +warmPostsScreen() + +beforeEach(() => server.use(http.get('/api/content', () => HttpResponse.json({ items: [], total: 0 })))) + +/** + * Returns the sidebar once its rows have arrived. + * @param name - The name the sidebar region goes by. + * @returns The sidebar region. + */ +async function menu(name = 'Navigation'): Promise { + const nav = await screen.findByRole('region', { name }) + await within(nav).findByRole('link', { name: /Posts|Entradas/ }) + return nav +} + +test('puts Updates after Settings, opening the Updates screen', async () => { + renderAt('/content/post') + + const nav = await menu() + const targets = within(nav) + .getAllByRole('link') + .map((link) => link.getAttribute('href')) + + expect(within(nav).getByRole('link', { name: 'Updates' })).toHaveAttribute('href', '/admin/update-core') + expect(targets.indexOf('/admin/update-core')).toBe(targets.indexOf('/admin/settings') + 1) +}) + +test('counts the update that waits beside the Updates label, as WordPress does', async () => { + serveUpdates(patchWaiting) + renderAt('/content/post') + + const nav = await menu() + const updates = await within(nav).findByRole('link', { name: 'Updates 1 update available' }) + + expect(within(updates).getByText('1')).toHaveAttribute('aria-hidden', 'true') +}) + +test('counts nothing while no update is on offer', async () => { + const client = renderAt('/content/post') + + const nav = await menu() + await updatesAnswered(client) + + expect(within(nav).getByRole('link', { name: 'Updates' })).toBeInTheDocument() + expect(nav.querySelector('.godmin-menu-count')).toBeNull() +}) + +test('counts nothing while the offer names a version this site refused', async () => { + serveUpdates({ ...patchWaiting, refused: [patchOffer.version] }) + const client = renderAt('/content/post') + + const nav = await menu() + await updatesAnswered(client) + + expect(within(nav).getByRole('link', { name: 'Updates' })).toBeInTheDocument() + expect(nav.querySelector('.godmin-menu-count')).toBeNull() +}) + +test('asks a reader without update_core nothing about updates and shows it no Updates row', async () => { + let asked = false + server.use( + http.get('/api/updates', () => { + asked = true + return HttpResponse.json(patchWaiting) + }), + ) + renderAt('/content/post', { ...defaultUser, role: 'editor', capabilities: [CHANGE_OTHERS_WORK] }) + + const nav = await menu() + + expect(within(nav).queryByRole('link', { name: /Updates/ })).toBeNull() + expect(asked).toBe(false) +}) + +test('names the Updates row and its count in the words of WordPress es_ES for a Spanish reader', async () => { + setLocaleData(await catalogFor('es-ES'), 'gophenberg') + setLocaleData(await listChromeCatalogFor('es-ES'), LIST_CHROME_DOMAIN) + onTestFinished(() => { + resetLocaleData({}, 'gophenberg') + resetLocaleData({}, LIST_CHROME_DOMAIN) + }) + serveUpdates(patchWaiting) + renderAt('/content/post') + + const nav = await menu('Navegación') + + expect( + await within(nav).findByRole('link', { name: 'Actualizaciones 1 actualización disponible' }), + ).toHaveAttribute('href', '/admin/update-core') +}) diff --git a/frontend/src/test/updates-run.test.tsx b/frontend/src/test/updates-run.test.tsx new file mode 100644 index 00000000..c8d62b6e --- /dev/null +++ b/frontend/src/test/updates-run.test.tsx @@ -0,0 +1,644 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { Notice } from '@gophenberg/frontend-sdk' +import { http, HttpResponse, server } from '@gophenberg/frontend-sdk/testing' +import { screen, waitFor, within } from '@testing-library/react' +import userEvent from '@testing-library/user-event' +import { resetLocaleData, setLocaleData } from '@wordpress/i18n' +import { beforeAll, beforeEach, expect, onTestFinished, test } from 'vitest' + +import { catalogFor } from '../i18n/catalog' +import { listenAt } from './announcements' +import { classesOf } from './classes' +import { renderAt } from './render' +import { siteSettings } from './siteSettings' +import { declarations } from './stylesheet' +import { + backedUpAgain, + briefUpdateTimings, + longJumpWaiting, + patchAt, + patchFailed, + patchOffer, + patchRetryFailed, + patchRolledBack, + patchRunning, + patchStaysFailed, + patchWaiting, + patchWentBack, +} from './updatesOverview' +import { warmPostsScreen } from './warm' + +/** The page that shows how to update Gophenberg. */ +const UPDATING_PAGE = 'https://docs.gophenberg.org/self-hosting/updates-and-backups/' + +warmPostsScreen() + +beforeAll(async () => { + await import('../updates/UpdatesScreen') +}, 120000) + +beforeEach(() => { + server.use( + http.get('/api/settings', () => HttpResponse.json({ ...siteSettings, ...briefUpdateTimings })), + http.get('/api/content', () => HttpResponse.json({ items: [], total: 0 })), + ) +}) + +/** What the site answers for its overview: an overview, or no answer at all while it restarts. */ +type Answer = object | 'down' + +/** + * Serves the overview the test names, which it changes as the update moves on. + * @param first - What the site answers first. + * @returns What switches the answer, settling once the site served the new answer. + */ +function siteAnswering(first: Answer): (next: Answer) => Promise { + let answer = first + let served = () => {} + server.use( + http.get('/api/updates', () => { + const held = answer + served() + return held === 'down' ? HttpResponse.error() : HttpResponse.json(held) + }), + ) + return (next) => { + answer = next + return new Promise((resolve) => { + served = resolve + }) + } +} + +/** + * Lets the screen read an answer twice, so the first read has reached the screen. + * @param site - What switches the site's answer. + * @param answer - The answer to read. + */ +async function readTwice(site: (next: Answer) => Promise, answer: Answer) { + await site(answer) + await site(answer) +} + +/** + * Records each start of an update the screen sends, answering it as the server does. + * @param answer - The overview the start answers with. + * @returns The bodies sent so far. + */ +function acceptStarts(answer: object): unknown[] { + const sent: unknown[] = [] + server.use( + http.post('/api/updates/apply', async ({ request }) => { + sent.push(await request.json()) + return HttpResponse.json(answer, { status: 202 }) + }), + ) + return sent +} + +/** The words of the button that updates to the patch release on its first try. */ +const UPDATE = 'Update to version 0.20.1' + +/** The words of the button that tries the patch release again once it failed its start check. */ +const REINSTALL = 'Re-install version 0.20.1' + +/** The title of the notice saying the patch release failed its start check past the minimum version and stays. */ +const STAYS_FAILED = 'The update to 0.20.1 failed its start check, and Gophenberg cannot go back to 0.20.0 on its own.' + +/** + * Opens the confirm of the update on offer. + * @param button - The words of the button that opens it. + * @returns The confirm dialog. + */ +async function openConfirm(button = UPDATE): Promise { + await userEvent.click(await screen.findByRole('button', { name: button })) + return screen.findByRole('alertdialog') +} + +/** + * Accepts the confirm of the update on offer and waits until it closes. + * @param button - The words of the button that opens it. + */ +async function confirmUpdate(button = UPDATE) { + const dialog = await openConfirm(button) + await userEvent.click(within(dialog).getByRole('button', { name: 'Update' })) + await waitFor(() => expect(screen.queryByRole('alertdialog')).toBeNull()) +} + +/** + * Checks that the screen shows neither the warning to back up nor the sentence leading to the button. + */ +function noBackupWarningOrLead() { + expect(screen.queryByText('Important:')).toBeNull() + expect(screen.queryByText(/manually:/)).toBeNull() +} + +/** + * Waits until the steps mark the line reading the given words as the one under way. + * @param words - The words of the line. + */ +async function underWay(words: string) { + await waitFor(() => expect(screen.getByText(words).closest('li')).toHaveAttribute('aria-current', 'step')) +} + +/** + * Returns the list of the steps the line reading the given words belongs to. + * @param words - The words of a line of the steps. + * @returns The list element. + */ +function stepsOf(words: string): HTMLElement | null { + return screen.getByText(words).closest('ol') +} + +/** + * Opens the Updates screen on a site offering an update and starts it, the start answering with an overview. + * @param waiting - The overview the site answers before the start. + * @param answered - The overview the start answers with. + * @returns What switches the site's answer. + */ +async function startUpdate(waiting: object, answered: object): Promise<(next: Answer) => Promise> { + const site = siteAnswering(waiting) + acceptStarts(answered) + renderAt('/update-core') + await confirmUpdate() + return site +} + +/** + * Opens the Updates screen on a site offering the patch release and starts the update to it. + * @returns What switches the site's answer. + */ +function updateToPatch(): Promise<(next: Answer) => Promise> { + return startUpdate(patchWaiting, patchAt('download')) +} + +test('asks before updating, naming the version and how Gophenberg goes back', async () => { + siteAnswering(patchWaiting) + renderAt('/update-core') + + const dialog = await openConfirm() + + expect(dialog).toHaveAccessibleName('Update to Gophenberg 0.20.1?') + expect(dialog).toHaveAccessibleDescription( + 'A backup of the database is taken first, and Gophenberg goes back to 0.20.0 on its own ' + + 'if the new version does not start.', + ) +}) + +test('starts nothing when the confirm is cancelled', async () => { + siteAnswering(patchWaiting) + const sent = acceptStarts(patchAt('download')) + renderAt('/update-core') + + const dialog = await openConfirm() + await userEvent.click(within(dialog).getByRole('button', { name: 'Cancel' })) + + await waitFor(() => expect(screen.queryByRole('alertdialog')).toBeNull()) + expect(sent).toEqual([]) + expect(screen.getByRole('button', { name: 'Update to version 0.20.1' })).toBeInTheDocument() +}) + +test('says in the confirm of an update past the minimum version that the site stays down when it fails', async () => { + siteAnswering({ ...patchWaiting, offer: { ...patchOffer, long_jump: true } }) + renderAt('/update-core') + + const dialog = await openConfirm() + + expect(dialog).toHaveAccessibleDescription( + 'A backup of the database is taken first, and the site stays down until you restore it ' + + 'if the new version does not start.', + ) +}) + +test('sends the version on offer once the confirm is accepted', async () => { + siteAnswering(patchWaiting) + const sent = acceptStarts(patchAt('download')) + renderAt('/update-core') + + await confirmUpdate() + + expect(sent).toEqual([{ version: '0.20.1', retry: false }]) +}) + +test('asks for a retry of a version that failed its start check here', async () => { + siteAnswering(patchWentBack) + const sent = acceptStarts(patchWentBack) + renderAt('/update-core') + + await confirmUpdate(REINSTALL) + + expect(sent).toEqual([{ version: '0.20.1', retry: true }]) +}) + +test('leaves the warning to back up and the sentence leading to the button out while the update runs', async () => { + await updateToPatch() + + await underWay('Downloading Gophenberg 0.20.1…') + + noBackupWarningOrLead() +}) + +test('drops the heading saying an update is available while it runs, as WordPress shows only progress', async () => { + await updateToPatch() + + await underWay('Downloading Gophenberg 0.20.1…') + + expect(screen.queryByRole('heading', { level: 3, name: 'An updated version of Gophenberg is available.' })).toBeNull() +}) + +test('follows the update one step at a time, marking the step under way', async () => { + const site = await updateToPatch() + + await underWay('Downloading Gophenberg 0.20.1…') + expect(screen.queryByRole('button', { name: 'Update to version 0.20.1' })).toBeNull() + site(patchAt('stage')) + await underWay('Unpacking the update…') + expect(screen.getByText('Downloading Gophenberg 0.20.1…').closest('li')).not.toHaveAttribute('aria-current') + site(patchAt('backup')) + await underWay('Backing up the database…') + expect(screen.getByText('Verifying the unpacked files…').closest('li')).not.toHaveAttribute('aria-current') + site(patchAt('switched')) + await underWay('Restarting Gophenberg…') + site('down') + await underWay('Restarting Gophenberg…') + site(patchRunning('switched')) + await underWay('Checking the new version…') +}) + +test('keeps the steps in one live region as the offer goes away at the check of the new version', async () => { + const site = await updateToPatch() + + site(patchAt('switched')) + await underWay('Restarting Gophenberg…') + const steps = stepsOf('Restarting Gophenberg…') + site(patchRunning('switched')) + await underWay('Checking the new version…') + + expect(stepsOf('Checking the new version…')).toBe(steps) +}) + +test('moves the focus to the steps once the confirm starts the update', async () => { + await updateToPatch() + + await underWay('Downloading Gophenberg 0.20.1…') + + await waitFor(() => expect(document.activeElement).toBe(stepsOf('Downloading Gophenberg 0.20.1…'))) +}) + +test('draws no focus ring around the steps, which only the screen moves the focus to', () => { + expect(declarations('.gophenberg-updates__steps:focus')).toEqual({ outline: 'none' }) +}) + +test('marks the step under way by its colour and its spinner alone', () => { + expect(Object.keys(declarations(".gophenberg-updates__steps > li[aria-current='step']"))).toEqual(['color']) +}) + +test('says the update succeeded once the new version runs and offers to reload the admin', async () => { + const polite = listenAt('polite') + const site = await updateToPatch() + + site('down') + await underWay('Restarting Gophenberg…') + site(patchRunning('committed')) + + expect(await screen.findByText('Gophenberg updated successfully.')).toBeInTheDocument() + const reload = screen.getByRole('link', { name: 'Reload the admin' }) + expect(reload).toHaveAttribute('href', '/admin/update-core') + expect(reload.className).toBe(classesOf(Reload)) + expect(screen.getByText('Current version: 0.20.1')).toBeInTheDocument() + expect(within(screen.getByRole('main')).queryByRole('list')).toBeNull() + await waitFor(() => expect(polite()).toContain('Gophenberg updated successfully.')) +}) + +test('says the update failed and Gophenberg went back, until the notice is dismissed', async () => { + const assertive = listenAt('assertive') + const site = await updateToPatch() + + site(patchAt('switched')) + await underWay('Restarting Gophenberg…') + site(patchWentBack) + + const title = await screen.findByText('The update to 0.20.1 failed.') + const description = screen.getByText('Gophenberg went back to 0.20.0 and is running normally.') + expect(title.compareDocumentPosition(description) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy() + await waitFor(() => + expect(assertive()).toContain( + 'The update to 0.20.1 failed. Gophenberg went back to 0.20.0 and is running normally.', + ), + ) + await userEvent.click(screen.getByRole('button', { name: 'Dismiss' })) + await waitFor(() => expect(screen.queryByText(/Gophenberg went back to/)).toBeNull()) + expect(screen.getByRole('button', { name: REINSTALL })).toBeInTheDocument() +}) + +test('offers the retry under the failed start check once the update went back, with no offer above it', async () => { + const site = await updateToPatch() + + site(patchAt('switched')) + await underWay('Restarting Gophenberg…') + site(patchWentBack) + + await screen.findByText('The update to 0.20.1 failed.') + const failed = screen.getByText( + 'Gophenberg 0.20.1 failed its start check on this site. Fix what failed before you try it again.', + ) + expect(failed.nextElementSibling).toBe(screen.getByRole('button', { name: REINSTALL })) + expect(screen.queryByRole('button', { name: UPDATE })).toBeNull() + noBackupWarningOrLead() +}) + +test.each([ + ['the start check', patchWentBack], + ['the rollback unit', patchRolledBack], +])('says Gophenberg went back once %s took back a first try no read caught under way', async (_by, wentBack) => { + const site = await startUpdate(patchWaiting, patchWaiting) + await underWay('Downloading Gophenberg 0.20.1…') + + site(wentBack) + + expect(await screen.findByText(/Gophenberg went back to 0.20.0/)).toBeInTheDocument() +}) + +test('keeps following a retry of a version the rollback unit took back until it goes back again', async () => { + const site = siteAnswering(patchRolledBack) + const sent = acceptStarts(patchRolledBack) + renderAt('/update-core') + + await confirmUpdate(REINSTALL) + await readTwice(site, patchRolledBack) + + await underWay('Downloading Gophenberg 0.20.1…') + expect(screen.queryByText(/Gophenberg went back to/)).toBeNull() + site(patchAt('switched')) + await underWay('Restarting Gophenberg…') + site(patchRolledBack) + expect(await screen.findByText(/Gophenberg went back to 0.20.0/)).toBeInTheDocument() + expect(sent).toEqual([{ version: '0.20.1', retry: true }]) +}) + +test('says a retry of a version the rollback unit took back failed before anything changed', async () => { + const assertive = listenAt('assertive') + const site = siteAnswering(patchRolledBack) + acceptStarts(patchRolledBack) + renderAt('/update-core') + + await confirmUpdate(REINSTALL) + await readTwice(site, { ...patchAt('download'), refused: ['0.20.1'] }) + await underWay('Downloading Gophenberg 0.20.1…') + site(patchRetryFailed) + + expect(await screen.findByText('The update failed before anything changed.')).toBeInTheDocument() + expect(screen.queryByText(/went back to/)).toBeNull() + expect(screen.getByRole('button', { name: REINSTALL })).toBeInTheDocument() + await waitFor(() => expect(assertive()).toEqual(['The update failed before anything changed.'])) +}) + +test('says the update stays failed once a release past the minimum version fails its start check', async () => { + const assertive = listenAt('assertive') + const site = await startUpdate(longJumpWaiting, { ...longJumpWaiting, job: patchAt('download').job }) + + site('down') + await underWay('Restarting Gophenberg…') + site(patchStaysFailed) + + expect(await screen.findByText(STAYS_FAILED)).toBeInTheDocument() + expect(screen.getByText('update:status', { selector: 'code' }).parentElement).toHaveTextContent( + /^Run update:status on the server to see the backup taken before the update\./, + ) + expect(screen.getByRole('link', { name: 'restore that backup' })).toHaveAttribute( + 'href', + `${UPDATING_PAGE}#restoring-on-a-server-install`, + ) + expect(screen.queryByText('Checking the new version…')).toBeNull() + expect(screen.queryByRole('heading', { level: 3 })).toBeNull() + await waitFor(() => expect(assertive()).toContain(STAYS_FAILED)) +}) + +test('says an update stays failed, speaking nothing, when the screen opens after its start check failed', async () => { + const assertive = listenAt('assertive') + siteAnswering(patchStaysFailed) + renderAt('/update-core') + + expect(await screen.findByText(STAYS_FAILED)).toBeInTheDocument() + expect(screen.getByRole('link', { name: 'restore that backup' })).toHaveAttribute( + 'href', + `${UPDATING_PAGE}#restoring-on-a-server-install`, + ) + expect(screen.queryByRole('heading', { level: 3 })).toBeNull() + expect(assertive()).toEqual([]) +}) + +test('says the update failed before anything changed, with the reason the server gave', async () => { + const assertive = listenAt('assertive') + const site = await updateToPatch() + + await underWay('Downloading Gophenberg 0.20.1…') + site(patchFailed) + + expect(await screen.findByText('The update failed before anything changed.')).toBeInTheDocument() + expect(screen.getByText('the checksum of the archive does not match the index')).toBeInTheDocument() + expect(screen.getByRole('button', { name: UPDATE })).toBeInTheDocument() + await waitFor(() => expect(assertive()).toContain('The update failed before anything changed.')) + noBackupWarningOrLead() +}) + +test('speaks nothing of an update that failed before anything changed on an earlier visit', async () => { + const assertive = listenAt('assertive') + siteAnswering(patchFailed) + renderAt('/update-core') + + expect(await screen.findByText('The update failed before anything changed.')).toBeInTheDocument() + expect(assertive()).toEqual([]) +}) + +test('keeps following an update while the overview still holds the failure of an earlier try', async () => { + const site = siteAnswering(patchFailed) + acceptStarts(patchFailed) + renderAt('/update-core') + + await confirmUpdate() + await readTwice(site, patchFailed) + + await underWay('Downloading Gophenberg 0.20.1…') + expect(screen.queryByText('The update failed before anything changed.')).toBeNull() + site(patchAt('stage')) + await underWay('Unpacking the update…') +}) + +test('keeps following a retry while the overview still names the version it went back from', async () => { + const site = siteAnswering(patchWentBack) + acceptStarts(patchWentBack) + renderAt('/update-core') + + await confirmUpdate(REINSTALL) + await readTwice(site, patchWentBack) + + await underWay('Downloading Gophenberg 0.20.1…') + expect(screen.queryByText(/Gophenberg went back to/)).toBeNull() + await readTwice(site, { ...patchAt('download'), refused: ['0.20.1'] }) + await underWay('Downloading Gophenberg 0.20.1…') + expect(screen.queryByText(/Gophenberg went back to/)).toBeNull() + site(patchAt('switched')) + await underWay('Restarting Gophenberg…') + site(patchWentBack) + expect(await screen.findByText(/Gophenberg went back to 0.20.0/)).toBeInTheDocument() +}) + +test.each([ + ['the start check', patchWentBack], + ['the rollback unit', patchRolledBack], +])('says Gophenberg went back once %s took back a retry no read caught under way', async (_by, wentBack) => { + const site = siteAnswering(wentBack) + acceptStarts(wentBack) + renderAt('/update-core') + + await confirmUpdate(REINSTALL) + await readTwice(site, wentBack) + await underWay('Downloading Gophenberg 0.20.1…') + site(backedUpAgain(wentBack)) + + expect(await screen.findByText(/Gophenberg went back to 0.20.0/)).toBeInTheDocument() + expect(screen.getByRole('button', { name: REINSTALL })).toBeInTheDocument() +}) + +test('says Gophenberg has not come back once the restart outlasts the wait the site sets', async () => { + const assertive = listenAt('assertive') + const site = await updateToPatch() + + site('down') + + expect(await screen.findByText('Gophenberg has not come back yet.')).toBeInTheDocument() + const advice = screen.getByText('update:status', { selector: 'code' }).parentElement as HTMLElement + expect(advice).toHaveTextContent('after exit code 75, and run update:status on the server') + expect(within(advice).getByText('75', { selector: 'code' })).toBeInTheDocument() + expect(screen.queryByRole('button', { name: UPDATE })).toBeNull() + await waitFor(() => expect(assertive()).toContain('Gophenberg has not come back yet.')) + noBackupWarningOrLead() +}) + +test('says the update succeeded when Gophenberg comes back after the wait passed', async () => { + const site = await updateToPatch() + + site('down') + await screen.findByText('Gophenberg has not come back yet.') + site(patchRunning('committed')) + + expect(await screen.findByText('Gophenberg updated successfully.')).toBeInTheDocument() + expect(screen.queryByText('Gophenberg has not come back yet.')).toBeNull() +}) + +test('shows in the confirm why the server refused to start the update', async () => { + siteAnswering(patchWaiting) + server.use( + http.post('/api/updates/apply', () => + HttpResponse.json( + { + error: 'refused', + code: 'update_refused', + meta: { reason: 'Gophenberg 0.20.1 needs PostgreSQL 18 or newer' }, + }, + { status: 422 }, + ), + ), + ) + renderAt('/update-core') + + const dialog = await openConfirm() + await userEvent.click(within(dialog).getByRole('button', { name: 'Update' })) + + expect( + await within(dialog).findByText( + 'Gophenberg cannot start this update: Gophenberg 0.20.1 needs PostgreSQL 18 or newer', + ), + ).toBeInTheDocument() + expect(screen.getByRole('alertdialog')).toBeInTheDocument() +}) + +test('follows the update under way once the server refuses a second start', async () => { + const site = siteAnswering(patchWaiting) + server.use( + http.post('/api/updates/apply', () => + HttpResponse.json({ error: 'another update runs', code: 'update_runs' }, { status: 409 }), + ), + ) + renderAt('/update-core') + + const dialog = await openConfirm() + site(patchAt('stage')) + await userEvent.click(within(dialog).getByRole('button', { name: 'Update' })) + + await underWay('Unpacking the update…') + expect(screen.queryByRole('button', { name: 'Update to version 0.20.1' })).toBeNull() + await waitFor(() => expect(document.activeElement).toBe(stepsOf('Unpacking the update…'))) +}) + +test('follows an update already under way when the screen opens', async () => { + siteAnswering(patchAt('stage')) + renderAt('/update-core') + + await underWay('Unpacking the update…') + expect(screen.queryByRole('button', { name: 'Update to version 0.20.1' })).toBeNull() +}) + +test('says an update already under way when the screen opens succeeded once the new version runs', async () => { + const site = siteAnswering(patchAt('backup')) + renderAt('/update-core') + await underWay('Backing up the database…') + + site('down') + await underWay('Restarting Gophenberg…') + site(patchRunning('committed')) + + expect(await screen.findByText('Gophenberg updated successfully.')).toBeInTheDocument() + expect(screen.getByRole('link', { name: 'Reload the admin' })).toHaveAttribute('href', '/admin/update-core') +}) + +test('says an update already under way when the screen opens went back once the version before it runs', async () => { + const site = siteAnswering(patchAt('backup')) + renderAt('/update-core') + await underWay('Backing up the database…') + + site(patchAt('switched')) + await underWay('Restarting Gophenberg…') + site(patchWentBack) + + expect(await screen.findByText(/Gophenberg went back to 0.20.0/)).toBeInTheDocument() +}) + +test.each([ + ['succeeded once it passes', patchRunning('committed'), 'Gophenberg updated successfully.'], + ['went back once it fails', patchWentBack, 'Gophenberg went back to 0.20.0 and is running normally.'], +])('says an update the screen opens on while the new version checks itself %s', async (_ending, ended, words) => { + const site = siteAnswering(patchRunning('switched')) + renderAt('/update-core') + + await underWay('Checking the new version…') + expect(screen.queryByRole('heading', { level: 3, name: 'You have the latest version of Gophenberg.' })).toBeNull() + site(ended) + + expect(await screen.findByText(words)).toBeInTheDocument() +}) + +test('leaves the focus on the menu when Updates opens on an update under way', async () => { + siteAnswering(patchAt('stage')) + renderAt('/content/post') + + const nav = await screen.findByRole('region', { name: 'Navigation' }) + const updates = await within(nav).findByRole('link', { name: 'Updates 1 update available' }) + await userEvent.click(updates) + + await underWay('Unpacking the update…') + expect(document.activeElement).toBe(updates) +}) + +test('follows the steps in the words of WordPress es_ES for a Spanish reader', async () => { + setLocaleData(await catalogFor('es-ES'), 'gophenberg') + onTestFinished(() => resetLocaleData({}, 'gophenberg')) + siteAnswering(patchAt('backup')) + renderAt('/update-core') + + await underWay('Haciendo copia de seguridad de la base de datos…') + expect(screen.getByText('Descomprimiendo la actualización…')).toBeInTheDocument() + expect(screen.getByText('Verificando los archivos descomprimidos…')).toBeInTheDocument() +}) diff --git a/frontend/src/test/updates-screen.test.tsx b/frontend/src/test/updates-screen.test.tsx new file mode 100644 index 00000000..a3e8cc75 --- /dev/null +++ b/frontend/src/test/updates-screen.test.tsx @@ -0,0 +1,318 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { Button } from '@gophenberg/frontend-sdk' +import { http, HttpResponse, server } from '@gophenberg/frontend-sdk/testing' +import { screen, within } from '@testing-library/react' +import { resetLocaleData, setLocaleData } from '@wordpress/i18n' +import { beforeAll, expect, onTestFinished, test } from 'vitest' + +import { catalogFor } from '../i18n/catalog' +import { classesOf } from './classes' +import { renderAt } from './render' +import { declarations } from './stylesheet' +import { patchFailed, patchOffer, patchWaiting, serveUpdates, upToDate } from './updatesOverview' + +/** The page that shows how to update Gophenberg. */ +const UPDATING_PAGE = 'https://docs.gophenberg.org/self-hosting/updates-and-backups/' + +/** How many milliseconds a minute lasts. */ +const MINUTE = 60_000 + +beforeAll(async () => { + await import('../updates/UpdatesScreen') +}, 120000) + +/** + * Returns the paragraph of the screen that reads exactly the given words. + * @param words - The whole text of the paragraph. + * @returns The paragraph element. + */ +function paragraph(words: string): Promise { + return screen.findByText((_content, element) => element?.tagName === 'P' && element.textContent === words) +} + +/** + * Opens the Updates screen on a site answering the given overview. + * @param overview - What GET /api/updates answers. + */ +async function openUpdates(overview: object) { + serveUpdates(overview) + renderAt('/update-core') + await screen.findByRole('heading', { level: 2, name: 'Gophenberg Updates' }) +} + +/** + * Returns the overview of a site whose next check runs a while from now. + * @param away - How many milliseconds from now the next check runs. + * @returns The overview. + */ +function nextCheckIn(away: number) { + return { ...upToDate, next_check: new Date(Date.now() + away).toISOString() } +} + +test('names the version that runs under the title, as WordPress does', async () => { + await openUpdates(upToDate) + + expect(await screen.findByText('Current version: 0.20.0')).toHaveClass('godmin-page__subtitle') +}) + +test('says when the site last checked, in the site format, with the check one click away', async () => { + await openUpdates(upToDate) + + const line = await paragraph('Last checked on 22/10/2026 at 09:12. Check again.') + + expect(within(line).getByRole('button', { name: 'Check again.' })).toBeInTheDocument() +}) + +test.each([ + ['minutes away', 30 * MINUTE, 'The next check runs in 30 minutes.'], + ['under a minute away', MINUTE / 3, 'The next check runs in 1 minute.'], + ['hours away', 11 * 60 * MINUTE, 'The next check runs in 11 hours.'], + ['days away', 3 * 24 * 60 * MINUTE, 'The next check runs in 3 days.'], + ['already due', -5 * MINUTE, 'The next check runs in 1 minute.'], +])('says when the next check runs while it is %s', async (_condition, away, words) => { + await openUpdates(nextCheckIn(away)) + + expect(await paragraph(words)).toBeInTheDocument() +}) + +test('says the site has not checked yet and offers the first check', async () => { + await openUpdates({ ...upToDate, checked_at: null }) + + const line = await paragraph('Gophenberg has not checked for updates yet. Check now.') + + expect(within(line).getByRole('button', { name: 'Check now.' })).toBeInTheDocument() +}) + +test('wraps the line holding the check greedily, so the control pulls no words down with it', async () => { + await openUpdates({ ...upToDate, checked_at: null }) + + const line = await paragraph('Gophenberg has not checked for updates yet. Check now.') + + expect(line).toHaveClass('gophenberg-updates__last-check') + expect(declarations('.gophenberg-updates__last-check')).toEqual({ 'text-wrap': 'wrap' }) +}) + +test('says the site does not check on its own while its checks are off', async () => { + await openUpdates({ ...upToDate, next_check: null }) + + expect(await paragraph('This site does not check for updates on its own.')).toBeInTheDocument() +}) + +test('names when the last check failed and why, in the words the server gave', async () => { + await openUpdates({ ...upToDate, failed_at: '2026-10-22T10:00:00Z', error: 'the update site did not answer' }) + + expect(await paragraph('The check on 22/10/2026 at 10:00 failed: the update site did not answer')).toBeInTheDocument() +}) + +test('says the site receives no automatic updates, in the words WordPress uses while they are off', async () => { + await openUpdates(upToDate) + + expect( + await paragraph('This site will not receive automatic updates for new versions of Gophenberg.'), + ).toBeInTheDocument() +}) + +test('says the site runs the latest version and offers no reinstall', async () => { + await openUpdates(upToDate) + + expect( + await screen.findByRole('heading', { level: 3, name: 'You have the latest version of Gophenberg.' }), + ).toBeInTheDocument() + expect(screen.queryByRole('button', { name: /version/i })).toBeNull() +}) + +test.each([ + ['no check ran yet', { ...upToDate, checked_at: null }], + ['the only check failed', { ...upToDate, checked_at: null, failed_at: '2026-10-22T10:00:00Z', error: 'timeout' }], +])('claims no latest version while %s', async (_condition, overview) => { + await openUpdates(overview) + + await paragraph('Gophenberg has not checked for updates yet. Check now.') + + expect(screen.queryByRole('heading', { level: 3 })).toBeNull() +}) + +test('offers the patch release with its release notes and the button that updates', async () => { + await openUpdates(patchWaiting) + + expect( + await screen.findByRole('heading', { level: 3, name: 'An updated version of Gophenberg is available.' }), + ).toBeInTheDocument() + const offer = await paragraph('You can update from Gophenberg 0.20.0 to Gophenberg 0.20.1 manually:') + expect(within(offer).getByRole('link', { name: 'Gophenberg 0.20.1' })).toHaveAttribute( + 'href', + 'https://example.com/releases/0.20.1', + ) + expect(offer.nextElementSibling).toBe(screen.getByRole('button', { name: 'Update to version 0.20.1' })) + expect( + await paragraph('While your site is being updated, it keeps serving until Gophenberg restarts on the new version.'), + ).toBeInTheDocument() +}) + +test('keeps the release notes link on one line, so the version never parts from its name', async () => { + await openUpdates(patchWaiting) + + const offer = await paragraph('You can update from Gophenberg 0.20.0 to Gophenberg 0.20.1 manually:') + + expect(within(offer).getByRole('link', { name: 'Gophenberg 0.20.1' })).toHaveClass('gophenberg-updates__version') + expect(declarations('.gophenberg-updates__version')).toEqual({ 'white-space': 'nowrap' }) +}) + +test('warns to back up before updating, linking the backup advice and the page on updating', async () => { + await openUpdates(patchWaiting) + + const warning = (await screen.findByText('Important:')).parentElement as HTMLElement + + expect(warning).toHaveTextContent( + 'Important: Before updating, please back up your database and files. ' + + 'For help with updates, visit the Updating Gophenberg documentation page.', + ) + expect(within(warning).getByRole('link', { name: 'back up your database and files' })).toHaveAttribute( + 'href', + `${UPDATING_PAGE}#what-to-back-up`, + ) + expect(within(warning).getByRole('link', { name: 'Updating Gophenberg' })).toHaveAttribute('href', UPDATING_PAGE) +}) + +test('refuses an update the PostgreSQL server is too old for and offers no button', async () => { + await openUpdates({ + ...patchWaiting, + offer: { ...patchOffer, version: '0.21.0', postgresql: 18, needs_postgresql: true }, + }) + + const refused = await paragraph( + 'You cannot update because Gophenberg 0.21.0 requires PostgreSQL version 18 or higher.', + ) + + expect(within(refused).getByRole('link', { name: 'Gophenberg 0.21.0' })).toBeInTheDocument() + expect(screen.queryByRole('button', { name: /Update to version/ })).toBeNull() + expect(screen.queryByText(/keeps serving until/)).toBeNull() +}) + +test('says an update past the minimum version needs the backup above the sentence leading to the button', async () => { + await openUpdates({ ...patchWaiting, offer: { ...patchOffer, long_jump: true } }) + + const warning = await paragraph( + 'This update needs a backup of the database, and the site stays down if the new version does not start.', + ) + const offer = await paragraph('You can update from Gophenberg 0.20.0 to Gophenberg 0.20.1 manually:') + + expect(warning.compareDocumentPosition(offer) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy() + expect(offer.nextElementSibling).toBe(screen.getByRole('button', { name: 'Update to version 0.20.1' })) +}) + +test('offers a version that failed its start check again as a reinstall under the sentence saying so', async () => { + await openUpdates({ ...patchWaiting, refused: ['0.20.1'] }) + + const failed = await paragraph( + 'Gophenberg 0.20.1 failed its start check on this site. Fix what failed before you try it again.', + ) + const reinstall = screen.getByRole('button', { name: 'Re-install version 0.20.1' }) + + expect(failed.nextElementSibling).toBe(reinstall) + expect(reinstall.className).toBe(classesOf()) + expect(screen.queryByRole('button', { name: 'Update to version 0.20.1' })).toBeNull() + expect(screen.queryByText(/manually:/)).toBeNull() +}) + +test('claims no update is available while the only version on offer is one this site refuses', async () => { + await openUpdates({ ...patchWaiting, refused: ['0.20.1'] }) + + await paragraph('Gophenberg 0.20.1 failed its start check on this site. Fix what failed before you try it again.') + + expect(screen.queryByRole('heading', { level: 3 })).toBeNull() +}) + +test.each([ + ['no install root', 'no_install_root', 'This install of Gophenberg has no install root, so it updates by hand.'], + ['a custom build', 'custom_build', 'This is a custom build of Gophenberg, so it updates by hand.'], + ['a reason a newer server names', 'a_reason_from_the_future', 'This install of Gophenberg updates by hand.'], +])('shows the steps by hand in place of the button for an install with %s', async (_condition, reason, words) => { + await openUpdates({ ...patchWaiting, can_update: false, cannot_update: reason }) + + expect(await paragraph(words)).toBeInTheDocument() + const steps = await paragraph( + 'Follow the steps on the Updating Gophenberg documentation page to update by hand.', + ) + expect(within(steps).getByRole('link', { name: 'Updating Gophenberg' })).toHaveAttribute('href', UPDATING_PAGE) + expect(screen.queryByRole('button', { name: /Update to version/ })).toBeNull() + expect(screen.queryByText(/manually:/)).toBeNull() +}) + +test('counts the backups kept, naming when the newest was taken', async () => { + await openUpdates(upToDate) + + expect(await paragraph('Backups kept: 2 of 3, the newest on 21/10/2026 at 14:02.')).toBeInTheDocument() +}) + +test('names when the one backup kept was taken', async () => { + await openUpdates({ ...upToDate, backups: { kept: 1, limit: 3, newest: '2026-10-21T14:02:00Z' } }) + + expect(await paragraph('Backups kept: 1 of 3, taken on 21/10/2026 at 14:02.')).toBeInTheDocument() +}) + +test('says nothing of backups while the install keeps none', async () => { + await openUpdates({ ...upToDate, backups: { kept: 0, limit: 3, newest: null } }) + + await screen.findByRole('heading', { level: 3, name: 'You have the latest version of Gophenberg.' }) + + expect(screen.queryByText(/Backups kept/)).toBeNull() +}) + +test('shows the last update that failed before anything changed, with the reason the server gave', async () => { + await openUpdates(patchFailed) + + expect(await screen.findByText('The update failed before anything changed.')).toBeInTheDocument() + expect(screen.getByText('the checksum of the archive does not match the index')).toBeInTheDocument() +}) + +test('says the updates could not be read when the server answers none', async () => { + server.use(http.get('/api/updates', () => HttpResponse.json({ error: 'boom' }, { status: 500 }))) + renderAt('/update-core') + + expect(await screen.findByRole('alert')).toHaveTextContent( + 'The updates could not be read, so nothing can be updated here yet.', + ) +}) + +test('says the updates could not be read and offers no button when the site settings cannot be read', async () => { + server.use(http.get('/api/settings', () => HttpResponse.json({ error: 'boom' }, { status: 500 }))) + serveUpdates(patchWaiting) + renderAt('/update-core') + + expect( + await screen.findByText('The updates could not be read, so nothing can be updated here yet.'), + ).toBeInTheDocument() + expect(screen.queryByRole('button', { name: 'Update to version 0.20.1' })).toBeNull() +}) + +test('shows a Spanish reader the Updates screen in the words of WordPress es_ES', async () => { + setLocaleData(await catalogFor('es-ES'), 'gophenberg') + onTestFinished(() => resetLocaleData({}, 'gophenberg')) + serveUpdates(patchWaiting) + renderAt('/update-core') + + expect(await screen.findByRole('heading', { level: 2, name: 'Actualizaciones de Gophenberg' })).toBeInTheDocument() + expect(await screen.findByText('Versión actual: 0.20.0')).toBeInTheDocument() + expect(await paragraph('Última comprobación el 22/10/2026 a las 09:12. Comprobar de nuevo.')).toBeInTheDocument() + expect( + await paragraph('Este sitio no recibirá actualizaciones automáticas de nuevas versiones de Gophenberg.'), + ).toBeInTheDocument() + expect( + screen.getByRole('heading', { level: 3, name: 'Hay disponible una versión actualizada de Gophenberg.' }), + ).toBeInTheDocument() + expect( + await paragraph('Puedes actualizar desde Gophenberg 0.20.0 a Gophenberg 0.20.1 manualmente:'), + ).toBeInTheDocument() + expect(screen.getByRole('button', { name: 'Actualizar a la versión 0.20.1' })).toBeInTheDocument() +}) + +test('offers a Spanish reader the retry of a refused version in the words of WordPress es_ES', async () => { + setLocaleData(await catalogFor('es-ES'), 'gophenberg') + onTestFinished(() => resetLocaleData({}, 'gophenberg')) + serveUpdates({ ...patchWaiting, refused: ['0.20.1'] }) + renderAt('/update-core') + + expect(await screen.findByRole('button', { name: 'Reinstalar la versión 0.20.1' })).toBeInTheDocument() +}) diff --git a/frontend/src/test/updatesOverview.ts b/frontend/src/test/updatesOverview.ts new file mode 100644 index 00000000..38ac5739 --- /dev/null +++ b/frontend/src/test/updatesOverview.ts @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { http, HttpResponse, server } from '@gophenberg/frontend-sdk/testing' +import type { QueryClient } from '@tanstack/react-query' +import { waitFor } from '@testing-library/react' +import { expect } from 'vitest' + +import { updatesQueryKey } from '../updates/api' + +/** + * Serves the overview GET /api/updates answers. + * @param overview - The overview to answer. + */ +export function serveUpdates(overview: object) { + server.use(http.get('/api/updates', () => HttpResponse.json(overview))) +} + +/** + * Waits until the admin holds the overview of the updates, or knows it cannot. + * @param client - The query client the admin renders with. + * @param status - How the request for the overview settles. + */ +export async function updatesAnswered(client: QueryClient, status: 'success' | 'error' = 'success') { + await waitFor(() => expect(client.getQueryState(updatesQueryKey)?.status).toBe(status)) +} + +/** The overview a site answers while no update is on offer. */ +export const upToDate = { + running: '0.20.0', + can_update: true, + refused: [] as string[], + job: null, + backups: { kept: 2, limit: 3, newest: '2026-10-21T14:02:00Z' }, + next_check: '2026-10-22T21:12:00Z', + checked_at: '2026-10-22T09:12:00Z', + offer: null, + failed_at: null, + error: '', +} + +/** The offer a check found for the next patch release, with its release notes. */ +export const patchOffer = { + version: '0.20.1', + minimum_version: '0.19.0', + postgresql: 0, + kits: [], + notes: 'https://example.com/releases/0.20.1', + auto: false, + long_jump: false, + needs_postgresql: false, +} + +/** The overview a site answers while the patch release waits. */ +export const patchWaiting = { ...upToDate, offer: patchOffer } + +/** + * Returns the job of the update from the version that runs to the patch release, standing at a step. + * @param step - The step the job stands at. + * @returns The job as the overview names it. + */ +function patchJob(step: string) { + return { step, from: '0.20.0', to: '0.20.1', failure: null } +} + +/** + * Returns the overview a site answers while the update to the patch release stands at a step. + * @param step - The step the update stands at. + * @returns The overview, the version before the update still running. + */ +export function patchAt(step: string) { + return { ...patchWaiting, job: patchJob(step) } +} + +/** + * Returns the overview the patch release answers once it runs, its update standing at a step. + * @param step - The step the update stands at. + * @returns The overview, which no longer offers the version that runs. + */ +export function patchRunning(step: string) { + return { ...upToDate, running: '0.20.1', job: patchJob(step) } +} + +/** The overview a site answers once the patch release failed its start check and the version before it runs again. */ +export const patchWentBack = { ...patchAt('switched'), refused: ['0.20.1'] } + +/** The overview a site answers once the rollback unit took back the patch release after it failed its start check. */ +export const patchRolledBack = { ...patchAt('rolled-back'), refused: ['0.20.1'] } + +/** The overview a site answers once a retry of the patch release the rollback unit took back failed at its download. */ +export const patchRetryFailed = { + ...patchRolledBack, + job: { + ...patchRolledBack.job, + failure: { + at: '2026-10-22T09:40:00Z', + from: '0.20.0', + to: '0.20.1', + step: 'download', + error: 'the checksum of the archive does not match the index', + }, + }, +} + +/** + * Returns the overview a site answers once a retry took its own backup and went back as the try before it did. + * @param wentBack - The overview the site answered once the try before went back. + * @returns The overview, which differs from it in its backups alone. + */ +export function backedUpAgain(wentBack: T): T { + return { ...wentBack, backups: { kept: 3, limit: 3, newest: '2026-10-22T09:41:00Z' } } +} + +/** The overview a site answers while the patch release, offered as raising the minimum version, waits. */ +export const longJumpWaiting = { ...patchWaiting, offer: { ...patchOffer, long_jump: true } } + +/** The overview the patch release answers once it raised the minimum version and failed its start check. */ +export const patchStaysFailed = { ...patchRunning('failed'), refused: ['0.20.1'] } + +/** + * Returns what a check answers when it finds what the overview offers. + * @param overview - The overview the check leaves behind. + * @param overview.offer - The update the check found, or none. + * @returns The result of the check. + */ +export function checkFinding(overview: { offer: object | null }) { + return { checked_at: '2026-10-22T09:30:00Z', offer: overview.offer, failed_at: null, error: '' } +} + +/** The settings that make the Updates screen ask for progress often and wait for a restart only briefly. */ +export const briefUpdateTimings = { + updates_progress_milliseconds: 10, + updates_restart_wait_milliseconds: 800, +} + +/** The overview a site answers after an update to the patch release failed at its download. */ +export const patchFailed = { + ...patchWaiting, + job: { + step: 'committed', + from: '0.19.0', + to: '0.20.0', + failure: { + at: '2026-10-22T09:20:00Z', + from: '0.20.0', + to: '0.20.1', + step: 'download', + error: 'the checksum of the archive does not match the index', + }, + }, +} diff --git a/frontend/src/updates/CheckLines.tsx b/frontend/src/updates/CheckLines.tsx new file mode 100644 index 00000000..6a1889f6 --- /dev/null +++ b/frontend/src/updates/CheckLines.tsx @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { Link, Stack, Text, useToaster } from '@gophenberg/frontend-sdk' +import { ErrorNotice } from '@gopherium/godmin' +import { useMutation, useQueryClient } from '@tanstack/react-query' +import { __, sprintf } from '@wordpress/i18n' + +import { checkForUpdates, updatesQueryKey } from './api' +import type { CheckResult, UpdatesOverview } from './api' +import { dateAndTime, timeUntil } from './words' + +/** + * Returns the sentence saying when the site last checked, and the words of the control that checks again. + * @param checkedAt - When the last good check ran, or null before the first. + * @returns The sentence and the words of the control. + */ +function lastCheckedWords(checkedAt: string | null): { sentence: string, action: string } { + if (checkedAt === null) { + return { + sentence: __('Gophenberg has not checked for updates yet.', 'gophenberg'), + action: __('Check now.', 'gophenberg'), + } + } + return { + sentence: sprintf(__('Last checked on %(date)s at %(time)s.', 'gophenberg'), dateAndTime(checkedAt)), + action: __('Check again.', 'gophenberg'), + } +} + +/** + * Returns the sentence saying when the next check runs, or that the site does not check on its own. + * @param nextCheck - When the check job runs next, or null while the checks are off. + * @returns The sentence. + */ +function nextCheckWords(nextCheck: string | null): string { + if (nextCheck === null) { + return __('This site does not check for updates on its own.', 'gophenberg') + } + return sprintf(__('The next check runs in %(time)s.', 'gophenberg'), { time: timeUntil(nextCheck, Date.now()) }) +} + +/** + * Returns the line naming when the last check failed and why, or nothing while it did not. + * @param overview - The overview of the updates. + * @returns The line element, or null. + */ +function FailedCheck({ overview }: { overview: UpdatesOverview }) { + if (overview.failed_at === null) { + return null + } + const sentence = sprintf(__('The check on %(date)s at %(time)s failed: %(error)s', 'gophenberg'), { + ...dateAndTime(overview.failed_at), + error: overview.error, + }) + return }>{sentence} +} + +/** + * Reports whether a check that ran found nothing the overview did not already offer. + * @param result - What the check found. + * @param before - The overview the screen held when the check started. + * @returns True when the check succeeded and found no newer update. + */ +function foundNothingNew(result: CheckResult, before: UpdatesOverview): boolean { + return result.error === '' && result.offer?.version === before.offer?.version +} + +/** + * Returns the check of the update site that the screen runs on request, saying when it found nothing new. + * @param before - The overview the screen holds. + * @returns The mutation running the check. + */ +function useCheck(before: UpdatesOverview) { + const client = useQueryClient() + const toaster = useToaster() + return useMutation({ + mutationFn: checkForUpdates, + onSuccess: async (result) => { + if (foundNothingNew(result, before)) { + toaster.show(__('No new updates found.', 'gophenberg')) + } + await client.invalidateQueries({ queryKey: updatesQueryKey }) + }, + }) +} + +/** + * Renders when the site last checked for updates with the control that checks again, and when it checks next. + * @param props - The overview of the updates. + * @returns The lines element. + */ +export function CheckLines({ overview }: { overview: UpdatesOverview }) { + const check = useCheck(overview) + const last = lastCheckedWords(overview.checked_at) + return ( + + } className="gophenberg-updates__last-check"> + {last.sentence}{' '} + } + onClick={() => check.mutate()} + > + {last.action} + + + }>{nextCheckWords(overview.next_check)} + + {check.isError ? {check.error.message} : null} + + ) +} diff --git a/frontend/src/updates/CoreOffer.tsx b/frontend/src/updates/CoreOffer.tsx new file mode 100644 index 00000000..531cb5e8 --- /dev/null +++ b/frontend/src/updates/CoreOffer.tsx @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { AlertDialog, Button, Link, Notice, Stack, Text } from '@gophenberg/frontend-sdk' +import { SectionTitle } from '@gopherium/godmin' +import { formatNumber } from '@gopherium/gottext' +import { createInterpolateElement } from '@wordpress/element' +import { __, _n, sprintf } from '@wordpress/i18n' + +import { errorText } from '../i18n/errors' +import type { BackupCount, UpdateJob, UpdateOffer, UpdateStart, UpdatesOverview } from './api' +import { backupAdvice, notesLink, updatingPage } from './links' +import { mayMoveOn } from './run' +import type { RunView } from './run' +import { RunEnding, UpdateSteps, useSpoken } from './UpdateSteps' +import { dateAndTime } from './words' + +/** What the offer needs: the overview, the update the screen follows, and the controls of an update. */ +interface OfferProps { + overview: UpdatesOverview + view: RunView | undefined + onStart: (asked: UpdateStart) => Promise + onDismiss: () => void +} + +/** + * Renders WordPress's warning to back up before updating, linking the backup advice and the page on updating. + * @returns The notice element. + */ +function BackUpFirst() { + const sentence = __( + 'Important: Before updating, please back up your database and files. ' + + 'For help with updates, visit the Updating Gophenberg documentation page.', + 'gophenberg', + ) + return ( + + + {createInterpolateElement(sentence, { + strong: , + backup: , + docs: , + })} + + + ) +} + +/** + * Renders the sentence saying the PostgreSQL server is too old for the update on offer. + * @param props - The update on offer. + * @returns The line element, the version on offer linked to its release notes. + */ +function BlockedLine({ offer }: { offer: UpdateOffer }) { + const sentence = sprintf( + __( + 'You cannot update because Gophenberg %(version)s requires PostgreSQL version ' + + '%(postgresql)s or higher.', + 'gophenberg', + ), + { version: offer.version, postgresql: formatNumber(offer.postgresql) } as never, + ) + return }>{createInterpolateElement(sentence, { notes: notesLink(offer) })} +} + +/** + * Renders the sentence leading to the button, naming the version that runs and the update on offer. + * @param props - The version that runs and the update on offer. + * @returns The line element, the version on offer linked to its release notes. + */ +function UpdateLine({ running, offer }: { running: string, offer: UpdateOffer }) { + const sentence = sprintf( + __('You can update from Gophenberg %(running)s to Gophenberg %(version)s manually:', 'gophenberg'), + { running, version: offer.version }, + ) + return }>{createInterpolateElement(sentence, { notes: notesLink(offer) })} +} + +/** + * Reports whether the install refuses a version, which then only a retry installs. + * @param overview - The overview of the updates. + * @param version - The version asked about. + * @returns True when the version failed its start check here. + */ +function refuses(overview: UpdatesOverview, version: string): boolean { + return overview.refused.includes(version) +} + +/** + * Returns what the confirm says before an update: the backup comes first, and what happens when the update fails. + * @param offer - The update on offer. + * @param running - The version that runs. + * @returns The description of the confirm. + */ +function confirmWords(offer: UpdateOffer, running: string): string { + if (offer.long_jump) { + return __( + 'A backup of the database is taken first, and the site stays down until you restore it ' + + 'if the new version does not start.', + 'gophenberg', + ) + } + return sprintf( + __( + 'A backup of the database is taken first, and Gophenberg goes back to %(running)s on its own ' + + 'if the new version does not start.', + 'gophenberg', + ), + { running } as never, + ) +} + +/** + * Returns the words of the button: a reinstall for a refused version, as WordPress names it, an update otherwise. + * @param offer - The update on offer. + * @param retry - Whether the button tries a refused version again. + * @returns The words of the button. + */ +function buttonWords(offer: UpdateOffer, retry: boolean): string { + const words = retry + ? __('Re-install version %(version)s', 'gophenberg') + : __('Update to version %(version)s', 'gophenberg') + return sprintf(words, { version: offer.version }) +} + +/** + * Renders the button updating to the version on offer and the confirm it asks first, a retry for a refused version. + * @param props - The update on offer, the overview, and what starts an update. + * @returns The button and its confirm. + */ +function UpdateButton({ offer, overview, onStart }: Pick & { offer: UpdateOffer }) { + const retry = refuses(overview, offer.version) + const confirm = async () => { + try { + await onStart({ version: offer.version, retry }) + } catch (cause) { + return { close: false, error: (cause as Error).message } + } + } + return ( + + }> + {buttonWords(offer, retry)} + + + + ) +} + +/** + * Renders why this install updates by hand and where the steps are, in place of the button. + * @param props - The reason the server names, if any. + * @returns The lines element. + */ +function ByHand({ reason }: { reason: string | undefined }) { + const why = errorText({ error: __('This install of Gophenberg updates by hand.', 'gophenberg'), code: reason }) + const steps = __( + 'Follow the steps on the Updating Gophenberg documentation page to update by hand.', + 'gophenberg', + ) + return ( + <> + }>{why} + }>{createInterpolateElement(steps, { docs: })} + + ) +} + +/** + * Renders the steps of the update the screen follows while it runs, or nothing. + * @param props - What the screen sees of the update, if anything. + * @returns The steps element, or null. + */ +function RunSteps({ view }: { view: RunView | undefined }) { + if (view === undefined || view.phase.kind !== 'steps') { + return null + } + return +} + +/** + * Renders the steps by hand, or the button, led by its sentence outside a run unless the version on offer is refused. + * @param props - The offer's props and the update on offer. + * @returns The element, or null while the PostgreSQL server is too old for it. + */ +function OfferAction(props: OfferProps & { offer: UpdateOffer }) { + const { view, overview, offer } = props + if (offer.needs_postgresql) { + return null + } + if (!overview.can_update) { + return + } + const leads = view === undefined && !refuses(overview, offer.version) + return ( + <> + {leads ? : null} + + }> + {__( + 'While your site is being updated, it keeps serving until Gophenberg restarts on the new version.', + 'gophenberg', + )} + + + ) +} + +/** + * Renders the update on offer: the warning outside a run, why it cannot install, a long jump, a failed try, its action. + * @param props - The offer's props and the update on offer. + * @returns The offer elements, or null while an update may move on. + */ +function OfferDetails(props: OfferProps & { offer: UpdateOffer }) { + const { overview, offer, view } = props + if (mayMoveOn(view)) { + return null + } + const refused = sprintf( + __( + 'Gophenberg %(version)s failed its start check on this site. Fix what failed before you try it again.', + 'gophenberg', + ), + { version: offer.version }, + ) + const longJump = __( + 'This update needs a backup of the database, and the site stays down if the new version does not start.', + 'gophenberg', + ) + return ( + <> + {view === undefined ? : null} + {offer.needs_postgresql ? : null} + {offer.long_jump ? }>{longJump} : null} + {refuses(overview, offer.version) ? }>{refused} : null} + + + ) +} + +/** + * Renders the last update that failed before anything changed, with the reason the server gave, or nothing. + * @param props - The last update the install names, and whether it is the ending of the update followed. + * @returns The notice element, or null. + */ +function FailedBefore({ job, live }: { job: UpdateJob | null, live: boolean }) { + const title = __('The update failed before anything changed.', 'gophenberg') + useSpoken(live ? title : undefined, 'assertive') + const failure = job?.failure + if (!failure) { + return null + } + return ( + + {title} + {failure.error} + + ) +} + +/** + * Renders how many backups the install keeps and when the newest was taken, or nothing while it keeps none. + * @param props - The backups the server counts. + * @returns The line element, or null. + */ +export function BackupsLine({ backups }: { backups: BackupCount }) { + if (backups.newest === null) { + return null + } + const sentence = sprintf( + _n( + 'Backups kept: %(kept)s of %(limit)s, taken on %(date)s at %(time)s.', + 'Backups kept: %(kept)s of %(limit)s, the newest on %(date)s at %(time)s.', + backups.kept, + 'gophenberg', + ), + { kept: formatNumber(backups.kept), limit: formatNumber(backups.limit), ...dateAndTime(backups.newest) }, + ) + return }>{sentence} +} + +/** + * Returns the heading of the core update: one on offer this site takes, the latest version once a check ran, or none. + * @param overview - The overview of the updates. + * @param moving - Whether the update the screen follows may still move on. + * @returns The heading, or undefined before a check, while an update may move on, or while a version is refused. + */ +function offerHeading(overview: UpdatesOverview, moving: boolean): string | undefined { + if (moving) { + return undefined + } + if (overview.offer !== null) { + return refuses(overview, overview.offer.version) + ? undefined + : __('An updated version of Gophenberg is available.', 'gophenberg') + } + const latest = overview.checked_at !== null && !refuses(overview, overview.running) + return latest ? __('You have the latest version of Gophenberg.', 'gophenberg') : undefined +} + +/** + * Renders the core update: whether one is available, the ending of the update followed, the offer, and the steps. + * @param props - The overview, the update the screen follows, and the controls of an update. + * @returns The section element. + */ +export function CoreOffer(props: OfferProps) { + const { overview, view } = props + const offer = overview.offer + const phase = view?.phase.kind + const heading = offerHeading(overview, mayMoveOn(view)) + return ( + + {heading === undefined ? null : {heading}} + {view === undefined ? null : } + {phase === 'steps' ? null : } + {offer === null ? null : } + + + ) +} diff --git a/frontend/src/updates/UpdateNag.tsx b/frontend/src/updates/UpdateNag.tsx new file mode 100644 index 00000000..b9006e17 --- /dev/null +++ b/frontend/src/updates/UpdateNag.tsx @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { Link, Notice } from '@gophenberg/frontend-sdk' +import { Link as RouterLink, useMatchRoute } from '@tanstack/react-router' +import { createInterpolateElement } from '@wordpress/element' +import { __, sprintf } from '@wordpress/i18n' +import type { ReactNode } from 'react' + +import { useUpdates, waitingOffer } from './api' +import type { UpdateOffer, UpdatesOverview } from './api' +import { notesLink } from './links' + +/** + * Renders the link to the Updates screen that a nag wraps around its last words, named by those words. + * @param props - The words linked. + * @returns The link element. + */ +function UpdatesLink({ children }: { children?: ReactNode }) { + return }>{children} +} + +/** + * Renders the nag saying the version on offer is available, its release notes and the Updates screen linked. + * @param props - The update on offer. + * @returns The notice element. + */ +function AvailableNag({ offer }: { offer: UpdateOffer }) { + const notes = notesLink(offer) + const sentence = sprintf( + __('Gophenberg %(version)s is available! Please update now.', 'gophenberg'), + { version: offer.version }, + ) + return ( + + + {createInterpolateElement(sentence, { notes, update: })} + + + ) +} + +/** + * Renders the nag saying the update to a version failed, with the Updates screen linked to try again. + * @param props - The version the failed update went to. + * @returns The notice element. + */ +function FailedNag({ version }: { version: string }) { + const sentence = sprintf( + __( + 'The update to Gophenberg %(version)s failed to complete. Please attempt the update again now.', + 'gophenberg', + ), + { version }, + ) + return ( + + {createInterpolateElement(sentence, { retry: })} + + ) +} + +/** + * Returns the update the nag offers: the one that waits, unless the last failure already names its version. + * @param overview - The overview of the updates. + * @returns The offer, or undefined when none waits or the failure nag already names it. + */ +function nagOffer(overview: UpdatesOverview): UpdateOffer | undefined { + const offer = waitingOffer(overview) + return offer?.version === overview.job?.failure?.to ? undefined : offer +} + +/** + * Renders the nags an update_core holder sees above every admin screen but Updates, in the order WordPress draws them. + * @returns The nag of the update that waits unless the failure names it, then the failure nag, or null. + */ +export function UpdateNag() { + const overview = useUpdates() + const onUpdates = useMatchRoute()({ to: '/update-core' }) !== false + if (onUpdates || overview === undefined) { + return null + } + const offer = nagOffer(overview) + const failure = overview.job?.failure + return ( + <> + {offer === undefined ? null : } + {failure ? : null} + + ) +} diff --git a/frontend/src/updates/UpdateSteps.tsx b/frontend/src/updates/UpdateSteps.tsx new file mode 100644 index 00000000..79ed91ce --- /dev/null +++ b/frontend/src/updates/UpdateSteps.tsx @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { Link, Notice, Spinner, Text, speak } from '@gophenberg/frontend-sdk' +import { createInterpolateElement } from '@wordpress/element' +import { __, sprintf } from '@wordpress/i18n' +import { useEffect, useRef } from 'react' + +import { adminBasepath } from '../basepath' +import { restoreSteps } from './links' +import { STEP_LINES } from './run' +import type { RunView, StepLine, UpdateRun } from './run' + +/** The address of the Updates screen, which a full load opens on the admin the new version serves. */ +const reloadAddress = `${adminBasepath}/update-core` + +/** + * Speaks the words of an ending once they show, since a notice does not announce itself. + * @param words - The words to speak, or undefined to speak nothing. + * @param urgency - How urgently a screen reader speaks them. + */ +export function useSpoken(words: string | undefined, urgency: 'polite' | 'assertive') { + useEffect(() => { + if (words !== undefined) { + speak(words, urgency) + } + }, [words, urgency]) +} + +/** + * Returns the words of each line of the steps, read fresh so the catalogue the reader loaded answers. + * @param run - The update the steps follow. + * @returns The words, keyed by line. + */ +function stepWords(run: UpdateRun): Record { + return { + download: sprintf(__('Downloading Gophenberg %(version)s…', 'gophenberg'), { version: run.to }), + unpack: __('Unpacking the update…', 'gophenberg'), + verify: __('Verifying the unpacked files…', 'gophenberg'), + backup: __('Backing up the database…', 'gophenberg'), + restart: __('Restarting Gophenberg…', 'gophenberg'), + check: __('Checking the new version…', 'gophenberg'), + } +} + +/** + * Renders the steps an update reached, one line each, the one under way marked, taking the focus nothing else holds. + * @param props - The update and the line it stands at. + * @returns The list element. + */ +export function UpdateSteps({ run, line }: { run: UpdateRun, line: StepLine }) { + const list = useRef(null) + useEffect(() => { + if (document.activeElement === document.body) { + (list.current as HTMLOListElement).focus() + } + }, []) + const words = stepWords(run) + const reached = STEP_LINES.slice(0, STEP_LINES.indexOf(line) + 1) + return ( +
    + {reached.map((name) => ( +
  1. + {words[name]} + {name === line ? : null} +
  2. + ))} +
+ ) +} + +/** + * Renders the notice saying the update succeeded, with the link that loads the admin the new version serves. + * @returns The notice element. + */ +function UpdatedNotice() { + const words = __('Gophenberg updated successfully.', 'gophenberg') + useSpoken(words, 'polite') + return ( + + {words} + + {__('Reload the admin', 'gophenberg')} + + + ) +} + +/** + * Renders the notice saying the update failed and Gophenberg went back, which stays until dismissed. + * @param props - The update and what dismisses the notice. + * @returns The notice element. + */ +function WentBackNotice({ run, onDismiss }: { run: UpdateRun, onDismiss: () => void }) { + const title = sprintf(__('The update to %(to)s failed.', 'gophenberg'), { to: run.to }) + const description = sprintf(__('Gophenberg went back to %(from)s and is running normally.', 'gophenberg'), { + from: run.from, + }) + useSpoken(`${title} ${description}`, 'assertive') + return ( + + {title} + {description} + + + ) +} + +/** + * Renders the notice saying the new version failed its start check and stays, with how to restore the backup. + * @param props - The update that failed, which speaks its title unless it had ended when the screen found it. + * @returns The notice element. + */ +function FailedNotice({ run }: { run: UpdateRun }) { + const title = sprintf( + __( + 'The update to %(to)s failed its start check, and Gophenberg cannot go back to %(from)s on its own.', + 'gophenberg', + ), + { to: run.to, from: run.from }, + ) + const steps = __( + 'Run update:status on the server to see the backup taken before the update. ' + + 'Then restore that backup, or fix what failed and start Gophenberg again.', + 'gophenberg', + ) + useSpoken(run.ended ? undefined : title, 'assertive') + return ( + + {title} + + {createInterpolateElement(steps, { code: , restore: })} + + + ) +} + +/** + * Renders the notice saying Gophenberg has not come back within the wait, and what to check on the server. + * @returns The notice element. + */ +function NotBackNotice() { + const title = __('Gophenberg has not come back yet.', 'gophenberg') + const advice = __( + 'Gophenberg stopped after the switch so that its service manager, such as systemd, starts the new ' + + 'version. Check that the service manager starts it again after exit code 75, and run ' + + 'update:status on the server to see where the update stands.', + 'gophenberg', + ) + useSpoken(title, 'assertive') + return ( + + {title} + {createInterpolateElement(advice, { code: })} + + ) +} + +/** + * Renders the ending of the update the screen follows, or nothing while it runs or after it failed before its switch. + * @param props - What the screen sees of the update, and what dismisses its ending. + * @returns The notice element, or null. + */ +export function RunEnding({ view, onDismiss }: { view: RunView, onDismiss: () => void }) { + switch (view.phase.kind) { + case 'updated': + return + case 'rolled-back': + return + case 'failed': + return + case 'not-back': + return + default: + return null + } +} diff --git a/frontend/src/updates/UpdatesScreen.tsx b/frontend/src/updates/UpdatesScreen.tsx new file mode 100644 index 00000000..3636aab5 --- /dev/null +++ b/frontend/src/updates/UpdatesScreen.tsx @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { Skeleton, Stack, Text } from '@gophenberg/frontend-sdk' +import { ErrorNotice, Page } from '@gopherium/godmin' +import { __, sprintf } from '@wordpress/i18n' + +import { CheckLines } from './CheckLines' +import { BackupsLine, CoreOffer } from './CoreOffer' +import { useUpdatesScreen } from './useUpdatesScreen' +import type { UpdatesScreenState } from './useUpdatesScreen' + +/** + * Returns what the screen shows under its title: the checks, the policy, the offer and the backups. + * @param state - The screen's state. + * @returns The body element. + */ +function updatesBody(state: UpdatesScreenState) { + const { overview } = state + if (state.unread) { + return ( + + {__('The updates could not be read, so nothing can be updated here yet.', 'gophenberg')} + + ) + } + if (overview === undefined) { + return + } + return ( + + + }> + {__('This site will not receive automatic updates for new versions of Gophenberg.', 'gophenberg')} + + + + + ) +} + +/** + * Renders the Updates screen, where an update_core holder checks for and installs a new version of Gophenberg. + * @returns The page element. + */ +export function UpdatesScreen() { + const state = useUpdatesScreen() + const running = state.overview?.running + return ( + + {updatesBody(state)} + + ) +} diff --git a/frontend/src/updates/api.ts b/frontend/src/updates/api.ts new file mode 100644 index 00000000..49225001 --- /dev/null +++ b/frontend/src/updates/api.ts @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { UPDATE_CORE, can, useSession } from '@gophenberg/frontend-sdk' +import { useQuery } from '@tanstack/react-query' +import { z } from 'zod' + +import { errorText } from '../i18n/errors' + +const failureSchema = z.object({ + at: z.string(), + from: z.string(), + to: z.string(), + step: z.string(), + error: z.string(), +}) + +const jobSchema = z.object({ + step: z.string(), + from: z.string(), + to: z.string(), + failure: failureSchema.nullable(), +}) + +const offerSchema = z.object({ + version: z.string(), + notes: z.string(), + postgresql: z.number(), + long_jump: z.boolean(), + needs_postgresql: z.boolean(), +}) + +const resultSchema = z.object({ + checked_at: z.string().nullable(), + offer: offerSchema.nullable(), + failed_at: z.string().nullable(), + error: z.string(), +}) + +const backupsSchema = z.object({ + kept: z.number(), + limit: z.number(), + newest: z.string().nullable(), +}) + +const overviewSchema = resultSchema.extend({ + running: z.string(), + can_update: z.boolean(), + cannot_update: z.string().optional(), + refused: z.array(z.string()), + job: jobSchema.nullable(), + backups: backupsSchema, + next_check: z.string().nullable(), +}) + +const errorSchema = z.object({ + error: z.string(), + code: z.string().optional(), + meta: z.record(z.string(), z.unknown()).optional(), +}) + +/** What GET /api/updates answers: what the checks found, the version that runs, its install and its last update. */ +export type UpdatesOverview = z.infer + +/** The update a check found for this site. */ +export type UpdateOffer = z.infer + +/** The last update the install names, with the failure of the last one that stopped before its switch. */ +export type UpdateJob = z.infer + +/** What POST /api/updates/check answers: the last good check and the failure of any check since it. */ +export type CheckResult = z.infer + +/** How many backups the install keeps, how many it may keep, and when the newest was taken. */ +export type BackupCount = z.infer + +/** What an administrator asks of the start of an update: the version to update to, and whether to retry it. */ +export interface UpdateStart { + version: string + retry: boolean +} + +/** The key the overview of the updates is cached under, which the menu, the nag and the Updates screen share. */ +export const updatesQueryKey = ['updates'] + +/** + * Returns the overview of the updates, raising when it cannot be read. + * @returns The overview the server answers. + */ +export async function fetchUpdates(): Promise { + const response = await fetch('/api/updates') + if (!response.ok) { + throw new Error(`loading the updates failed with status ${response.status}`) + } + return overviewSchema.parse(await response.json()) +} + +/** + * Checks the update site now, raising with the reason the server gave when it refuses. + * @returns What the check found. + */ +export async function checkForUpdates(): Promise { + const response = await fetch('/api/updates/check', { method: 'POST' }) + if (!response.ok) { + throw await errorFrom(response) + } + return resultSchema.parse(await response.json()) +} + +/** + * Starts the update an administrator asked for, raising with the reason the server gave when it refuses. + * @param asked - The version to update to and whether to retry it. + * @returns The overview the server answers once the update started. + */ +export async function startUpdate(asked: UpdateStart): Promise { + const response = await fetch('/api/updates/apply', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(asked), + }) + if (!response.ok) { + throw await errorFrom(response) + } + return overviewSchema.parse(await response.json()) +} + +/** + * Returns the error a refused request carries, in the reader's language. + * @param response - The answer the server gave. + * @returns The error to raise. + */ +async function errorFrom(response: Response): Promise { + const parsed = errorSchema.safeParse(await response.json().catch(() => null)) + return new Error(parsed.success ? errorText(parsed.data) : errorText({ error: '' })) +} + +/** + * Returns the overview of the updates to a session carrying update_core, asking and showing nothing to any other. + * @returns The overview, or undefined before it arrives and for a session without update_core. + */ +export function useUpdates(): UpdatesOverview | undefined { + const holds = can(useSession().data, UPDATE_CORE) + const { data } = useQuery({ queryKey: updatesQueryKey, queryFn: fetchUpdates, enabled: holds }) + return holds ? data : undefined +} + +/** + * Returns the update that waits: the one on offer, unless this site refused its version. + * @param overview - The overview of the updates, or nothing before it arrives. + * @returns The offer, or undefined when none waits. + */ +export function waitingOffer(overview: UpdatesOverview | undefined): UpdateOffer | undefined { + if (!overview?.offer || overview.refused.includes(overview.offer.version)) { + return undefined + } + return overview.offer +} diff --git a/frontend/src/updates/links.tsx b/frontend/src/updates/links.tsx new file mode 100644 index 00000000..c322b7d8 --- /dev/null +++ b/frontend/src/updates/links.tsx @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { Link } from '@gophenberg/frontend-sdk' +import type { ReactElement } from 'react' + +import type { UpdateOffer } from './api' + +/** What a release notes address starts with when it names a web page. */ +const webPage = /^https?:\/\//i + +/** The documentation page that shows how to update Gophenberg. */ +export const updatingPage = 'https://docs.gophenberg.org/self-hosting/updates-and-backups/' + +/** The part of that page naming what to back up. */ +export const backupAdvice = `${updatingPage}#what-to-back-up` + +/** The part of that page showing how a server install restores a backup of the database. */ +export const restoreSteps = `${updatingPage}#restoring-on-a-server-install` + +/** The class that keeps the name and the number of a version on one line. */ +const versionClass = 'gophenberg-updates__version' + +/** + * Returns the element a sentence wraps around the version on offer: its release notes linked, or the words alone. + * @param offer - The update on offer. + * @returns A link to the release notes when they are a web page, otherwise a span, both kept on one line. + */ +export function notesLink(offer: UpdateOffer): ReactElement { + if (webPage.test(offer.notes)) { + return + } + return +} diff --git a/frontend/src/updates/nav.tsx b/frontend/src/updates/nav.tsx new file mode 100644 index 00000000..9e0c9a08 --- /dev/null +++ b/frontend/src/updates/nav.tsx @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { UPDATE_CORE, updateIcon } from '@gophenberg/frontend-sdk' +import type { MenuItem } from '@gophenberg/frontend-sdk' +import { formatNumber } from '@gopherium/gottext' +import { __, _n, sprintf } from '@wordpress/i18n' + +import { useUpdates, waitingOffer } from './api' + +/** + * Returns the Updates row of the sidebar, counting the update that waits as WordPress counts it. + * @returns The menu item, its count one while an update waits and zero otherwise. + */ +export function useUpdatesMenuItem(): MenuItem { + const waiting = waitingOffer(useUpdates()) === undefined ? 0 : 1 + return { + label: __('Updates', 'gophenberg'), + to: '/update-core', + icon: updateIcon, + capability: UPDATE_CORE, + count: { + value: waiting, + label: sprintf(_n('%s update available', '%s updates available', waiting, 'gophenberg'), formatNumber(waiting)), + }, + } +} diff --git a/frontend/src/updates/run.ts b/frontend/src/updates/run.ts new file mode 100644 index 00000000..75fe4441 --- /dev/null +++ b/frontend/src/updates/run.ts @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: Apache-2.0 + +import type { UpdateJob, UpdateStart, UpdatesOverview } from './api' + +/** An update the screen follows: its versions, its retry, the failure and backup at its start, and how it stands. */ +export interface UpdateRun { + to: string + from: string + retry: boolean + priorFailure: string | undefined + priorBackup: string | null + moved: boolean + ended: boolean +} + +/** A line of the steps an update shows, in the order it reaches them. */ +export type StepLine = 'download' | 'unpack' | 'verify' | 'backup' | 'restart' | 'check' + +/** How an update ended: kept, gone back, failed on the new version, or failed before its switch. */ +type Ending = 'updated' | 'rolled-back' | 'failed' | 'over' + +/** Where an update stands: at a line of its steps, at one of its endings, or past the wait for its restart. */ +type RunPhase = { kind: 'steps', line: StepLine } | { kind: Ending | 'not-back' } + +/** What the screen sees of an update: the update, where it stands, and whether it restarts. */ +export interface RunView { + run: UpdateRun + phase: RunPhase + restarting: boolean +} + +/** The overview last read, and whether the last read of it failed. */ +interface Seen { + overview: UpdatesOverview + failing: boolean +} + +/** The lines an update reaches, in order. */ +export const STEP_LINES: StepLine[] = ['download', 'unpack', 'verify', 'backup', 'restart', 'check'] + +/** The line each step of the job shows, the download standing for any step not named. */ +const LINE_OF_STEP: Record = { stage: 'unpack', backup: 'backup', switched: 'restart' } + +/** The steps of a job that still runs on the version it started from. */ +const UNDER_WAY = ['download', 'stage', 'backup'] + +/** The steps of a job past its switch that a version going back leaves. */ +const PAST_SWITCH = ['switched', 'rolled-back'] + +/** The lines an update shows while Gophenberg restarts and checks the new version. */ +const RESTARTING: StepLine[] = ['restart', 'check'] + +/** The ending each step of the job of an update names once the version it went to runs. */ +const ENDING_ON_NEW: Partial> = { committed: 'updated', failed: 'failed' } + +/** The phases an update may still move on from: its steps, and the wait for its restart that passed. */ +const OPEN_PHASES: RunPhase['kind'][] = ['steps', 'not-back'] + +/** + * Returns the update an administrator just started. + * @param asked - The version it updates to and whether it retries it. + * @param before - The overview the screen held when the update started. + * @param answered - The overview the start answered with. + * @returns The update, which has not moved yet. + */ +export function startedRun(asked: UpdateStart, before: UpdatesOverview, answered: UpdatesOverview): UpdateRun { + return { + to: asked.version, + from: before.running, + retry: asked.retry, + priorFailure: before.job?.failure?.at, + priorBackup: answered.backups.newest, + moved: false, + ended: false, + } +} + +/** + * Returns the update the overview names as under way or as failed on the version that runs, which the screen follows. + * @param overview - The overview of the updates. + * @returns The update, or undefined when none is under way and none stays failed. + */ +function foundRun(overview: UpdatesOverview): UpdateRun | undefined { + const job = overview.job + if (job === null || !pickedUp(job, overview)) { + return undefined + } + return { + to: job.to, + from: job.from, + retry: false, + priorFailure: undefined, + priorBackup: overview.backups.newest, + moved: true, + ended: job.step === 'failed', + } +} + +/** + * Reports whether the screen follows a job: under way on the version it left, or checking or failed on its new one. + * @param job - The job the overview names. + * @param overview - The overview of the updates. + * @returns True when the screen follows the job. + */ +function pickedUp(job: UpdateJob, overview: UpdatesOverview): boolean { + if (job.to === overview.running) { + return job.step === 'failed' || openStep(job, overview.refused) + } + return job.from === overview.running && openStep(job, overview.refused) +} + +/** + * Reports whether the screen follows an update that may still move on: under way, or not back within the wait. + * @param view - What the screen sees of the update, if anything. + * @returns True while the update runs or has not come back yet. + */ +export function mayMoveOn(view: RunView | undefined): boolean { + return view !== undefined && OPEN_PHASES.includes(view.phase.kind) +} + +/** + * Reports whether a job stands at a step before its switch, or at a switch the version it went to has not refused. + * @param job - The job the overview names. + * @param refused - The versions the install refuses. + * @returns True while the job is under way. + */ +function openStep(job: UpdateJob, refused: string[]): boolean { + if (UNDER_WAY.includes(job.step)) { + return true + } + return job.step === 'switched' && !refused.includes(job.to) +} + +/** + * Returns what the screen sees of the update it follows, or of one under way when it follows none. + * @param run - The update the screen started, if any. + * @param overview - The overview last read, if any arrived. + * @param failing - Whether the last read of the overview failed. + * @param waited - Whether the wait for a restart passed. + * @returns The view, or undefined while there is no update to follow. + */ +export function runView( + run: UpdateRun | undefined, + overview: UpdatesOverview | undefined, + failing: boolean, + waited: boolean, +): RunView | undefined { + if (overview === undefined) { + return undefined + } + const followed = run ?? foundRun(overview) + if (followed === undefined) { + return undefined + } + const seen = { overview, failing } + const current = withMove(followed, seen) + const line = stepLine(current, seen) + const restarting = RESTARTING.includes(line) + return { run: followed, phase: phaseOf(current, seen, line, waited && restarting), restarting } +} + +/** + * Returns the update the screen holds after a read: the one it follows, or one under way it picks up, marked as moved. + * @param run - The update the screen follows, if any. + * @param overview - The overview the read left, if any. + * @param failing - Whether the read failed. + * @returns The update, marked as moved once a read showed it moving, or undefined while there is none to follow. + */ +export function heldRun( + run: UpdateRun | undefined, + overview: UpdatesOverview | undefined, + failing: boolean, +): UpdateRun | undefined { + if (overview === undefined) { + return run + } + const followed = run ?? foundRun(overview) + return followed === undefined ? undefined : withMove(followed, { overview, failing }) +} + +/** + * Returns the update marked as moved when the overview shows it moving, the same update otherwise. + * @param run - The update followed. + * @param seen - The overview last read and whether the read failed. + * @returns The update. + */ +function withMove(run: UpdateRun, seen: Seen): UpdateRun { + return run.moved || !movedOn(run, seen) ? run : { ...run, moved: true } +} + +/** + * Reports whether the overview shows the update moving: the server gone, another version running, or its own step. + * @param run - The update followed. + * @param seen - The overview last read and whether the read failed. + * @returns True once the update moved past the overview it started from. + */ +function movedOn(run: UpdateRun, seen: Seen): boolean { + return seen.failing || advanced(run, seen.overview) +} + +/** + * Reports whether another version runs, the job of the update is under way, or a backup was taken since it started. + * @param run - The update followed. + * @param overview - The overview last read. + * @returns True when the overview shows the update under way or past its backup. + */ +function advanced(run: UpdateRun, overview: UpdatesOverview): boolean { + return overview.running !== run.from || progressed(run, overview) +} + +/** + * Reports whether the job of the update is under way, or the install holds a newer backup than at its start. + * @param run - The update followed. + * @param overview - The overview last read. + * @returns True when the job runs or backed up the database. + */ +function progressed(run: UpdateRun, overview: UpdatesOverview): boolean { + return ownJobOpen(run, overview) || overview.backups.newest !== run.priorBackup +} + +/** + * Reports whether the job of the update stands before its switch, or at a switch the install does not refuse. + * @param run - The update followed. + * @param overview - The overview last read. + * @returns True while the job of the update is under way. + */ +function ownJobOpen(run: UpdateRun, overview: UpdatesOverview): boolean { + const job = ownJob(run, overview) + return job !== undefined && openStep(job, overview.refused) +} + +/** + * Returns the job of the update, when the overview names it. + * @param run - The update followed. + * @param overview - The overview last read. + * @returns The job, or undefined when the overview names another one or none. + */ +function ownJob(run: UpdateRun, overview: UpdatesOverview): UpdateJob | undefined { + const job = overview.job + return job?.to === run.to && job.from === run.from ? job : undefined +} + +/** + * Returns the step the job of the update stands at, empty when the overview names another job. + * @param run - The update followed. + * @param overview - The overview last read. + * @returns The step, or an empty string. + */ +function ownStep(run: UpdateRun, overview: UpdatesOverview): string { + return ownJob(run, overview)?.step ?? '' +} + +/** + * Returns the line the update stands at: the download until it moved, then its step, the restart, and the check. + * @param run - The update followed. + * @param seen - The overview last read and whether the read failed. + * @returns The line under way. + */ +function stepLine(run: UpdateRun, seen: Seen): StepLine { + if (seen.failing) { + return 'restart' + } + if (seen.overview.running === run.to) { + return 'check' + } + return run.moved ? (LINE_OF_STEP[ownStep(run, seen.overview)] ?? 'download') : 'download' +} + +/** + * Returns where the update stands: an ending the overview shows, the end of the wait, or the line under way. + * @param run - The update followed. + * @param seen - The overview last read and whether the read failed. + * @param line - The line the update stands at. + * @param waited - Whether the wait for its restart passed. + * @returns The phase. + */ +function phaseOf(run: UpdateRun, seen: Seen, line: StepLine, waited: boolean): RunPhase { + const ending = seen.failing ? undefined : endingOf(run, seen.overview) + if (ending !== undefined) { + return { kind: ending } + } + return waited ? { kind: 'not-back' } : { kind: 'steps', line } +} + +/** + * Returns the ending the overview shows: the new version kept or failed, a failure before, or the one before it back. + * @param run - The update followed. + * @param overview - The overview last read. + * @returns The ending, or undefined while the update runs. + */ +function endingOf(run: UpdateRun, overview: UpdatesOverview): Ending | undefined { + if (overview.running === run.to) { + return ENDING_ON_NEW[ownStep(run, overview)] + } + if (failedBefore(run, overview)) { + return 'over' + } + return ownOutcome(run) && wentBack(run, overview) ? 'rolled-back' : undefined +} + +/** + * Reports whether the overview tells of this update and not the try before it: on a first try, or once a retry moved. + * @param run - The update followed. + * @returns True when a version gone back in the overview is the outcome of this update. + */ +function ownOutcome(run: UpdateRun): boolean { + return run.moved || !run.retry +} + +/** + * Reports whether the version before the update runs again, refusing the version the update switched to. + * @param run - The update followed. + * @param overview - The overview last read. + * @returns True once the update went back. + */ +function wentBack(run: UpdateRun, overview: UpdatesOverview): boolean { + return overview.running === run.from && refusedPastSwitch(run, overview) +} + +/** + * Reports whether the install refuses the version the update went to, its job standing past the switch. + * @param run - The update followed. + * @param overview - The overview last read. + * @returns True when the new version failed its start check. + */ +function refusedPastSwitch(run: UpdateRun, overview: UpdatesOverview): boolean { + return overview.refused.includes(run.to) && PAST_SWITCH.includes(ownStep(run, overview)) +} + +/** + * Reports whether the overview holds a failure of the update other than the one it held when the update started. + * @param run - The update followed. + * @param overview - The overview last read. + * @returns True once the update failed before its switch. + */ +function failedBefore(run: UpdateRun, overview: UpdatesOverview): boolean { + const failure = overview.job?.failure + return failure?.to === run.to && failure.at !== run.priorFailure +} diff --git a/frontend/src/updates/useUpdatesScreen.ts b/frontend/src/updates/useUpdatesScreen.ts new file mode 100644 index 00000000..2b0a8ede --- /dev/null +++ b/frontend/src/updates/useUpdatesScreen.ts @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { hashKey, useQuery, useQueryClient } from '@tanstack/react-query' +import type { QueryClient } from '@tanstack/react-query' +import { useEffect, useState } from 'react' +import type { Dispatch, SetStateAction } from 'react' + +import { useListSettings } from '../settings/useListSettings' +import { fetchUpdates, startUpdate, updatesQueryKey } from './api' +import type { UpdateStart, UpdatesOverview } from './api' +import { heldRun, mayMoveOn, runView, startedRun } from './run' +import type { RunView, UpdateRun } from './run' + +/** The hash the query cache files the overview of the updates under. */ +const updatesHash = hashKey(updatesQueryKey) + +/** What the Updates screen holds: the overview, whether it or the timings failed, the update followed and controls. */ +export interface UpdatesScreenState { + overview: UpdatesOverview | undefined + unread: boolean + view: RunView | undefined + start: (asked: UpdateStart) => Promise + dismiss: () => void +} + +/** + * Returns how often to ask for the overview: as the site sets while the update followed may move on, never otherwise. + * @param view - What the screen sees of the update it follows. + * @param every - How many milliseconds the site waits between two asks. + * @returns The interval, or false to stop asking. + */ +function askingEvery(view: RunView | undefined, every: number | undefined): number | false | undefined { + return mayMoveOn(view) ? every : false +} + +/** A read of the overview: whether it failed, and the overview it left, if any. */ +interface OverviewRead { + isError: boolean + data: UpdatesOverview | undefined +} + +/** + * Reports whether the screen can show nothing to update: no overview arrived, or the timings an update follows failed. + * @param read - The read of the overview. + * @param timingsFailed - Whether the read of the site settings failed. + * @returns True when the screen shows that the updates could not be read. + */ +function unreadable(read: OverviewRead, timingsFailed: boolean): boolean { + const overviewLost = read.isError && read.data === undefined + return overviewLost || timingsFailed +} + +/** + * Marks the wait for a restart as passed once the update stays restarting for as long as the site sets. + * @param view - What the screen sees of the update it follows. + * @param wait - How many milliseconds the site waits for a restart. + * @param setWaited - What marks the wait as passed. + */ +function useRestartWait(view: RunView | undefined, wait: number | undefined, setWaited: (waited: boolean) => void) { + const restarting = view?.restarting === true + useEffect(() => { + if (!restarting) { + return + } + const timer = setTimeout(() => setWaited(true), wait) + return () => clearTimeout(timer) + }, [restarting, wait, setWaited]) +} + +/** + * Keeps the update the screen holds in step with each read of the overview, picking up one under way. + * @param client - The query client the overview is cached in. + * @param setRun - What sets the update the screen holds. + */ +function useHeldRun(client: QueryClient, setRun: Dispatch>) { + useEffect( + () => + client.getQueryCache().subscribe((event) => { + if (event.type === 'updated' && event.query.queryHash === updatesHash) { + const { data, status } = event.query.state + setRun((held) => heldRun(held, data as UpdatesOverview | undefined, status === 'error')) + } + }), + [client, setRun], + ) +} + +/** + * Returns the overview of the updates and the update the screen follows, asking again while one runs. + * @returns The screen's state and the controls that start an update and dismiss its ending. + */ +export function useUpdatesScreen(): UpdatesScreenState { + const client = useQueryClient() + const settings = useListSettings() + const timings = settings.data + const [run, setRun] = useState() + const [waited, setWaited] = useState(false) + const read = useQuery({ + queryKey: updatesQueryKey, + queryFn: fetchUpdates, + retry: false, + refetchIntervalInBackground: true, + refetchInterval: (query) => + askingEvery( + runView(run, query.state.data, query.state.status === 'error', waited), + timings?.updates_progress_milliseconds, + ), + }) + const view = timings === undefined ? undefined : runView(run, read.data, read.isError, waited) + useRestartWait(view, timings?.updates_restart_wait_milliseconds, setWaited) + useHeldRun(client, setRun) + + /** + * Starts the update asked for, then follows it from the overview the start answered, reading it again when refused. + * @param asked - The version to update to and whether to retry it. + */ + async function start(asked: UpdateStart) { + const before = read.data as UpdatesOverview + const answered = await startUpdate(asked).catch((cause: unknown) => { + void client.invalidateQueries({ queryKey: updatesQueryKey }) + throw cause + }) + setWaited(false) + setRun(startedRun(asked, before, answered)) + client.setQueryData(updatesQueryKey, answered) + } + + return { + overview: read.data, + unread: unreadable(read, settings.isError), + view, + start, + dismiss: () => setRun(undefined), + } +} diff --git a/frontend/src/updates/words.ts b/frontend/src/updates/words.ts new file mode 100644 index 00000000..31c12cf4 --- /dev/null +++ b/frontend/src/updates/words.ts @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { formatDate, formatNumber, formatTime } from '@gopherium/gottext' +import { _n, sprintf } from '@wordpress/i18n' + +/** How many milliseconds a minute lasts. */ +const MINUTE = 60_000 + +/** How many milliseconds an hour lasts. */ +const HOUR = 60 * MINUTE + +/** How many milliseconds a day lasts. */ +const DAY = 24 * HOUR + +/** + * Returns a moment as the date and the time of day the site format writes it with. + * @param at - The moment the server stored. + * @returns The date and the time, named for the sentence they fill. + */ +export function dateAndTime(at: string): { date: string, time: string } { + return { date: formatDate(at), time: formatTime(at) } +} + +/** + * Returns how long until a moment, counted the way WordPress counts a time difference. + * @param at - The moment ahead. + * @param now - The moment it is now, in milliseconds. + * @returns The minutes, hours or days left, one minute at the least. + */ +export function timeUntil(at: string, now: number): string { + const left = new Date(at).getTime() - now + if (left < HOUR) { + const minutes = wholeCount(left / MINUTE) + return sprintf(_n('%s minute', '%s minutes', minutes, 'gophenberg'), formatNumber(minutes)) + } + if (left < DAY) { + const hours = wholeCount(left / HOUR) + return sprintf(_n('%s hour', '%s hours', hours, 'gophenberg'), formatNumber(hours)) + } + const days = wholeCount(left / DAY) + return sprintf(_n('%s day', '%s days', days, 'gophenberg'), formatNumber(days)) +} + +/** + * Returns an amount rounded to a whole count of one or more, as WordPress rounds a time difference. + * @param amount - The amount, in minutes, hours or days. + * @returns The whole count. + */ +function wholeCount(amount: number): number { + return Math.max(1, Math.round(amount)) +} diff --git a/internal/app/site_updates_steps_test.go b/internal/app/site_updates_steps_test.go index 5a6e1507..ec7599ff 100644 --- a/internal/app/site_updates_steps_test.go +++ b/internal/app/site_updates_steps_test.go @@ -20,6 +20,7 @@ import ( "github.com/gopherium/gophenberg/internal/cron" "github.com/gopherium/gophenberg/internal/postgres" + "github.com/gopherium/gophenberg/internal/update" "github.com/gopherium/gophenberg/internal/updater" "github.com/gopherium/gophenberg/internal/version" ) @@ -76,6 +77,8 @@ type answeredBackups struct { // initializeSiteUpdates binds the steps of the scenarios where an administrator asks the site for its updates to s. func initializeSiteUpdates(sc *godog.ScenarioContext, s *operatorScenario) { sc.Given(`^an earlier update failed at the step "([^"]*)"$`, s.failEarlierUpdate) + sc.Given(`^an earlier update from "([^"]*)" to this version failed at the step "([^"]*)"$`, s.failUpdateToThis) + sc.Given(`^the last check ran on the build "([^"]*)" and found this version$`, s.checkedOnBuild) sc.Given(`^the operator ran "([^"]*)" and it failed$`, s.ranLineFailing) sc.Given(`^the install root keeps (\d+) database backups, the newest taken at "([^"]*)"$`, s.keepBackups) sc.Given(`^the settings keep (\d+) backups$`, s.keepBackupLimit) @@ -89,6 +92,8 @@ func initializeSiteUpdates(sc *godog.ScenarioContext, s *operatorScenario) { sc.Then(`^the site says this install can update itself$`, s.saysItCanUpdate) sc.Then(`^the site says this install cannot update itself, since "([^"]*)"$`, s.saysItCannotUpdate) sc.Then(`^the site names no refused version and no update$`, s.namesNothingRefused) + sc.Then(`^the site names no update on offer$`, s.namesNoOffer) + sc.Then(`^the site names no failure$`, s.namesNoFailure) sc.Then(`^the site names "([^"]*)" as refused$`, s.namesRefused) sc.Then(`^the site names the update from this version to "([^"]*)" at the step "([^"]*)"$`, s.namesUpdate) sc.Then(`^the site names when the update from this version to "([^"]*)" failed, at the step "([^"]*)", `+ @@ -109,6 +114,40 @@ func (s *operatorScenario) failEarlierUpdate(step string) error { }) } +// failUpdateToThis records that an earlier update from the build from to this version failed an hour ago at step. +func (s *operatorScenario) failUpdateToThis(from, step string) error { + return editState(s.env[installRootSetting], func(state *updater.State) { + state.Failure = &updater.JobFailure{ + At: time.Now().Add(-time.Hour).UTC(), From: from, To: version.Version(), Step: updater.Step(step), + Error: "an earlier update failed", + } + }) +} + +// checkedOnBuild stores what a check by the build running found on an update site offering this version. +func (s *operatorScenario) checkedOnBuild(ctx context.Context, running string) error { + s.offerUpdate(version.Version()) + address, addressErr := update.ParseAddress(s.site.address) + roots, rootsErr := update.ParseRoots(s.site.trustedRoots()) + pool, poolErr := pgxpool.New(ctx, s.env["GOPHENBERG_DATABASE_URL"]) + if err := errors.Join(addressErr, rootsErr, poolErr); err != nil { + return err + } + defer pool.Close() + check := update.Config{ + Address: address, Channel: "stable", Roots: roots, Client: update.NewClient(siteStartLimit), + Site: update.Site{Running: running}, Now: time.Now, + } + result, err := update.Run(ctx, check, postgres.NewSettingStore(pool)) + if err != nil { + return err + } + if result.Offer == nil || result.Offer.Version != version.Version() { + return fmt.Errorf("the check by %s found %+v, want %s on offer", running, result.Offer, version.Version()) + } + return nil +} + // ranLineFailing runs the command line and fails unless the command failed. func (s *operatorScenario) ranLineFailing(line string) error { s.runLine(line) @@ -270,6 +309,22 @@ func (s *operatorScenario) namesNothingRefused() error { return nil } +// namesNoOffer fails unless the site names no update on offer. +func (s *operatorScenario) namesNoOffer() error { + if !strings.Contains(s.updates.body, `"offer":null`) { + return fmt.Errorf("the site answered %s, want offer null", s.updates.body) + } + return nil +} + +// namesNoFailure fails unless the site names no failure of an update. +func (s *operatorScenario) namesNoFailure() error { + if s.updates.Job != nil && s.updates.Job.Failure != nil { + return fmt.Errorf("the site answered %s, want no failure", s.updates.body) + } + return nil +} + // namesRefused fails unless the site names release among the refused versions. func (s *operatorScenario) namesRefused(release string) error { if !slices.Contains(s.updates.Refused, release) { diff --git a/internal/app/updates.go b/internal/app/updates.go index 67dcfae4..b3bab484 100644 --- a/internal/app/updates.go +++ b/internal/app/updates.go @@ -150,12 +150,43 @@ func (u siteUpdates) Overview(ctx context.Context) (server.UpdatesOverview, erro return server.UpdatesOverview{}, err } reason := updater.CannotUpdate(u.install, u.stamp) + running := version.Version() return server.UpdatesOverview{ - Result: result, Overview: install, Running: version.Version(), CanUpdate: reason == "", CannotUpdate: reason, - NextCheck: next, + Result: withoutReachedOffer(result, running), Overview: withoutReachedFailure(install, running), + Running: running, CanUpdate: reason == "", CannotUpdate: reason, NextCheck: next, }, nil } +// withoutReachedOffer returns result without its offer once running is that version or a newer one, as after an update. +func withoutReachedOffer(result update.Result, running string) update.Result { + if result.Offer != nil && !version.Before(running, result.Offer.Version) { + result.Offer = nil + } + return result +} + +// withoutReachedFailure returns install without the failure of an update to running or an older version. +func withoutReachedFailure(install updater.Overview, running string) updater.Overview { + if !failedOnReachedVersion(install.Job, running) { + return install + } + cleared := *install.Job + cleared.Failure = nil + install.Job = &cleared + if cleared.Step == "" { + install.Job = nil + } + return install +} + +// failedOnReachedVersion reports whether job holds the failure of an update to running or an older version. +func failedOnReachedVersion(job *updater.LastUpdate, running string) bool { + if job == nil || job.Failure == nil { + return false + } + return !version.Before(running, job.Failure.To) +} + // nextCheck returns when the check job runs next, now while it is due, and none while the checks are off. func (u siteUpdates) nextCheck(ctx context.Context) (*time.Time, error) { if !u.settings.checks { diff --git a/internal/app/updates_test.go b/internal/app/updates_test.go index 5f674d99..d9b368b4 100644 --- a/internal/app/updates_test.go +++ b/internal/app/updates_test.go @@ -410,6 +410,42 @@ func TestSiteUpdatesOverviewReportsWhatItCannotRead(t *testing.T) { } } +func TestSiteUpdatesOverviewDropsAnOfferTheRunningVersionReached(t *testing.T) { + t.Parallel() + + for running, kept := range map[string]bool{"0.20.0": true, "0.20.1": false, "0.20.2": false} { + got := withoutReachedOffer(update.Result{Offer: &update.Found{Version: "0.20.1"}}, running) + + if (got.Offer != nil) != kept { + t.Errorf("withoutReachedOffer() on %s = %+v, want the offer of 0.20.1 kept %v", running, got.Offer, kept) + } + } +} + +func TestSiteUpdatesOverviewDropsTheFailureOfAnUpdateTheRunningVersionReached(t *testing.T) { + t.Parallel() + + failure := &updater.JobFailure{From: "0.20.0", To: "0.20.1", Step: updater.StepDownload} + committed := &updater.LastUpdate{Step: updater.StepCommitted, From: "0.19.0", To: "0.20.0", Failure: failure} + cleared := &updater.LastUpdate{Step: updater.StepCommitted, From: "0.19.0", To: "0.20.0"} + for name, tc := range map[string]struct { + job *updater.LastUpdate + running string + want *updater.LastUpdate + }{ + "a failure of an update to a newer version": {job: committed, running: "0.20.0", want: committed}, + "a failure of an update to the running version": {job: committed, running: "0.20.1", want: cleared}, + "a failure alone, to the running version": {job: &updater.LastUpdate{Failure: failure}, running: "0.20.1"}, + "no update at all": {running: "0.20.1"}, + } { + got := withoutReachedFailure(updater.Overview{Job: tc.job}, tc.running) + + if !reflect.DeepEqual(got.Job, tc.want) { + t.Errorf("withoutReachedFailure() with %s = %+v, want %+v", name, got.Job, tc.want) + } + } +} + func TestUpdateSummaryNamesTheVersionOnOffer(t *testing.T) { t.Parallel() diff --git a/internal/i18n/catalogs/es-ES.json b/internal/i18n/catalogs/es-ES.json index 491c9dac..ee837c14 100644 --- a/internal/i18n/catalogs/es-ES.json +++ b/internal/i18n/catalogs/es-ES.json @@ -1 +1 @@ -{"":{"lang":"es","plural-forms":"nplurals=3; plural=((n == 1) ? 0 : ((n != 0 && n % 1000000 == 0) ? 1 : 2));"}," and ":[" y "]," or ":[" o "],"\"%s\" activated.":["Se ha activado «%s»."],"\"%s\" deactivated.":["Se ha desactivado «%s»."],"\"%s\" has been restored.":["«%s» se ha restaurado."],"\"%s\" moved to the trash.":["«%s» trasladado a la papelera."],"\"%s\" permanently deleted.":["«%s» borrado permanentemente."],"\"%s\" successfully created.":["«%s» creado correctamente."],"\"%s\" uploaded.":["«%s» subido."],"%(field)s address":["Dirección de %(field)s"],"%(field)s cannot move inside itself. Pick a container that is not one of its own.":["%(field)s no puede moverse dentro de sí mismo. Elige un contenedor que no sea uno de los suyos."],"%(field)s declared.":["%(field)s declarado."],"%(field)s deleted.":["%(field)s borrado."],"%(field)s does not match the format its field asks for. Check it and save again.":["%(field)s no tiene el formato que su campo requiere. Revísalo y guarda de nuevo."],"%(field)s goes no higher than %(limit)s. Lower the value and save again.":["%(field)s no pasa de %(limit)s. Baja el valor y guarda de nuevo."],"%(field)s goes no lower than %(limit)s. Raise the value and save again.":["%(field)s no baja de %(limit)s. Sube el valor y guarda de nuevo."],"%(field)s holds no value of its own, so it cannot be required. Make it optional.":["%(field)s no guarda ningún valor propio, así que no puede ser obligatorio. Hazlo opcional."],"%(field)s is optional again.":["%(field)s vuelve a ser opcional."],"%(field)s is required now.":["%(field)s ahora es obligatorio."],"%(field)s moved.":["%(field)s movido."],"%(field)s names the same one twice. Remove the repeat and save again.":["%(field)s nombra el mismo dos veces. Quita la repetición y guarda de nuevo."],"%(field)s needs at least %(limit)s files. Add one and save again.":["%(field)s necesita al menos %(limit)s archivos. Añade uno y guarda de nuevo."],"%(field)s needs at least %(limit)s rows. Add one and save again.":["%(field)s necesita al menos %(limit)s filas. Añade una y guarda de nuevo."],"%(field)s only takes one of its listed choices. Pick one and save again.":["%(field)s solo admite una de las opciones de su lista. Elige una y guarda de nuevo."],"%(field)s reads a relation field that is not there. Pick a group and a relation field it holds.":["%(field)s lee un campo de relación que no existe. Elige un grupo y un campo de relación que contenga."],"%(field)s reads a relation pointing at %(type)s, so it would list nothing here. Pick a relation pointing at the items this group is shown on.":["%(field)s lee una relación que apunta a %(type)s, así que aquí no mostraría nada. Elige una relación que apunte a los elementos donde se muestra este grupo."],"%(field)s renamed.":["%(field)s renombrado."],"%(field)s settled.":["%(field)s ajustado."],"%(field)s shows by its rules now.":["%(field)s ahora se muestra según sus reglas."],"%(field)s stands in the list.":["%(field)s aparece en la lista."],"%(field)s stays out of the list.":["%(field)s se queda fuera de la lista."],"%(field)s takes at most %(limit)s files. Remove one and save again.":["%(field)s acepta como mucho %(limit)s archivos. Quita uno y guarda de nuevo."],"%(field)s takes at most %(limit)s letters. Shorten what you wrote and save again.":["%(field)s acepta como mucho %(limit)s letras. Acorta lo que has escrito y guarda de nuevo."],"%(field)s takes at most %(limit)s rows. Remove one and save again.":["%(field)s admite como mucho %(limit)s filas. Quita una y guarda de nuevo."],"%(field)s title":["Título de %(field)s"],"%(file)s is larger than one upload may be.":["%(file)s es más grande de lo que una subida permite."],"%(file)s is not a file this block accepts.":["%(file)s no es un archivo que este bloque acepte."],"%(file)s: %(reason)s":["%(file)s: %(reason)s"],"%(group)s created.":["%(group)s creado."],"%(group)s now appears where you said.":["%(group)s ya aparece donde has dicho."],"%(group)s removed.":["%(group)s eliminado."],"%(group)s updated.":["%(group)s actualizado."],"%(key)s is served by %(winner)s, so %(loser)s does not show it on %(where)s.":["%(key)s lo sirve %(winner)s, así que %(loser)s no lo muestra en %(where)s."],"%(name)s %(version)s is serving the public site.":["%(name)s %(version)s está publicado en la web."],"%(name)s belongs to the site now.":["%(name)s ya pertenece al sitio."],"%(name)s came from the %(plugin)s plugin, which no longer declares it.":["%(name)s vino del plugin %(plugin)s, que ya no lo declara."],"%(name)s cannot be used as a theme name. Name the zip file after the theme, with no dot at the start and no slashes in it.":["%(name)s no se puede usar como nombre de tema. Nombra el archivo zip como el tema, sin punto al principio y sin barras."],"%(name)s moves to /%(word)s. Every address of both types changes.":["El tipo %(name)s pasa a /%(word)s. Cambian todas las direcciones de ambos tipos."],"%(name)s would move to /%(word)s, which Gophenberg keeps for itself. Change its plural name and try again.":["El tipo %(name)s pasaría a /%(word)s, que Gophenberg reserva para sí mismo. Cambia su nombre en plural e inténtalo de nuevo."],"%(source)s is %(value)s":["%(source)s es %(value)s"],"%(theme)s failed to start, so the built-in renderer is serving.":["%(theme)s no pudo arrancar, así que el renderizador ha tomado el relevo."],"%(theme)s is now serving the public site.":["%(theme)s ya sirve el sitio público."],"%(theme)s is serving the public site.":["%(theme)s sirve el sitio público."],"%(theme)s is still starting, so the built-in renderer is serving.":["%(theme)s todavía está arrancando, así que el renderizador ha tomado el relevo."],"%(theme)s was installed.":["%(theme)s se ha instalado."],"%(theme)s will not load, so the built-in renderer is serving.":["%(theme)s no se carga, así que el renderizador ha tomado el relevo."],"%(type)s answers on a new address, and stored links move with it.":["%(type)s responde en una dirección nueva, y los enlaces guardados se mueven con ella."],"%(type)s becomes the type the site opens on, and the old one takes an address.":["%(type)s pasa a ser el tipo con el que abre el sitio, y el anterior toma una dirección."],"%(type)s keeps nesting while %(items)s of its items sit inside another. Move those to the top level first, the ones in the trash included.":["%(type)s sigue anidando mientras %(items)s de sus elementos están dentro de otro. Muévelos primero al nivel superior, incluidos los de la papelera."],"%(type)s keeps nesting, because some of its items sit inside another.":["%(type)s sigue anidando, porque algunos de sus elementos están dentro de otro."],"%(type)s will answer at the root.":["El tipo %(type)s responderá en la raíz."],"%s content type activated.":["Se ha activado %s tipo de contenido.","Se han activado %s de tipos de contenido.","Se han activado %s tipos de contenido."],"%s content type could not be activated.":["No se ha podido activar %s tipo de contenido.","No se han podido activar %s de tipos de contenido.","No se han podido activar %s tipos de contenido."],"%s content type could not be deactivated.":["No se ha podido desactivar %s tipo de contenido.","No se han podido desactivar %s de tipos de contenido.","No se han podido desactivar %s tipos de contenido."],"%s content type could not be permanently deleted.":["No se ha podido borrar permanentemente %s tipo de contenido.","No se han podido borrar permanentemente %s de tipos de contenido.","No se han podido borrar permanentemente %s tipos de contenido."],"%s content type deactivated.":["Se ha desactivado %s tipo de contenido.","Se han desactivado %s de tipos de contenido.","Se han desactivado %s tipos de contenido."],"%s content type permanently deleted.":["Se ha borrado permanentemente %s tipo de contenido.","Se han borrado permanentemente %s de tipos de contenido.","Se han borrado permanentemente %s tipos de contenido."],"%s item could not be moved to the trash.":["No se ha podido mover %s elemento a la papelera.","No se han podido mover %s de elementos a la papelera.","No se han podido mover %s elementos a la papelera."],"%s item could not be permanently deleted.":["No se ha podido borrar permanentemente %s elemento.","No se han podido borrar permanentemente %s de elementos.","No se han podido borrar permanentemente %s elementos."],"%s item could not be restored.":["No se ha podido restaurar %s elemento.","No se han podido restaurar %s de elementos.","No se han podido restaurar %s elementos."],"%s item moved to the trash.":["%s elemento movido a la papelera.","%s de elementos movidos a la papelera.","%s elementos movidos a la papelera."],"%s item permanently deleted.":["%s elemento borrado permanentemente.","%s de elementos borrados permanentemente.","%s elementos borrados permanentemente."],"%s item stays in the trash.":["%s elemento sigue en la papelera.","%s de elementos siguen en la papelera.","%s elementos siguen en la papelera."],"%s page has been restored.":["Se ha restaurado %s página.","Se han restaurado %s de páginas.","Se han restaurado %s páginas."],"%s post has been restored.":["Se ha restaurado %s entrada.","Se han restaurado %s de entradas.","Se han restaurado %s entradas."],"(no title)":["(sin título)"],"A %(kind)s field does not take a setting called %(setting)s. Remove it and try again.":["Un campo %(kind)s no acepta un ajuste llamado %(setting)s. Quítalo y prueba de nuevo."],"A Linked from field stands on its own, not inside a section or a repeater. Declare %(field)s beside the container.":["Un campo Enlazado desde va por su cuenta, no dentro de una sección ni de un repetidor. Declara %(field)s junto al contenedor."],"A content type needs a singular and a plural name, like Guide and Guides. Fill both in and try again.":["Un tipo de contenido necesita un nombre en singular y otro en plural, como Guía y Guías. Rellena ambos e inténtalo de nuevo."],"A descriptive summary of the content type.":["Un resumen descriptivo del tipo de contenido."],"A field group key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Rename the group in the file so its key comes out in that shape.":["La clave de un grupo de campos tiene que empezar por una letra minúscula y después llevar solo letras minúsculas, números y guiones. Cambia el nombre del grupo en el archivo para que su clave salga con esa forma."],"A field key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Rename the field so its key comes out in that shape.":["La clave de un campo tiene que empezar por una letra minúscula y contener solo letras minúsculas, números y guiones. Renombra el campo para que su clave tenga esa forma."],"A field needs a name. Type one and try again.":["El campo necesita un nombre. Escribe uno e inténtalo de nuevo."],"A field with that name already exists on the items this group reaches. Pick another name.":["Ya existe un campo con ese nombre en los elementos que este grupo alcanza. Elige otro nombre."],"A flexible content field holds layouts, and %(field)s is not one. Add a layout first, then declare the field inside that layout.":["Un campo de contenido flexible contiene diseños, y %(field)s no lo es. Añade primero un diseño y después declara el campo dentro de ese diseño."],"A higher quality stores larger files, and it applies to pictures uploaded from now on.":["Una calidad más alta almacena archivos más grandes, y se aplica a las imágenes que subas a partir de ahora."],"A layout stands inside a flexible content field only. Put %(field)s inside one of those instead.":["Un diseño solo va dentro de un campo de contenido flexible. Pon %(field)s dentro de uno de ellos."],"A layout stands inside a flexible content field, never on its own. Declare a flexible content field first, then add %(field)s inside it.":["Un diseño va dentro de un campo de contenido flexible, nunca por su cuenta. Declara primero un campo de contenido flexible y después añade %(field)s dentro."],"A listing carries between 1 and %(max)s items, so %(value)s is not a size Gophenberg takes. Pick a number inside that range.":["Un listado muestra entre 1 y %(max)s elementos, así que %(value)s no es un tamaño que Gophenberg acepte. Elige un número dentro de ese rango."],"A relation field has to say which content type it points at. Pick that type and try again.":["Un campo de relación tiene que indicar a qué tipo de contenido apunta. Elige ese tipo e inténtalo de nuevo."],"A reload shows the admin in the language you chose.":["Al recargar verás el panel de administración en el idioma que has elegido."],"A route word has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Change it and try again.":["La palabra de ruta de la URL tiene que empezar por una letra minúscula y contener solo letras minúsculas, números y guiones. Cámbiala e inténtalo de nuevo."],"A row of %(field)s has to name the layout it takes. Pick a layout for the row, or remove the row.":["Una fila de %(field)s tiene que nombrar el diseño que toma. Elige un diseño para la fila, o quita la fila."],"A row of %(field)s takes one layout and no more. Reload the page and build the row again.":["Una fila de %(field)s toma un solo diseño. Recarga la página y crea la fila otra vez."],"A rule matching any %(source)s cannot be turned into an exclusion. Leave it as is, or name the ones to leave out instead.":["Una regla que vale para cualquier %(source)s no se puede convertir en exclusión. Déjala como está, o nombra los que quieras dejar fuera."],"A theme naming its own page size uses that instead.":["Un tema que indica su propio tamaño de página usa ese en su lugar."],"A type key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Change the key and try again.":["La clave de un tipo tiene que empezar por una letra minúscula y contener solo letras minúsculas, números y guiones. Cambia la clave e inténtalo de nuevo."],"Actions":["Acciones"],"Activate":["Activar"],"Activate %(theme)s":["Activar %(theme)s"],"Active":["Activo"],"Add":["Añadir"],"Add %(layout)s":["Añadir %(layout)s"],"Add %(name)s":["Añadir %(name)s"],"Add %(type)s":["Añadir %(type)s"],"Add Category":["Añadir categoría"],"Add Content Type":["Añadir tipo de contenido"],"Add Field Group":["Añadir grupo de campos"],"Add Media File":["Añadir medios"],"Add Page":["Añadir página"],"Add Post":["Añadir entrada"],"Add User":["Añadir usuario"],"Add block":["Añadir bloque"],"Add choice":["Añadir opción"],"Add condition":["Añadir condición"],"Add field":["Añadir campo"],"Add field to %(field)s":["Añadir campo a %(field)s"],"Add layout":["Añadir diseño"],"Add layout to %(field)s":["Añadir diseño a %(field)s"],"Add one with %(button)s.":["Añade un elemento con %(button)s."],"Add row":["Añadir fila"],"Add rule set":["Añadir conjunto de reglas"],"Add title":["Añadir título"],"Add to %(field)s":["Añadir a %(field)s"],"Address":["Dirección"],"Address updated.":["Dirección actualizada."],"Adopt":["Adoptar"],"Allow custom":["Permitir valores propios"],"Allow empty":["Permitir vacío"],"Alt text":["Texto alternativo"],"An item cannot point at itself. Pick a different item for %(field)s.":["Un elemento no puede apuntarse a sí mismo. Elige otro elemento para %(field)s."],"An item cannot sit inside itself, or inside one of the items nested under it. Pick a parent outside this branch.":["Un elemento no puede estar dentro de sí mismo, ni dentro de otro anidado bajo él. Elige un nivel superior fuera de esta rama."],"Another account wrote this, and only its author, an editor or an administrator may change it. You can still read it.":["Otra cuenta escribió esto, y solo su autor, un editor o un administrador pueden cambiarlo. Todavía puedes leerlo."],"Another account wrote this, so you are reading it rather than editing it.":["Otra cuenta escribió esto, así que lo estás leyendo, no editando."],"Another content type already answers under this route word. Pick a different word.":["Ya hay otro tipo de contenido que responde con esta palabra de ruta de URL. Elige una palabra distinta."],"Another content type already lives at the root of your site, and only one can. Give this type a route word, or hand the root over with Make default.":["Ya hay otro tipo de contenido en la raíz de tu sitio, y solo puede haber uno. Dale a este tipo de contenido una palabra de ruta de URL, o cede la raíz con Establecer como predeterminado."],"Another content type already uses this key. Give this type a different name.":["Ya hay otro tipo de contenido que usa esta clave. Dale a este tipo un nombre distinto."],"Another item of this content type already uses that address. Pick a different slug and save again.":["Ya hay otro elemento de este tipo de contenido que usa esa dirección. Elige un slug distinto y guarda de nuevo."],"Another update is currently in progress.":["En este momento hay otra actualización en marcha."],"Appears on":["Aparece en"],"Apply":["Aplicar"],"April":["abril"],"Are you sure you want to move \"%s\" to the trash?":["¿Seguro que quieres mover «%s» a la papelera?"],"Audio":["Audio"],"August":["agosto"],"Author":["Autor"],"Back to %(type)s":["Volver a %(type)s"],"Back to the latest posts":["Volver a las últimas entradas"],"Block":["Bloque"],"Broken":["Roto"],"Bundles of fields, shown where their rules place them.":["Conjuntos de campos, mostrados donde sus reglas los colocan."],"Button group":["Grupo de botones"],"Cancel":["Cancelar"],"Caption":["Leyenda"],"Change %(name)s":["Cambiar %(name)s"],"Change address":["Cambiar la dirección"],"Change address…":["Cambiar la dirección…"],"Change role":["Cambiar el rol"],"Change the role of %(name)s":["Cambiar el rol de %(name)s"],"Checkbox group":["Grupo de casillas"],"Choices":["Opciones"],"Choose %(field)s":["Elegir %(field)s"],"Choose how the site serves its content.":["Elige cómo el sitio sirve su contenido."],"Choose the language the admin reads in.":["Elige el idioma en el que se lee el panel de administración."],"Choose the role of %(name)s.":["Elige el rol de %(name)s."],"Choose the version to update to.":["Elige la versión a la que actualizar."],"Clear %(field)s":["Vaciar %(field)s"],"Close":["Cerrar"],"Close Settings":["Cerrar ajustes"],"Closed":["Cerrado"],"Condition":["Condición"],"Content":["Contenido"],"Content Types":["Tipos de contenido"],"Content nests at most %(max)s levels deep, and this item would sit deeper. Pick a parent closer to the top.":["El contenido se anida como mucho %(max)s niveles, y este elemento quedaría más abajo. Elige un nivel superior más cercano al inicio."],"Content type":["Tipo de contenido"],"Content type updated.":["Tipo de contenido actualizado."],"Could not load that post.":["No se ha podido cargar esa entrada."],"Could not save image. %s":["No se ha podido guardar la imagen. %s"],"Could not save media. %s":["No se ha podido guardar el archivo multimedia. %s"],"Could not save that post.":["No se ha podido guardar esa entrada."],"Create":["Crear"],"Create a field group":["Crear un grupo de campos"],"Create user":["Crear usuario"],"Created":["Fecha de creación"],"Date added":["Fecha de inclusión"],"Date modified":["Fecha de modificación"],"Deactivate":["Desactivar"],"Deactivate %(theme)s":["Desactivar %(theme)s"],"December":["diciembre"],"Default":["Por defecto"],"Default content type updated.":["Tipo de contenido predeterminado actualizado."],"Definitions file":["Archivo de definiciones"],"Delete":["Borrar"],"Delete \"%(title)s\" for good? This cannot be undone.":["¿Borrar permanentemente «%(title)s»? Esto no se puede deshacer."],"Delete %(field)s":["Borrar %(field)s"],"Delete %(group)s":["Eliminar %(group)s"],"Delete %s content type for good? This cannot be undone.":["¿Borrar permanentemente %s tipo de contenido? Esto no se puede deshacer.","¿Borrar permanentemente %s de tipos de contenido? Esto no se puede deshacer.","¿Borrar permanentemente %s tipos de contenido? Esto no se puede deshacer."],"Delete %s item for good? This cannot be undone.":["¿Borrar permanentemente %s elemento? Esto no se puede deshacer.","¿Borrar permanentemente %s de elementos? Esto no se puede deshacer.","¿Borrar permanentemente %s elementos? Esto no se puede deshacer."],"Delete permanently":["Borrar permanentemente"],"Delete the field":["Borrar el campo"],"Delete the group":["Eliminar el grupo"],"Delete…":["Borrar…"],"Describe":["Describir"],"Describe the purpose of the image.":["Describe el propósito de la imagen."],"Describe…":["Describir…"],"Description":["Descripción"],"Description updated.":["Descripción actualizada."],"Desktop":["Escritorio"],"Destination":["Destino"],"Dimensions":["Dimensiones"],"Disable":["Desactivar"],"Disable %(name)s":["Desactivar a %(name)s"],"Disabled":["Desactivado"],"Dismiss":["Descartar"],"Document":["Documento"],"Documents":["Documentos"],"Done. The site now holds what the file describes.":["Hecho. El sitio ya tiene lo que describe el archivo."],"Draft saved.":["Borrador guardado."],"Drop files to upload":["Arrastra los archivos para subirlos"],"Edit media":["Editar los medios"],"Edit…":["Editar…"],"Email":["Correo electrónico"],"Empty Trash":["Vaciar papelera"],"Empty trash":["Vaciar papelera"],"Enable":["Activar"],"Enable %(name)s":["Activar a %(name)s"],"Every address of this type moves. Links kept elsewhere to the old addresses stop working.":["Cambian todas las direcciones de este tipo. Los enlaces guardados en otro sitio hacia las direcciones antiguas dejan de funcionar."],"Every content type":["Todos los tipos de contenido"],"Every field group needs a title. Give it a name and save again.":["Todo grupo de campos necesita un título. Ponle un nombre y guarda otra vez."],"Every item needs an author who exists. Pick one from the list and save again.":["Cada elemento necesita un autor que exista. Elige uno de la lista y guarda de nuevo."],"Every kind of content this site holds.":["Todos los tipos de contenido que hay en este sitio."],"Every value stored under this field goes with it, in every item the group reaches and in the revisions behind them.":["Todos los valores guardados en este campo se van con él, en cada elemento que el grupo alcanza y en las revisiones que hay detrás."],"Excerpt":["Extracto"],"Export definitions":["Exportar definiciones"],"February":["febrero"],"Fewest files":["Mínimo de archivos"],"Fewest rows":["Mínimo de filas"],"Field":["Campo"],"Field Groups":["Grupos de campos"],"Field group":["Grupo de campos"],"Fields":["Campos"],"Fields of %(group)s":["Campos de %(group)s"],"File name":["Nombre del archivo"],"File size":["Tamaño del archivo"],"File type":["Tipo de archivo"],"Filter by status":["Filtrar por estado"],"Follow the browser":["Sigue al navegador"],"From %(plugin)s":["De %(plugin)s"],"Full Size":["Tamaño completo"],"Gophenberg cannot start this update: %(reason)s":["Gophenberg no puede empezar esta actualización: %(reason)s"],"Gophenberg checked for updates moments ago. Try again later.":["Gophenberg ha buscado actualizaciones hace un momento. Inténtalo de nuevo más tarde."],"Gophenberg could not read what your browser sent. Reload the page and try again, and tell whoever looks after your site if it keeps happening.":["Gophenberg no ha podido leer lo que ha enviado tu navegador. Recarga la página e inténtalo de nuevo, y avisa a quien gestiona tu sitio si sigue pasando."],"Gophenberg could not read which item you picked as parent. Reload the page and pick it again.":["Gophenberg no ha podido leer qué elemento has elegido como elemento superior. Recarga la página y vuelve a elegirlo."],"Gophenberg does not accept %(extension)s files. Upload a picture, a video, an audio file, a PDF or a zip instead.":["Gophenberg no acepta archivos %(extension)s. Sube una imagen, un vídeo, un audio, un PDF o un zip."],"Gophenberg does not answer in %(value)s. Pick one of the languages on the list.":["Gophenberg no responde en %(value)s. Elige uno de los idiomas de la lista."],"Gophenberg has no autosave of yours for this item. Open the item to see the version that is stored.":["Gophenberg no tiene ningún guardado automático tuyo de este elemento. Ábrelo para ver la versión guardada."],"Gophenberg holds no kind of definition called %(subject)s, so nothing was taken over. Reload the page so the admin and the server agree again.":["Gophenberg no tiene ninguna clase de definición llamada %(subject)s, así que no se ha adoptado nada. Recarga la página para que el admin y el servidor vuelvan a coincidir."],"Gophenberg keeps /%(path)s for itself or for another content type, so your content cannot answer there. Give the item a different slug.":["Gophenberg reserva la dirección /%(path)s para sí mismo o para otro tipo de contenido, así que tu contenido no puede usarla. Dale al elemento otro slug."],"Gophenberg keeps this word for itself, so no content type can answer under it. Pick a different route word.":["Gophenberg reserva esta palabra para sí mismo, así que ningún tipo de contenido puede usarla. Elige otra palabra de ruta de URL."],"Group":["Grupo"],"Highest":["Máximo"],"Holds":["Contiene"],"Images":["Imágenes"],"Import definitions":["Importar definiciones"],"In list":["En la lista"],"Inactive":["Inactivo"],"Installed":["Instalado"],"Instructions":["Instrucciones"],"It moves here from another group and keeps its stored values.":["Se mueve aquí desde otro grupo y conserva sus valores guardados."],"It moves to another group and keeps its stored values.":["Se mueve a otro grupo y conserva sus valores guardados."],"It moves to another group, so its stored values do not follow.":["Se mueve a otro grupo, así que sus valores guardados no le siguen."],"It reads a relation inside a container, and only an import can point it elsewhere.":["Lee una relación dentro de un contenedor, y solo una importación puede apuntarlo a otro sitio."],"It starts on %(type)s, and the rules may be edited afterwards.":["Empieza en %(type)s, y las reglas se pueden editar después."],"Items could not be loaded.":["No se han podido cargar los elementos."],"Its items sit inside one another, so it keeps nesting.":["Sus elementos están unos dentro de otros, así que sigue anidando."],"Its kind changed, so its stored values go with it.":["Su tipo ha cambiado, así que sus valores guardados se van con él."],"January":["enero"],"July":["julio"],"June":["junio"],"Keep %(field)s out of the list":["Dejar %(field)s fuera de la lista"],"Keep it":["Conservarlo"],"Keep it here":["Dejarlo aquí"],"Key":["Clave"],"Label":["Etiqueta"],"Language":["Idioma"],"Large":["Grande"],"Leave empty if decorative.":["Déjalo vacío si es decorativo."],"Let items nest":["Permitir anidar"],"Linked from":["Enlazado desde"],"List view":["Vista de lista"],"Loading field groups.":["Cargando los grupos de campos."],"Loading the post.":["Cargando la entrada."],"Loading the screen.":["Cargando la pantalla."],"Loading themes.":["Cargando los temas."],"Loading users.":["Cargando los usuarios."],"Loading…":["Cargando…"],"Longest":["Largo máximo"],"Lowest":["Mínimo"],"Make %(field)s optional":["Hacer %(field)s opcional"],"Make default":["Establecer como predeterminado"],"Make default…":["Establecer como predeterminado…"],"Make optional":["Hacer opcional"],"Manage the categories on this site.":["Gestiona las categorías de este sitio."],"Manage the images and files this site holds.":["Gestiona las imágenes y los archivos que hay en este sitio."],"Manage the items of this content type.":["Gestiona los elementos de este tipo de contenido."],"Manage the pages on this site.":["Gestiona las páginas de este sitio."],"Manage the posts on this site.":["Gestiona las entradas de este sitio."],"Many targets":["Varios destinos"],"Many values":["Varios valores"],"March":["marzo"],"May":["mayo"],"Media %(id)s":["Medio %(id)s"],"Media Library":["Biblioteca de medios"],"Media file updated.":["Archivo de medios actualizado."],"Medium":["Mediano"],"Mobile":["Móvil"],"Modified: %s":["Modificado: %s"],"Most files":["Máximo de archivos"],"Most rows":["Máximo de filas"],"Move":["Mover"],"Move \"%(title)s\" to the trash?":["¿Mover «%(title)s» a la papelera?"],"Move %(field)s down":["Bajar %(field)s"],"Move %(field)s elsewhere":["Mover %(field)s a otro sitio"],"Move %(field)s up":["Subir %(field)s"],"Move %(group)s down":["Bajar %(group)s"],"Move %(group)s up":["Subir %(group)s"],"Move %(name)s down":["Bajar %(name)s"],"Move %(name)s up":["Subir %(name)s"],"Move %s item to the trash?":["¿Mover %s elemento a la papelera?","¿Mover %s de elementos a la papelera?","¿Mover %s elementos a la papelera?"],"Move every address":["Mover todas las direcciones"],"Move row down":["Bajar la fila"],"Move row up":["Subir la fila"],"Move the field":["Mover el campo"],"Move to trash":["Mover a la papelera"],"Name":["Nombre"],"Name updated.":["Nombre actualizado."],"Nests":["Anida"],"Newer posts":["Entradas más recientes"],"No":["No"],"No content types found.":["No se han encontrado tipos de contenido."],"No description":["Sin descripción"],"No file arrived with this upload. Choose a file and try again.":["No ha llegado ningún archivo con esta subida. Elige un archivo e inténtalo de nuevo."],"No items found.":["No se han encontrado elementos."],"No items yet.":["Todavía no hay elementos."],"No media chosen":["Ningún medio elegido"],"No media has been uploaded yet.":["Todavía no se ha subido ningún medio."],"No media items found.":["No se han encontrado archivos de medios."],"No media items yet.":["Todavía no hay archivos de medios."],"No page lives at this address.":["No existe ninguna página en esta dirección."],"No parent":["Sin elemento superior"],"No theme arrived with this upload. Choose a zip file and try again.":["No ha llegado ningún tema con esta subida. Elige un archivo zip e inténtalo de nuevo."],"No themes are installed.":["No hay ningún tema instalado."],"No title":["Sin título"],"None":["Ninguno"],"Not %(type)s":["Excepto %(type)s"],"Not found":["No encontrado"],"Not serving":["No está sirviendo"],"Nothing declares that role.":["Nada declara ese rol."],"Nothing points here yet.":["Todavía no apunta nada aquí."],"Nothing published here yet.":["Todavía no hay nada publicado aquí."],"Nothing published yet.":["Todavía no hay nada publicado."],"November":["noviembre"],"Nowhere":["En ningún sitio"],"Number":["Número"],"October":["octubre"],"Older posts":["Entradas anteriores"],"One frame of this animation holds more than %(max)s pixels, which is more than Gophenberg opens. Upload a smaller animation.":["Un fotograma de esta animación tiene más de %(max)s píxeles, más de lo que Gophenberg abre. Sube una animación más pequeña."],"One of the filters on this list is not one Gophenberg understands. Clear the filters and try again.":["Uno de los filtros de esta lista no es un filtro que Gophenberg entienda. Quita los filtros e inténtalo de nuevo."],"One of the items picked for %(field)s is not the kind of content that field points at. Reload the page and pick from the list the field offers.":["Uno de los elementos elegidos para %(field)s no es del tipo de contenido al que apunta ese campo. Recarga la página y elige de la lista que ofrece el campo."],"One of the items picked for %(field)s was not named in a way Gophenberg understands. Reload the page and pick the items again.":["Uno de los elementos elegidos para %(field)s no venía nombrado de una forma que Gophenberg entienda. Recarga la página y vuelve a elegir los elementos."],"One of the items picked no longer exists. Reload the page and pick again.":["Uno de los elementos elegidos ya no existe. Recarga la página y vuelve a elegir."],"One target":["Un destino"],"Only a relation field points at another content type or holds many items. Pick the Relation kind, or leave the target and the many option empty.":["Solo un campo de relación apunta a otro tipo de contenido o guarda varios elementos. Elige el tipo Relación, o deja vacío el destino y la opción de varios."],"Only one file may be placed here.":["Aquí solo se puede colocar un archivo."],"Only the content type at the root of your site may go without a route word. Give this type one and try again.":["Solo el tipo de contenido que está en la raíz de tu sitio puede ir sin palabra de ruta de URL. Dale una a este tipo e inténtalo de nuevo."],"Open %(field)s in a new tab":["Abrir %(field)s en una pestaña nueva"],"Order stored.":["Orden guardado."],"Other":["Otro"],"Out of list":["Fuera de la lista"],"Parent":["Elemento superior"],"Password":["Contraseña"],"Pending":["Pendiente"],"Pending Review":["Pendiente de revisión"],"Permanently delete…":["Eliminar permanentemente…"],"Picture quality":["Calidad de imagen"],"Picture quality runs from 1 to %(max)s, so %(value)s is not a quality Gophenberg stores at. Pick a number inside that range.":["La calidad de imagen va de 1 a %(max)s, así que %(value)s no es una calidad con la que Gophenberg guarde. Elige un número dentro de ese rango."],"Placeholder":["Texto de ejemplo"],"Plural name":["Nombre en plural"],"Points at":["Apunta a"],"Post published.":["Entrada publicada."],"Posts per page":["Entradas por página"],"Preview":["Vista previa"],"Private":["Privada"],"Publish":["Publicar"],"Published: %s":["Publicado: %s"],"Radio group":["Grupo de botones de radio"],"Reads from":["Lee de"],"Redo":["Rehacer"],"Relation":["Relación"],"Remove":["Quitar"],"Remove %(name)s":["Quitar %(name)s"],"Remove %(title)s":["Quitar %(title)s"],"Remove row":["Quitar fila"],"Rename":["Renombrar"],"Rename %(field)s":["Renombrar %(field)s"],"Rename…":["Renombrar…"],"Require":["Hacer obligatorio"],"Require %(field)s":["Hacer %(field)s obligatorio"],"Required":["Obligatorio"],"Restore":["Restaurar"],"Role changed.":["Rol cambiado."],"Roll back to %(theme)s":["Revertir a %(theme)s"],"Roll back to the built-in renderer":["Revertir al renderizador integrado"],"Route word":["Palabra de ruta"],"Rule %(number)s of set %(set)s":["Regla %(number)s del conjunto %(set)s"],"Rule set %(number)s":["Conjunto de reglas %(number)s"],"Rules":["Reglas"],"Rules showing %(field)s":["Reglas que muestran %(field)s"],"Save":["Guardar"],"Save draft":["Guardar el borrador"],"Save rules":["Guardar las reglas"],"Save settings":["Guardar los ajustes"],"Saved":["Guardado"],"Saving":["Guardando"],"Scheduled":["Programada"],"Scheduled: %s":["Programado: %s"],"Search %(type)s…":["Buscar %(type)s…"],"Search audio":["Buscar audios"],"Search images":["Buscar imágenes"],"Search media":["Buscar medios"],"Search videos":["Buscar vídeos"],"Select":["Seleccionar"],"September":["septiembre"],"Serving":["Atendiendo"],"Settings":["Ajustes"],"Settings of %(field)s":["Ajustes de %(field)s"],"Shadowed":["Eclipsado"],"Show %(field)s in the list":["Mostrar %(field)s en la lista"],"Showing %(held)s of %(total)s.":["Mostrando %(held)s de %(total)s."],"Singular name":["Nombre en singular"],"Slug":["Slug"],"Somebody must be able to manage users.":["Alguien tiene que poder gestionar los usuarios."],"Someone else changed this media item while you were editing it. Reload the page and make your change again.":["Otra persona ha cambiado este medio mientras lo editabas. Recarga la página y vuelve a hacer tu cambio."],"Someone else saved changes to this item while you were editing, so yours were not saved. Copy your text somewhere safe, then reload the item and put your changes back in.":["Otra persona ha guardado cambios en este elemento mientras editabas, así que los tuyos no se han guardado. Copia tu texto a un lugar seguro, recarga el elemento y vuelve a colocarlos de vuelta."],"Something went wrong inside Gophenberg. Try again in a moment, and tell whoever looks after your site if it keeps happening.":["Algo ha fallado dentro de Gophenberg. Inténtalo de nuevo en un momento, y avisa a quien gestione tu sitio si sigue pasando."],"Something went wrong.":["Algo ha ido mal."],"Something went wrong. Try again.":["Algo ha ido mal. Inténtalo de nuevo."],"Sorry, you are not allowed to access this page.":["Lo siento, no tienes permisos para acceder a esta página."],"Source":["Origen"],"Steps of":["Pasos de"],"Stop nesting":["Dejar de anidar"],"Tablet":["Tableta"],"Text":["Texto"],"Text area":["Área de texto"],"That email is already in use.":["Ese correo electrónico ya está en uso."],"That field group no longer exists. Reload the page to see the groups your site holds now.":["Ese grupo de campos ya no existe. Recarga la página para ver los grupos que tiene ahora tu sitio."],"That field is not on this content type any more. Reload the page to see the fields it has now.":["Ese campo ya no está en este tipo de contenido. Recarga la página para ver los campos que tiene ahora."],"That revision does not exist, and older ones drop off once a type holds more than it keeps. Open the item to see which revisions are left.":["Esa revisión no existe, y las más antiguas se pierden cuando un tipo guarda más de las que conserva. Abre el elemento para ver qué revisiones quedan."],"That role holds more than your own.":["Ese rol abarca más que el tuyo."],"That web address does not name a media item Gophenberg can look up. Open the media library and pick the item from there.":["Esa dirección web no nombra ningún medio que Gophenberg pueda encontrar. Abre la biblioteca de medios y elige el elemento desde ahí."],"That web address does not name a revision Gophenberg can look up. Open the item and pick a revision from its history.":["Esa dirección web no alude a ninguna revisión que Gophenberg pueda identificar. Abre el elemento y elige una revisión de su historial."],"That web address does not name an item Gophenberg can look up. Go back to the list and open the item from there.":["Esa dirección web no alude a ningún elemento que Gophenberg pueda identificar. Vuelve a la lista y abre el elemento desde ahí."],"The %(count)s item in the trash is deleted for good. This cannot be undone.":["%(count)s elemento de la papelera se borrará permanentemente. Esto no se puede deshacer.","%(count)s de elementos de la papelera se borrarán permanentemente. Esto no se puede deshacer.","Los %(count)s elementos de la papelera se borrarán permanentemente. Esto no se puede deshacer."],"The %(file)s calls this theme %(declared)s, but it is being installed as %(installed)s. Rename the zip file to match, or change the name inside %(file)s.":["El archivo %(file)s llama a este tema %(declared)s, pero se está instalando como %(installed)s. Renombra el zip para que coincida, o cambia el nombre dentro de %(file)s."],"The %(file)s inside %(name)s is not valid JSON, so it could not be read. Fix that file and package the theme again.":["El archivo %(file)s dentro de %(name)s no es JSON válido, así que no se ha podido leer. Corrige ese archivo y vuelve a empaquetar el tema."],"The %(file)s inside %(name)s names its theme kit as %(declared)s, which is not a version number. Build the theme again, and the build will fill that in.":["El %(file)s dentro de %(name)s identifica su kit de temas como %(declared)s, que no srive como número de versión. Compila el tema de nuevo y la compilación lo rellenará."],"The %(origin)s plugin declared this, so it can only be changed in that plugin. Turning it off is still yours to do.":["El plugin %(origin)s lo declaró, así que solo se puede cambiar en ese plugin. Desactivarlo sigue estando en tu mano."],"The %(plugin)s plugin also declares %(name)s, and the site keeps the key.":["El plugin %(plugin)s también declara %(name)s, y el sitio se queda con la clave."],"The %(plugin)s plugin declared these fields, so they change only in its code.":["El plugin %(plugin)s declaró estos campos, así que solo cambian en su código."],"The %(plugin)s plugin declares %(name)s flat, and the site keeps it nesting while its items sit inside another.":["El plugin %(plugin)s declara %(name)s sin anidar, y el sitio lo mantiene anidando mientras sus elementos están dentro de otro."],"The browser kept an unsaved version of this post.":["El navegador ha guardado una versión sin guardar de esta entrada."],"The built-in renderer is now serving the public site.":["El renderizador integrado ya presta servicio al sitio público."],"The built-in renderer is serving the public site.":["El renderizador integrado presta servicio al sitio público."],"The content type this field points at is not named in a shape Gophenberg accepts. Give it a key that starts with a lowercase letter and then holds only lowercase letters, numbers and hyphens.":["El tipo de contenido al que apunta este campo no está nombrado con un formato que Gophenberg acepte. Dale una clave que empiece por una letra minúscula y contenga solo letras minúsculas, números y guiones."],"The content types could not be loaded, so where these groups appear and which fields they shadow are not shown.":["No se han podido cargar los tipos de contenido, así que no se muestra dónde aparecen estos grupos ni qué campos eclipsan."],"The content types could not be loaded.":["No se han podido cargar los tipos de contenido."],"The content types could not be refreshed, so where these groups appear and what they shadow may be out of date.":["No se han podido actualizar los tipos de contenido, así que dónde aparecen estos grupos y qué eclipsan puede estar desactualizado."],"The draft could not be created.":["No se ha podido crear el borrador."],"The entry %(entry)s in this zip would be written outside the theme folder, so nothing was installed. Package the theme again.":["La entrada %(entry)s de este zip se escribiría fuera de la carpeta del tema, así que no se ha instalado nada. Vuelve a empaquetar el tema."],"The field %(field)s cannot go, because %(by)s reads it. Change %(by)s first.":["El campo %(field)s no se puede quitar, porque %(by)s lo lee. Cambia antes %(by)s."],"The field %(field)s cannot hold the value it was given. Check what kind of field it is and enter a value that matches.":["El campo %(field)s no puede guardar el valor que se le ha dado. Comprueba de qué tipo de campo se trata e introduce un valor que encaje."],"The field %(field)s has to hold a value before this item can be published. Fill it in, or leave the item as a draft.":["El campo %(field)s tiene que tener un valor antes de poder publicar este elemento. Rellénalo, o deja el elemento como borrador."],"The field %(field)s in %(group)s still points at this content type. Delete that field first, then delete this type.":["El campo %(field)s de %(group)s todavía apunta a este tipo de contenido. Borra antes ese campo y luego borra este tipo."],"The field %(field)s is hidden by its own rules right now, so it cannot hold a value. Show it again before filling it in.":["El campo %(field)s está oculto por sus propias reglas ahora mismo, así que no puede guardar ningún valor. Vuelve a mostrarlo antes de rellenarlo."],"The field %(field)s points at one item only. Remove the extra choices and keep one.":["El campo %(field)s apunta a un solo elemento. Quita las opciones de más y deja una."],"The field %(field)s points at other items, so it does not take a plain value. Pick the items it points at instead.":["El campo %(field)s apunta a otros elementos, así que no admite un valor suelto. Elige en su lugar los elementos a los que apunta."],"The field %(field)s takes a list of items, and what arrived was not a list. Reload the page and pick the items again.":["El campo %(field)s admite una lista de elementos, y lo que ha llegado no era una lista. Recarga la página y vuelve a elegir los elementos."],"The field %(source)s cannot hold the value %(value)s, so no rule can compare it. Write a value of the kind %(source)s stores.":["El campo %(source)s no puede guardar el valor %(value)s, así que ninguna regla puede compararlo. Escribe un valor de la clase que %(source)s guarda."],"The field groups could not be loaded.":["No se han podido cargar los grupos de campos."],"The field groups could not be reached.":["No se ha podido contactar con los grupos de campos."],"The field keeps its values on the content both groups reach.":["El campo conserva sus valores en el contenido al que llegan ambos grupos."],"The fields this group holds go with it, and so do the values every item stored in them.":["Los campos que contiene este grupo se van con él, y también los valores que cada elemento guardó en ellos."],"The groups were reordered.":["Los grupos se han reordenado."],"The item could not be duplicated.":["No se ha podido duplicar el elemento."],"The item could not be moved to the trash.":["No se ha podido mover el elemento a la papelera."],"The item could not be permanently deleted.":["No se ha podido borrar permanentemente el elemento."],"The item could not be restored.":["No se ha podido restaurar el elemento."],"The item you picked as parent holds another kind of content. Pick a parent of the same content type as this item.":["El elemento que has elegido como superior tiene otro tipo de contenido. Elige un elemento superior del mismo tipo de contenido que este elemento."],"The item you picked as parent is in the trash. Restore it, or pick another parent.":["El elemento que has elegido como superior está en la papelera. Restáuralo, o elige otro elemento superior."],"The item you picked as parent no longer exists. Reload the page and pick another parent.":["El elemento que has elegido como superior ya no existe. Recarga la página y elige otro."],"The media library could not be loaded.":["No se ha podido cargar la biblioteca de medios."],"The name changes. Nothing stored under this field moves.":["El nombre cambia. Nada de lo guardado en este campo se mueve."],"The name could not be updated.":["No se ha podido actualizar el nombre."],"The new order has to name every field group exactly once. Reload the page and move the groups again.":["El nuevo orden tiene que nombrar cada grupo de campos exactamente una vez. Recarga la página y mueve los grupos otra vez."],"The new order has to name every field of this content type exactly once. Reload the page and move the fields again.":["El nuevo orden tiene que nombrar cada campo de este tipo de contenido exactamente una vez. Recarga la página y mueve los campos de nuevo."],"The number of revisions to keep has to be a whole number, and it cannot be negative. Enter a different number.":["El número de revisiones que se conservan tiene que ser un número entero, y no puede ser negativo. Introduce otro número."],"The registry could not be reached.":["No se ha podido acceder al registro."],"The role could not be changed.":["No se ha podido cambiar el rol."],"The rule on %(source)s names nothing to match. Pick a value, or remove the rule.":["La regla sobre %(source)s no nombra nada con lo que coincidir. Elige un valor, o quita la regla."],"The rules could not be loaded.":["No se han podido cargar las reglas."],"The rules on %(field)s lead back to %(field)s itself, so nothing can decide whether to show it. Point one of them at another field.":["Las reglas de %(field)s vuelven al propio %(field)s, así que nada puede decidir si mostrarlo. Apunta una de ellas a otro campo."],"The same item was picked twice for %(field)s. Pick each item once.":["El mismo elemento se ha elegido dos veces para %(field)s. Elige cada elemento una sola vez."],"The server could not be reached, so nothing was changed.":["No se ha podido acceder al servidor, así que no se ha cambiado nada."],"The server could not be reached, so nothing was saved.":["No se ha podido acceder al servidor, así que no se ha guardado nada."],"The server could not be reached, so nothing was uploaded.":["No se ha podido acceder al servidor, así que no se ha subido nada."],"The setting %(setting)s cannot hold the value it was given. Check what this setting takes and try again.":["El ajuste %(setting)s no puede contener el valor que se le dio. Comprueba qué acepta este ajuste y prueba de nuevo."],"The setting %(setting)s falls outside the others. Keep min below max and the default inside the bounds.":["El ajuste %(setting)s queda fuera de los demás. Mantén min por debajo de max y el valor por defecto dentro de los límites."],"The settings could not be read, so nothing can be changed here yet.":["No se han podido leer los ajustes, así que todavía no se puede cambiar nada aquí."],"The site default":["El idioma por defecto del sitio"],"The site may already hold part of this file. Import it again to see what is left.":["Puede que el sitio ya tenga parte de este archivo. Impórtalo de nuevo para ver lo que queda."],"The source %(source)s does not offer %(operator)s. Pick one of the comparisons it does offer.":["La fuente %(source)s no ofrece %(operator)s. Elige una de las comparaciones que sí ofrece."],"The theme %(name)s carries no %(file)s, so Gophenberg cannot tell what it is. Put that file at the top level of the zip and package the theme again.":["El tema %(name)s no lleva ningún %(file)s, así que Gophenberg no puede saber qué es. Pon ese archivo en el primer nivel del zip y vuelve a empaquetar el tema."],"The theme %(name)s could not be read, so it cannot serve your site. Upload it again, or choose another theme.":["El tema %(name)s no se ha podido leer, así que no puede servir tu sitio. Vuelve a subirlo, o elige otro tema."],"The theme %(name)s did not start, so your site is still served by the theme it had. Ask whoever looks after your site to check the server log for what the theme reported.":["El tema %(name)s no ha arrancado, así que tu sitio lo sigue sirviendo el tema que tenía. Pide a quien gestiona tu sitio que mire en el registro del servidor para saber qué problema ha informado el tema."],"The theme %(name)s does not carry %(path)s as a file, so there is nothing to run. Package the built theme rather than its source.":["El tema %(name)s no lleva %(path)s como archivo, así que no hay nada que ejecutar. Empaqueta el tema ya construido, no su código fuente."],"The theme %(name)s does not carry %(path)s as a folder, so its styles and scripts are missing. Package the built theme rather than its source.":["El tema %(name)s no lleva %(path)s como carpeta, así que le faltan los estilos y los scripts. Empaqueta el tema ya construido, no su código fuente."],"The theme %(name)s holds a link to another file at %(path)s, and a theme may only carry real files. Replace it and package the theme again.":["El tema %(name)s lleva un enlace a otro archivo en %(path)s, y un tema solo puede llevar archivos de verdad. Sustitúyelo y vuelve a empaquetar el tema."],"The theme %(name)s is serving your site right now, so it cannot be replaced. Deactivate it first, or install this copy under another name.":["El tema %(name)s sirve tu sitio ahora mismo, así que no se puede sustituir. Desactívalo primero, o instala esta copia con otro nombre."],"The theme %(name)s is the one chosen, but it is not installed, so your site is served by the built-in renderer. Upload the theme again, or choose another one.":["El tema %(name)s es el elegido, pero no está instalado, así que el renderizador integrado está prestando servicio a tu sitio. Vuelve a subir el tema, o elige otro."],"The theme %(name)s was built on theme kit %(declared)s, and this site serves %(served)s. Build the theme again against a kit this site serves, then install it.":["El tema %(name)s se compiló con el kit de temas %(declared)s y este sitio sirve %(served)s. Compila el tema de nuevo con un kit que este sitio sirva y después instálalo."],"The trash could not be emptied.":["No se ha podido vaciar la papelera."],"The user could not be created.":["No se ha podido crear el usuario."],"The values stored under it do not follow.":["Los valores guardados debajo no le siguen."],"Theme":["Tema"],"Themes":["Temas"],"Themes could not be loaded.":["No se han podido cargar los temas."],"There is no content type called %(value)s. Pick a type your site holds, or register it first.":["No existe ningún tipo de contenido llamado %(value)s. Elige un tipo que tenga tu sitio, o regístralo primero."],"There is no content type called %(value)s. Pick one of the types your site holds and try again.":["No existe ningún tipo de contenido llamado %(value)s. Elige uno de los tipos que tiene tu sitio e inténtalo de nuevo."],"There is no kind of field called %(value)s. Pick one of these instead: %(allowed)s.":["No existe ningún tipo de campo llamado %(value)s. Elige uno de estos: %(allowed)s."],"There is no page kind called %(value)s. Pick one of these instead: %(allowed)s.":["No existe ningún tipo de página llamado %(value)s. Elige uno de estos: %(allowed)s."],"There is no status called %(value)s. Pick one of these instead: %(allowed)s.":["No existe ningún estado llamado %(value)s. Elige uno de estos: %(allowed)s."],"There is nothing at this address. Check the link and try again.":["No hay nada en esta dirección. Comprueba el enlace e inténtalo de nuevo."],"There is nothing to roll back to, because your site has not been through a theme change yet. Install a theme first, then a rollback has somewhere to go.":["No hay nada a lo que retornar, porque tu sitio todavía no ha cambiado de tema. Instala un tema primero y así el retorno tendrá adónde ir."],"These files could not be read.":["No se han podido leer estos archivos."],"These were left alone, because nobody confirmed losing them.":["Estos se han dejado como estaban, porque nadie confirmó perderlos."],"This content type does not exist any more. Reload the page to see the types your site holds now.":["Este tipo de contenido ya no existe. Recarga la página para ver los tipos que tiene ahora tu sitio."],"This content type does not nest, so one of its items cannot sit inside another. Mark the type as Nests first.":["Este tipo de contenido no anida, así que uno de sus elementos no puede estar dentro de otro. Marca el tipo como Anida primero."],"This content type has no field called %(field)s. Check the name, or declare the field on the type first.":["Este tipo de contenido no tiene ningún campo llamado %(field)s. Comprueba el nombre, o declara antes el campo en el tipo."],"This content type is turned off, so its content is not served or edited. Activate it first.":["Este tipo de contenido está desactivado, así que su contenido ni se sirve ni se edita. Actívalo primero."],"This content type still holds content, so it cannot be deleted. Move or delete its items first.":["Este tipo de contenido todavía tiene contenido, así que no se puede borrar. Mueve o borra antes sus elementos."],"This definitions file is larger than the %(max)s bytes Gophenberg reads in one request. Split it, or raise the limit your site runs with.":["Este archivo de definiciones es mayor que los %(max)s bytes que Gophenberg lee en una petición. Divídelo, o sube el límite con el que funciona tu sitio."],"This field holds no layouts yet.":["Este campo todavía no tiene diseños."],"This field would stand inside too many containers. Put it nearer the top and try again.":["Este campo quedaría dentro de demasiados contenedores. Ponlo más cerca del nivel superior e inténtalo de nuevo."],"This file could not be opened as a zip. Package the theme again and upload the new file.":["Este archivo no se ha podido abrir como zip. Vuelve a empaquetar el tema y sube el archivo nuevo."],"This file is larger than the upload limit. Upload a smaller file.":["Este archivo es más grande que el límite de subida. Sube un archivo más pequeño."],"This file is named %(extension)s but it holds %(detected)s content. Upload it under a name that matches what is inside it.":["Este archivo se llama %(extension)s pero lleva contenido %(detected)s. Súbelo con un nombre que coincida con lo que lleva dentro."],"This file matches the site, so there is nothing to change.":["Este archivo coincide con el sitio, así que no hay nada que cambiar."],"This file says it was written in format %(declared)s, which is not a version Gophenberg can read. Export the definitions again from the site they came from.":["Este archivo dice estar escrito en el formato %(declared)s, que no es una versión que Gophenberg pueda leer. Vuelve a exportar las definiciones desde el sitio del que vinieron."],"This file was written in format %(declared)s, and this release reads %(served)s. Upgrade the site the file came from, or this one.":["Este archivo está escrito en el formato %(declared)s, y esta versión lee %(served)s. Actualiza el sitio del que viene el archivo, o este."],"This group holds no fields yet.":["Este grupo todavía no tiene campos."],"This install of Gophenberg has no install root, so it updates by hand.":["Esta instalación de Gophenberg no tiene raíz de instalación, así que se actualiza a mano."],"This is a custom build of Gophenberg, so it updates by hand.":["Esta es una compilación propia de Gophenberg, así que se actualiza a mano."],"This item cannot go straight to that status from the one it holds now. Save it as a draft first, then try again.":["Este elemento no puede pasar directamente a ese estado desde el que tiene ahora. Guárdalo antes como borrador e inténtalo de nuevo."],"This item does not exist, and it may have been deleted. Go back to the list to see what is there.":["Este elemento no existe, y puede que se haya borrado. Vuelve a la lista para ver qué hay."],"This item is already in the trash. Restore it first to work on it again.":["Este elemento ya está en la papelera. Restáuralo primero para volver a trabajar en él."],"This item is in the trash. Restore it first to work on it again.":["Este elemento está en la papelera. Restáuralo primero para volver a trabajar en él."],"This item is not in the trash, so there is nothing to restore. Open it from the list to work on it as it is.":["Este elemento no está en la papelera, así que no hay nada que restaurar. Ábrelo desde la lista para trabajar en él tal como está."],"This item still holds items nested inside it. Move or delete those first.":["Este elemento todavía tiene elementos anidados dentro. Mueve o borra antes esos."],"This kind of field holds no fields inside it. Put the field in a section or a repeater instead.":["Este tipo de campo no contiene campos dentro. Pon el campo en una sección o en un repetidor."],"This media item is not in the library, and someone may have deleted it. Reload the page to see what is there now.":["Este medio no está en la biblioteca, y puede que alguien lo haya borrado. Recarga la página para ver qué hay ahora."],"This picture could not be read, so nothing was stored. The file may be damaged, so open it on your computer and upload it again.":["Esta imagen no se ha podido leer, así que no se ha guardado nada. Puede que el archivo esté dañado, así que ábrelo en tu ordenador y vuelve a subirlo."],"This picture is %(width)s by %(height)s pixels, over the limit of %(max)s pixels in all. Make it smaller and upload it again.":["Esta imagen tiene %(width)s por %(height)s píxeles, por encima del límite de %(max)s píxeles en total. Hazla más pequeña y vuelve a subirla."],"This post changed elsewhere. Reload before saving again.":["Esta entrada ha cambiado en otro sitio. Recarga antes de volver a guardar."],"This request came from a page on another site, so it was refused. Open the admin on this site and try again.":["Esta petición vino de una página de otro sitio, así que se rechazó. Abre la administración en este sitio e inténtalo de nuevo."],"This request carried %(attribute)s, which fields do not take. Reload the page so the admin and the server agree again.":["Esta petición llevaba %(attribute)s, que los campos no aceptan. Recarga la página para que la administración y el servidor vuelvan a coincidir."],"This request left out %(field)s, which Gophenberg needs. Reload the page and try again.":["En esta petición faltaba %(field)s, que Gophenberg necesita. Recarga la página e inténtalo de nuevo."],"This rule reads a source called %(source)s, and nothing on your site declares one. A plugin that added it may have been removed.":["Esta regla lee una fuente llamada %(source)s, y nada en tu sitio declara ninguna. Puede que se haya quitado un plugin que la añadía."],"This site cannot write to its themes folder, so no theme can be installed. Ask whoever looks after your site to make the folder that %(setting)s points at writable. A read-only mount is the usual cause.":["Este sitio no puede escribir en su carpeta de temas, así que no se puede instalar ninguno. Pide a quien gestione tu sitio que haga escribible la carpeta a la que apunta %(setting)s. La causa habitual es un montaje de solo lectura."],"This site has nowhere to keep themes, so no theme can be installed. Ask whoever looks after your site to point %(setting)s at a folder the server can write to.":["Este sitio no tiene dónde guardar los temas, así que no se puede instalar ninguno. Pide a quien gestione tu sitio que apunte %(setting)s a una carpeta en la que el servidor pueda escribir."],"This site has nowhere to store uploads, so nothing can be uploaded. Ask whoever looks after your site to point %(setting)s at a folder the server can write to.":["Este sitio no tiene dónde guardar las subidas, así que no se puede subir nada. Pide a quien gestione tu sitio que apunte %(setting)s a una carpeta en la que el servidor pueda escribir."],"This theme is over the limit of %(max)s bytes, packed or unpacked. Leave out what the theme does not need and package it again.":["Este tema pasa del límite de %(max)s bytes, comprimido o sin comprimir. Saca lo que el tema no necesite y vuelve a empaquetarlo."],"This type will answer under /%(word)s.":["Este tipo responderá como /%(word)s."],"This zip holds %(entries)s files, more than the %(max)s a theme may carry. Package only the built theme.":["Este zip lleva %(entries)s archivos, más de los %(max)s que puede llevar un tema. Empaqueta solo el tema ya construido."],"Through":["A través de"],"Thumbnail":["Miniatura"],"Title":["Título"],"Two field groups in this file share the key %(key)s. Give one of them a different key and import again.":["Dos grupos de campos de este archivo comparten la clave %(key)s. Dale una clave distinta a uno de ellos e importa de nuevo."],"Two rule sources are registered under the name %(param)s. A plugin is declaring a source your site already holds.":["Hay dos fuentes de reglas registradas con el nombre %(param)s. Un plugin declara una fuente que tu sitio ya tiene."],"Type":["Tipo"],"Type a whole number in both boxes before saving.":["Escribe un número entero en las dos casillas antes de guardar."],"Undo":["Deshacer"],"Unsaved changes":["Cambios sin guardar"],"Update":["Actualizar"],"Update failed.":["No se ha podido actualizar."],"Upload theme":["Subir tema"],"Uploaded %s file.":["%s archivo subido.","%s de archivos subidos.","%s archivos subidos."],"Users":["Usuarios"],"Users could not be loaded.":["No se han podido cargar los usuarios."],"Value":["Valor"],"Version":["Versión"],"Videos":["Vídeos"],"Visit Site":["Visitar el sitio"],"Web address":["Dirección web"],"What each Linked from field reads":["Qué lee cada campo Enlazado desde"],"What it points at changed, so its stored values go with it.":["Aquello a lo que apunta ha cambiado, así que sus valores guardados se van con él."],"Where %(group)s appears":["Dónde aparece %(group)s"],"Without a rule this field always shows.":["Sin ninguna regla este campo siempre se muestra."],"Without a rule this group appears nowhere.":["Sin una regla este grupo no aparece en ningún sitio."],"Yes":["Sí"],"Yes or no":["Sí o no"],"You cannot change your own role.":["No puedes cambiar tu propio rol."],"Your language":["Tu idioma"],"Your role does not allow %(capability)s.":["Tu rol no permite %(capability)s."],"Your server pins the site to the theme %(name)s, so themes cannot be changed here. Ask whoever looks after your site to remove the pin.":["Tu servidor bloque el sitio al tema %(name)s, así que los temas no se pueden cambiar desde aquí. Pide a quien gestiona tu sitio que quite ese bloqueo."],"Your site always needs one default content type, so this one cannot be turned off or deleted. Make another type the default first.":["Tu sitio siempre necesita un tipo de contenido por defecto, así que este no se puede desactivar ni borrar. Haz antes que otro tipo sea el que está por defecto."],"a content type":["un tipo de contenido"],"account\u0004Role":["Rol"],"account\u0004Status":["Estado"],"action label\u0004Duplicate":["Duplicar"],"action label\u0004Duplicate…":["Duplicar…"],"address":["dirección"],"admin section\u0004Content Types":["Tipos de contenido"],"admin section\u0004Field Groups":["Grupos de campos"],"admin section\u0004Language":["Idioma"],"admin section\u0004Media":["Medios"],"admin section\u0004Settings":["Ajustes"],"admin section\u0004Themes":["Temas"],"column\u0004Date":["Fecha"],"content type\u0004\"%s\" permanently deleted.":["Se ha borrado permanentemente el tipo de contenido «%s»."],"content type\u0004\"%s\" successfully created.":["Se ha creado correctamente el tipo de contenido «%s»."],"content type\u0004Status":["Estado"],"field\u0004Name":["Nombre"],"field group\u0004Status":["Estado"],"field type\u0004Choice":["Elección"],"field type\u0004Color":["Color"],"field type\u0004Date":["Fecha"],"field type\u0004Flexible content":["Contenido flexible"],"field type\u0004Gallery":["Galería"],"field type\u0004Kind":["Tipo"],"field type\u0004Layout":["Diseño"],"field type\u0004Link":["Enlace"],"field type\u0004Media":["Medio"],"field type\u0004Range":["Rango"],"field type\u0004Repeater":["Repetidor"],"field type\u0004Section":["Sección"],"field type\u0004Select":["Desplegable"],"file size\u0004%1$s %2$s":["%1$s %2$s"],"file type group\u0004Archives":["Archivos"],"file type group\u0004Audio":["Audio"],"file type group\u0004Video":["Vídeo"],"holds":["contiene"],"holds anything":["contiene algo"],"https://www.w3.org/WAI/tutorials/images/decision-tree/":["https://www.w3.org/WAI/tutorials/images/decision-tree/"],"image dimensions\u0004%1$s × %2$s":["%1$s × %2$s"],"is":["es"],"is above":["es mayor que"],"is below":["es menor que"],"is empty":["está vacío"],"is not":["no es"],"panel button label\u0004Settings":["Ajustes"],"person\u0004Name":["Nombre"],"post\u0004%s (Copy)":["%s (copia)"],"post\u0004Status":["Estado"],"post status\u0004Draft":["Borrador"],"post status\u0004Published":["Publicada"],"post status\u0004Trash":["Papelera"],"post type general name\u0004Pages":["Páginas"],"post type general name\u0004Posts":["Entradas"],"post type singular name\u0004Page":["Página"],"post type singular name\u0004Post":["Entrada"],"relation target\u0004None":["Ninguno"],"role\u0004Administrator":["Administrador"],"role\u0004Author":["Autor"],"role\u0004Editor":["Editor"],"role\u0004Member":["Miembro"],"role\u0004No role":["Sin rol"],"status filter\u0004All":["Todo"],"taxonomy general name\u0004Categories":["Categorías"],"taxonomy singular name\u0004Category":["Categoría"],"theme\u0004Status":["Estado"],"trash\u0004Restore":["Restaurar"],"unit symbol\u0004B":["B"],"unit symbol\u0004EB":["EB"],"unit symbol\u0004GB":["GB"],"unit symbol\u0004KB":["KB"],"unit symbol\u0004MB":["MB"],"unit symbol\u0004PB":["PB"],"unit symbol\u0004TB":["TB"],"unit symbol\u0004YB":["YB"],"unit symbol\u0004ZB":["ZB"],"v%(version)s":["v%(version)s"],"verb\u0004Trash…":["Papelera…"],"verb\u0004View":["Ver"],"{day} {month} {year}":["{day} de {month} de {year}"]} +{"":{"lang":"es","plural-forms":"nplurals=3; plural=((n == 1) ? 0 : ((n != 0 && n % 1000000 == 0) ? 1 : 2));"}," and ":[" y "]," or ":[" o "],"\"%s\" activated.":["Se ha activado «%s»."],"\"%s\" deactivated.":["Se ha desactivado «%s»."],"\"%s\" has been restored.":["«%s» se ha restaurado."],"\"%s\" moved to the trash.":["«%s» trasladado a la papelera."],"\"%s\" permanently deleted.":["«%s» borrado permanentemente."],"\"%s\" successfully created.":["«%s» creado correctamente."],"\"%s\" uploaded.":["«%s» subido."],"%(field)s address":["Dirección de %(field)s"],"%(field)s cannot move inside itself. Pick a container that is not one of its own.":["%(field)s no puede moverse dentro de sí mismo. Elige un contenedor que no sea uno de los suyos."],"%(field)s declared.":["%(field)s declarado."],"%(field)s deleted.":["%(field)s borrado."],"%(field)s does not match the format its field asks for. Check it and save again.":["%(field)s no tiene el formato que su campo requiere. Revísalo y guarda de nuevo."],"%(field)s goes no higher than %(limit)s. Lower the value and save again.":["%(field)s no pasa de %(limit)s. Baja el valor y guarda de nuevo."],"%(field)s goes no lower than %(limit)s. Raise the value and save again.":["%(field)s no baja de %(limit)s. Sube el valor y guarda de nuevo."],"%(field)s holds no value of its own, so it cannot be required. Make it optional.":["%(field)s no guarda ningún valor propio, así que no puede ser obligatorio. Hazlo opcional."],"%(field)s is optional again.":["%(field)s vuelve a ser opcional."],"%(field)s is required now.":["%(field)s ahora es obligatorio."],"%(field)s moved.":["%(field)s movido."],"%(field)s names the same one twice. Remove the repeat and save again.":["%(field)s nombra el mismo dos veces. Quita la repetición y guarda de nuevo."],"%(field)s needs at least %(limit)s files. Add one and save again.":["%(field)s necesita al menos %(limit)s archivos. Añade uno y guarda de nuevo."],"%(field)s needs at least %(limit)s rows. Add one and save again.":["%(field)s necesita al menos %(limit)s filas. Añade una y guarda de nuevo."],"%(field)s only takes one of its listed choices. Pick one and save again.":["%(field)s solo admite una de las opciones de su lista. Elige una y guarda de nuevo."],"%(field)s reads a relation field that is not there. Pick a group and a relation field it holds.":["%(field)s lee un campo de relación que no existe. Elige un grupo y un campo de relación que contenga."],"%(field)s reads a relation pointing at %(type)s, so it would list nothing here. Pick a relation pointing at the items this group is shown on.":["%(field)s lee una relación que apunta a %(type)s, así que aquí no mostraría nada. Elige una relación que apunte a los elementos donde se muestra este grupo."],"%(field)s renamed.":["%(field)s renombrado."],"%(field)s settled.":["%(field)s ajustado."],"%(field)s shows by its rules now.":["%(field)s ahora se muestra según sus reglas."],"%(field)s stands in the list.":["%(field)s aparece en la lista."],"%(field)s stays out of the list.":["%(field)s se queda fuera de la lista."],"%(field)s takes at most %(limit)s files. Remove one and save again.":["%(field)s acepta como mucho %(limit)s archivos. Quita uno y guarda de nuevo."],"%(field)s takes at most %(limit)s letters. Shorten what you wrote and save again.":["%(field)s acepta como mucho %(limit)s letras. Acorta lo que has escrito y guarda de nuevo."],"%(field)s takes at most %(limit)s rows. Remove one and save again.":["%(field)s admite como mucho %(limit)s filas. Quita una y guarda de nuevo."],"%(field)s title":["Título de %(field)s"],"%(file)s is larger than one upload may be.":["%(file)s es más grande de lo que una subida permite."],"%(file)s is not a file this block accepts.":["%(file)s no es un archivo que este bloque acepte."],"%(file)s: %(reason)s":["%(file)s: %(reason)s"],"%(group)s created.":["%(group)s creado."],"%(group)s now appears where you said.":["%(group)s ya aparece donde has dicho."],"%(group)s removed.":["%(group)s eliminado."],"%(group)s updated.":["%(group)s actualizado."],"%(key)s is served by %(winner)s, so %(loser)s does not show it on %(where)s.":["%(key)s lo sirve %(winner)s, así que %(loser)s no lo muestra en %(where)s."],"%(name)s %(version)s is serving the public site.":["%(name)s %(version)s está publicado en la web."],"%(name)s belongs to the site now.":["%(name)s ya pertenece al sitio."],"%(name)s came from the %(plugin)s plugin, which no longer declares it.":["%(name)s vino del plugin %(plugin)s, que ya no lo declara."],"%(name)s cannot be used as a theme name. Name the zip file after the theme, with no dot at the start and no slashes in it.":["%(name)s no se puede usar como nombre de tema. Nombra el archivo zip como el tema, sin punto al principio y sin barras."],"%(name)s moves to /%(word)s. Every address of both types changes.":["El tipo %(name)s pasa a /%(word)s. Cambian todas las direcciones de ambos tipos."],"%(name)s would move to /%(word)s, which Gophenberg keeps for itself. Change its plural name and try again.":["El tipo %(name)s pasaría a /%(word)s, que Gophenberg reserva para sí mismo. Cambia su nombre en plural e inténtalo de nuevo."],"%(source)s is %(value)s":["%(source)s es %(value)s"],"%(theme)s failed to start, so the built-in renderer is serving.":["%(theme)s no pudo arrancar, así que el renderizador ha tomado el relevo."],"%(theme)s is now serving the public site.":["%(theme)s ya sirve el sitio público."],"%(theme)s is serving the public site.":["%(theme)s sirve el sitio público."],"%(theme)s is still starting, so the built-in renderer is serving.":["%(theme)s todavía está arrancando, así que el renderizador ha tomado el relevo."],"%(theme)s was installed.":["%(theme)s se ha instalado."],"%(theme)s will not load, so the built-in renderer is serving.":["%(theme)s no se carga, así que el renderizador ha tomado el relevo."],"%(type)s answers on a new address, and stored links move with it.":["%(type)s responde en una dirección nueva, y los enlaces guardados se mueven con ella."],"%(type)s becomes the type the site opens on, and the old one takes an address.":["%(type)s pasa a ser el tipo con el que abre el sitio, y el anterior toma una dirección."],"%(type)s keeps nesting while %(items)s of its items sit inside another. Move those to the top level first, the ones in the trash included.":["%(type)s sigue anidando mientras %(items)s de sus elementos están dentro de otro. Muévelos primero al nivel superior, incluidos los de la papelera."],"%(type)s keeps nesting, because some of its items sit inside another.":["%(type)s sigue anidando, porque algunos de sus elementos están dentro de otro."],"%(type)s will answer at the root.":["El tipo %(type)s responderá en la raíz."],"%s content type activated.":["Se ha activado %s tipo de contenido.","Se han activado %s de tipos de contenido.","Se han activado %s tipos de contenido."],"%s content type could not be activated.":["No se ha podido activar %s tipo de contenido.","No se han podido activar %s de tipos de contenido.","No se han podido activar %s tipos de contenido."],"%s content type could not be deactivated.":["No se ha podido desactivar %s tipo de contenido.","No se han podido desactivar %s de tipos de contenido.","No se han podido desactivar %s tipos de contenido."],"%s content type could not be permanently deleted.":["No se ha podido borrar permanentemente %s tipo de contenido.","No se han podido borrar permanentemente %s de tipos de contenido.","No se han podido borrar permanentemente %s tipos de contenido."],"%s content type deactivated.":["Se ha desactivado %s tipo de contenido.","Se han desactivado %s de tipos de contenido.","Se han desactivado %s tipos de contenido."],"%s content type permanently deleted.":["Se ha borrado permanentemente %s tipo de contenido.","Se han borrado permanentemente %s de tipos de contenido.","Se han borrado permanentemente %s tipos de contenido."],"%s day":["%s día","%s de días","%s días"],"%s hour":["%s hora","%s de horas","%s horas"],"%s item could not be moved to the trash.":["No se ha podido mover %s elemento a la papelera.","No se han podido mover %s de elementos a la papelera.","No se han podido mover %s elementos a la papelera."],"%s item could not be permanently deleted.":["No se ha podido borrar permanentemente %s elemento.","No se han podido borrar permanentemente %s de elementos.","No se han podido borrar permanentemente %s elementos."],"%s item could not be restored.":["No se ha podido restaurar %s elemento.","No se han podido restaurar %s de elementos.","No se han podido restaurar %s elementos."],"%s item moved to the trash.":["%s elemento movido a la papelera.","%s de elementos movidos a la papelera.","%s elementos movidos a la papelera."],"%s item permanently deleted.":["%s elemento borrado permanentemente.","%s de elementos borrados permanentemente.","%s elementos borrados permanentemente."],"%s item stays in the trash.":["%s elemento sigue en la papelera.","%s de elementos siguen en la papelera.","%s elementos siguen en la papelera."],"%s minute":["%s minuto","%s de minutos","%s minutos"],"%s page has been restored.":["Se ha restaurado %s página.","Se han restaurado %s de páginas.","Se han restaurado %s páginas."],"%s post has been restored.":["Se ha restaurado %s entrada.","Se han restaurado %s de entradas.","Se han restaurado %s entradas."],"%s update available":["%s actualización disponible","%s de actualizaciones disponibles","%s actualizaciones disponibles"],"(no title)":["(sin título)"],"Gophenberg %(version)s is available! Please update now.":["¡Ya está disponible Gophenberg %(version)s! Por favor, actualiza ahora."],"Important: Before updating, please back up your database and files. For help with updates, visit the Updating Gophenberg documentation page.":["Importante: Antes de actualizar, por favor, haz una copia de seguridad de tu base de datos y de los archivos. Para obtener ayuda con las actualizaciones, visita la página de documentación Actualización de Gophenberg."],"A %(kind)s field does not take a setting called %(setting)s. Remove it and try again.":["Un campo %(kind)s no acepta un ajuste llamado %(setting)s. Quítalo y prueba de nuevo."],"A Linked from field stands on its own, not inside a section or a repeater. Declare %(field)s beside the container.":["Un campo Enlazado desde va por su cuenta, no dentro de una sección ni de un repetidor. Declara %(field)s junto al contenedor."],"A backup of the database is taken first, and Gophenberg goes back to %(running)s on its own if the new version does not start.":["Primero se hace una copia de seguridad de la base de datos, y Gophenberg vuelve a %(running)s por su cuenta si la nueva versión no arranca."],"A backup of the database is taken first, and the site stays down until you restore it if the new version does not start.":["Primero se hace una copia de seguridad de la base de datos, y el sitio deja de funcionar hasta que la restaures si la nueva versión no arranca."],"A content type needs a singular and a plural name, like Guide and Guides. Fill both in and try again.":["Un tipo de contenido necesita un nombre en singular y otro en plural, como Guía y Guías. Rellena ambos e inténtalo de nuevo."],"A descriptive summary of the content type.":["Un resumen descriptivo del tipo de contenido."],"A field group key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Rename the group in the file so its key comes out in that shape.":["La clave de un grupo de campos tiene que empezar por una letra minúscula y después llevar solo letras minúsculas, números y guiones. Cambia el nombre del grupo en el archivo para que su clave salga con esa forma."],"A field key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Rename the field so its key comes out in that shape.":["La clave de un campo tiene que empezar por una letra minúscula y contener solo letras minúsculas, números y guiones. Renombra el campo para que su clave tenga esa forma."],"A field needs a name. Type one and try again.":["El campo necesita un nombre. Escribe uno e inténtalo de nuevo."],"A field with that name already exists on the items this group reaches. Pick another name.":["Ya existe un campo con ese nombre en los elementos que este grupo alcanza. Elige otro nombre."],"A flexible content field holds layouts, and %(field)s is not one. Add a layout first, then declare the field inside that layout.":["Un campo de contenido flexible contiene diseños, y %(field)s no lo es. Añade primero un diseño y después declara el campo dentro de ese diseño."],"A higher quality stores larger files, and it applies to pictures uploaded from now on.":["Una calidad más alta almacena archivos más grandes, y se aplica a las imágenes que subas a partir de ahora."],"A layout stands inside a flexible content field only. Put %(field)s inside one of those instead.":["Un diseño solo va dentro de un campo de contenido flexible. Pon %(field)s dentro de uno de ellos."],"A layout stands inside a flexible content field, never on its own. Declare a flexible content field first, then add %(field)s inside it.":["Un diseño va dentro de un campo de contenido flexible, nunca por su cuenta. Declara primero un campo de contenido flexible y después añade %(field)s dentro."],"A listing carries between 1 and %(max)s items, so %(value)s is not a size Gophenberg takes. Pick a number inside that range.":["Un listado muestra entre 1 y %(max)s elementos, así que %(value)s no es un tamaño que Gophenberg acepte. Elige un número dentro de ese rango."],"A relation field has to say which content type it points at. Pick that type and try again.":["Un campo de relación tiene que indicar a qué tipo de contenido apunta. Elige ese tipo e inténtalo de nuevo."],"A reload shows the admin in the language you chose.":["Al recargar verás el panel de administración en el idioma que has elegido."],"A route word has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Change it and try again.":["La palabra de ruta de la URL tiene que empezar por una letra minúscula y contener solo letras minúsculas, números y guiones. Cámbiala e inténtalo de nuevo."],"A row of %(field)s has to name the layout it takes. Pick a layout for the row, or remove the row.":["Una fila de %(field)s tiene que nombrar el diseño que toma. Elige un diseño para la fila, o quita la fila."],"A row of %(field)s takes one layout and no more. Reload the page and build the row again.":["Una fila de %(field)s toma un solo diseño. Recarga la página y crea la fila otra vez."],"A rule matching any %(source)s cannot be turned into an exclusion. Leave it as is, or name the ones to leave out instead.":["Una regla que vale para cualquier %(source)s no se puede convertir en exclusión. Déjala como está, o nombra los que quieras dejar fuera."],"A theme naming its own page size uses that instead.":["Un tema que indica su propio tamaño de página usa ese en su lugar."],"A type key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Change the key and try again.":["La clave de un tipo tiene que empezar por una letra minúscula y contener solo letras minúsculas, números y guiones. Cambia la clave e inténtalo de nuevo."],"Actions":["Acciones"],"Activate":["Activar"],"Activate %(theme)s":["Activar %(theme)s"],"Active":["Activo"],"Add":["Añadir"],"Add %(layout)s":["Añadir %(layout)s"],"Add %(name)s":["Añadir %(name)s"],"Add %(type)s":["Añadir %(type)s"],"Add Category":["Añadir categoría"],"Add Content Type":["Añadir tipo de contenido"],"Add Field Group":["Añadir grupo de campos"],"Add Media File":["Añadir medios"],"Add Page":["Añadir página"],"Add Post":["Añadir entrada"],"Add User":["Añadir usuario"],"Add block":["Añadir bloque"],"Add choice":["Añadir opción"],"Add condition":["Añadir condición"],"Add field":["Añadir campo"],"Add field to %(field)s":["Añadir campo a %(field)s"],"Add layout":["Añadir diseño"],"Add layout to %(field)s":["Añadir diseño a %(field)s"],"Add one with %(button)s.":["Añade un elemento con %(button)s."],"Add row":["Añadir fila"],"Add rule set":["Añadir conjunto de reglas"],"Add title":["Añadir título"],"Add to %(field)s":["Añadir a %(field)s"],"Address":["Dirección"],"Address updated.":["Dirección actualizada."],"Adopt":["Adoptar"],"Allow custom":["Permitir valores propios"],"Allow empty":["Permitir vacío"],"Alt text":["Texto alternativo"],"An item cannot point at itself. Pick a different item for %(field)s.":["Un elemento no puede apuntarse a sí mismo. Elige otro elemento para %(field)s."],"An item cannot sit inside itself, or inside one of the items nested under it. Pick a parent outside this branch.":["Un elemento no puede estar dentro de sí mismo, ni dentro de otro anidado bajo él. Elige un nivel superior fuera de esta rama."],"An updated version of Gophenberg is available.":["Hay disponible una versión actualizada de Gophenberg."],"Another account wrote this, and only its author, an editor or an administrator may change it. You can still read it.":["Otra cuenta escribió esto, y solo su autor, un editor o un administrador pueden cambiarlo. Todavía puedes leerlo."],"Another account wrote this, so you are reading it rather than editing it.":["Otra cuenta escribió esto, así que lo estás leyendo, no editando."],"Another content type already answers under this route word. Pick a different word.":["Ya hay otro tipo de contenido que responde con esta palabra de ruta de URL. Elige una palabra distinta."],"Another content type already lives at the root of your site, and only one can. Give this type a route word, or hand the root over with Make default.":["Ya hay otro tipo de contenido en la raíz de tu sitio, y solo puede haber uno. Dale a este tipo de contenido una palabra de ruta de URL, o cede la raíz con Establecer como predeterminado."],"Another content type already uses this key. Give this type a different name.":["Ya hay otro tipo de contenido que usa esta clave. Dale a este tipo un nombre distinto."],"Another item of this content type already uses that address. Pick a different slug and save again.":["Ya hay otro elemento de este tipo de contenido que usa esa dirección. Elige un slug distinto y guarda de nuevo."],"Another update is currently in progress.":["En este momento hay otra actualización en marcha."],"Appears on":["Aparece en"],"Apply":["Aplicar"],"April":["abril"],"Are you sure you want to move \"%s\" to the trash?":["¿Seguro que quieres mover «%s» a la papelera?"],"Audio":["Audio"],"August":["agosto"],"Author":["Autor"],"Back to %(type)s":["Volver a %(type)s"],"Back to the latest posts":["Volver a las últimas entradas"],"Backing up the database…":["Haciendo copia de seguridad de la base de datos…"],"Backups kept: %(kept)s of %(limit)s, taken on %(date)s at %(time)s.":["Copias de seguridad guardadas: %(kept)s de %(limit)s, hecha el %(date)s a las %(time)s.","Copias de seguridad guardadas: %(kept)s de %(limit)s, la más reciente del %(date)s a las %(time)s.","Copias de seguridad guardadas: %(kept)s de %(limit)s, la más reciente del %(date)s a las %(time)s."],"Block":["Bloque"],"Broken":["Roto"],"Bundles of fields, shown where their rules place them.":["Conjuntos de campos, mostrados donde sus reglas los colocan."],"Button group":["Grupo de botones"],"Cancel":["Cancelar"],"Caption":["Leyenda"],"Change %(name)s":["Cambiar %(name)s"],"Change address":["Cambiar la dirección"],"Change address…":["Cambiar la dirección…"],"Change role":["Cambiar el rol"],"Change the role of %(name)s":["Cambiar el rol de %(name)s"],"Check again.":["Comprobar de nuevo."],"Check now.":["Comprobar ahora."],"Checkbox group":["Grupo de casillas"],"Checking the new version…":["Comprobando la nueva versión…"],"Choices":["Opciones"],"Choose %(field)s":["Elegir %(field)s"],"Choose how the site serves its content.":["Elige cómo el sitio sirve su contenido."],"Choose the language the admin reads in.":["Elige el idioma en el que se lee el panel de administración."],"Choose the role of %(name)s.":["Elige el rol de %(name)s."],"Choose the version to update to.":["Elige la versión a la que actualizar."],"Clear %(field)s":["Vaciar %(field)s"],"Close":["Cerrar"],"Close Settings":["Cerrar ajustes"],"Closed":["Cerrado"],"Condition":["Condición"],"Content":["Contenido"],"Content Types":["Tipos de contenido"],"Content nests at most %(max)s levels deep, and this item would sit deeper. Pick a parent closer to the top.":["El contenido se anida como mucho %(max)s niveles, y este elemento quedaría más abajo. Elige un nivel superior más cercano al inicio."],"Content type":["Tipo de contenido"],"Content type updated.":["Tipo de contenido actualizado."],"Could not load that post.":["No se ha podido cargar esa entrada."],"Could not save image. %s":["No se ha podido guardar la imagen. %s"],"Could not save media. %s":["No se ha podido guardar el archivo multimedia. %s"],"Could not save that post.":["No se ha podido guardar esa entrada."],"Create":["Crear"],"Create a field group":["Crear un grupo de campos"],"Create user":["Crear usuario"],"Created":["Fecha de creación"],"Current version: %(version)s":["Versión actual: %(version)s"],"Date added":["Fecha de inclusión"],"Date modified":["Fecha de modificación"],"Deactivate":["Desactivar"],"Deactivate %(theme)s":["Desactivar %(theme)s"],"December":["diciembre"],"Default":["Por defecto"],"Default content type updated.":["Tipo de contenido predeterminado actualizado."],"Definitions file":["Archivo de definiciones"],"Delete":["Borrar"],"Delete \"%(title)s\" for good? This cannot be undone.":["¿Borrar permanentemente «%(title)s»? Esto no se puede deshacer."],"Delete %(field)s":["Borrar %(field)s"],"Delete %(group)s":["Eliminar %(group)s"],"Delete %s content type for good? This cannot be undone.":["¿Borrar permanentemente %s tipo de contenido? Esto no se puede deshacer.","¿Borrar permanentemente %s de tipos de contenido? Esto no se puede deshacer.","¿Borrar permanentemente %s tipos de contenido? Esto no se puede deshacer."],"Delete %s item for good? This cannot be undone.":["¿Borrar permanentemente %s elemento? Esto no se puede deshacer.","¿Borrar permanentemente %s de elementos? Esto no se puede deshacer.","¿Borrar permanentemente %s elementos? Esto no se puede deshacer."],"Delete permanently":["Borrar permanentemente"],"Delete the field":["Borrar el campo"],"Delete the group":["Eliminar el grupo"],"Delete…":["Borrar…"],"Describe":["Describir"],"Describe the purpose of the image.":["Describe el propósito de la imagen."],"Describe…":["Describir…"],"Description":["Descripción"],"Description updated.":["Descripción actualizada."],"Desktop":["Escritorio"],"Destination":["Destino"],"Dimensions":["Dimensiones"],"Disable":["Desactivar"],"Disable %(name)s":["Desactivar a %(name)s"],"Disabled":["Desactivado"],"Dismiss":["Descartar"],"Document":["Documento"],"Documents":["Documentos"],"Done. The site now holds what the file describes.":["Hecho. El sitio ya tiene lo que describe el archivo."],"Downloading Gophenberg %(version)s…":["Descargando Gophenberg %(version)s…"],"Draft saved.":["Borrador guardado."],"Drop files to upload":["Arrastra los archivos para subirlos"],"Edit media":["Editar los medios"],"Edit…":["Editar…"],"Email":["Correo electrónico"],"Empty Trash":["Vaciar papelera"],"Empty trash":["Vaciar papelera"],"Enable":["Activar"],"Enable %(name)s":["Activar a %(name)s"],"Every address of this type moves. Links kept elsewhere to the old addresses stop working.":["Cambian todas las direcciones de este tipo. Los enlaces guardados en otro sitio hacia las direcciones antiguas dejan de funcionar."],"Every content type":["Todos los tipos de contenido"],"Every field group needs a title. Give it a name and save again.":["Todo grupo de campos necesita un título. Ponle un nombre y guarda otra vez."],"Every item needs an author who exists. Pick one from the list and save again.":["Cada elemento necesita un autor que exista. Elige uno de la lista y guarda de nuevo."],"Every kind of content this site holds.":["Todos los tipos de contenido que hay en este sitio."],"Every value stored under this field goes with it, in every item the group reaches and in the revisions behind them.":["Todos los valores guardados en este campo se van con él, en cada elemento que el grupo alcanza y en las revisiones que hay detrás."],"Excerpt":["Extracto"],"Export definitions":["Exportar definiciones"],"February":["febrero"],"Fewest files":["Mínimo de archivos"],"Fewest rows":["Mínimo de filas"],"Field":["Campo"],"Field Groups":["Grupos de campos"],"Field group":["Grupo de campos"],"Fields":["Campos"],"Fields of %(group)s":["Campos de %(group)s"],"File name":["Nombre del archivo"],"File size":["Tamaño del archivo"],"File type":["Tipo de archivo"],"Filter by status":["Filtrar por estado"],"Follow the browser":["Sigue al navegador"],"Follow the steps on the Updating Gophenberg documentation page to update by hand.":["Sigue los pasos de la página de documentación Actualización de Gophenberg para actualizar a mano."],"From %(plugin)s":["De %(plugin)s"],"Full Size":["Tamaño completo"],"Gophenberg %(version)s failed its start check on this site. Fix what failed before you try it again.":["Gophenberg %(version)s no ha superado su comprobación de arranque en este sitio. Corrige lo que ha fallado antes de volver a intentarlo."],"Gophenberg Updates":["Actualizaciones de Gophenberg"],"Gophenberg cannot start this update: %(reason)s":["Gophenberg no puede empezar esta actualización: %(reason)s"],"Gophenberg checked for updates moments ago. Try again later.":["Gophenberg ha buscado actualizaciones hace un momento. Inténtalo de nuevo más tarde."],"Gophenberg could not read what your browser sent. Reload the page and try again, and tell whoever looks after your site if it keeps happening.":["Gophenberg no ha podido leer lo que ha enviado tu navegador. Recarga la página e inténtalo de nuevo, y avisa a quien gestiona tu sitio si sigue pasando."],"Gophenberg could not read which item you picked as parent. Reload the page and pick it again.":["Gophenberg no ha podido leer qué elemento has elegido como elemento superior. Recarga la página y vuelve a elegirlo."],"Gophenberg does not accept %(extension)s files. Upload a picture, a video, an audio file, a PDF or a zip instead.":["Gophenberg no acepta archivos %(extension)s. Sube una imagen, un vídeo, un audio, un PDF o un zip."],"Gophenberg does not answer in %(value)s. Pick one of the languages on the list.":["Gophenberg no responde en %(value)s. Elige uno de los idiomas de la lista."],"Gophenberg has no autosave of yours for this item. Open the item to see the version that is stored.":["Gophenberg no tiene ningún guardado automático tuyo de este elemento. Ábrelo para ver la versión guardada."],"Gophenberg has not checked for updates yet.":["Gophenberg todavía no ha buscado actualizaciones."],"Gophenberg has not come back yet.":["Gophenberg todavía no ha vuelto."],"Gophenberg holds no kind of definition called %(subject)s, so nothing was taken over. Reload the page so the admin and the server agree again.":["Gophenberg no tiene ninguna clase de definición llamada %(subject)s, así que no se ha adoptado nada. Recarga la página para que el admin y el servidor vuelvan a coincidir."],"Gophenberg keeps /%(path)s for itself or for another content type, so your content cannot answer there. Give the item a different slug.":["Gophenberg reserva la dirección /%(path)s para sí mismo o para otro tipo de contenido, así que tu contenido no puede usarla. Dale al elemento otro slug."],"Gophenberg keeps this word for itself, so no content type can answer under it. Pick a different route word.":["Gophenberg reserva esta palabra para sí mismo, así que ningún tipo de contenido puede usarla. Elige otra palabra de ruta de URL."],"Gophenberg stopped after the switch so that its service manager, such as systemd, starts the new version. Check that the service manager starts it again after exit code 75, and run update:status on the server to see where the update stands.":["Gophenberg se ha detenido tras el cambio para que su gestor de servicios, como systemd, arranque la nueva versión. Comprueba que el gestor de servicios lo vuelve a arrancar tras el código de salida 75, y ejecuta update:status en el servidor para ver en qué punto está la actualización."],"Gophenberg updated successfully.":["Gophenberg se ha actualizado correctamente."],"Gophenberg went back to %(from)s and is running normally.":["Gophenberg ha vuelto a %(from)s y funciona con normalidad."],"Group":["Grupo"],"Highest":["Máximo"],"Holds":["Contiene"],"Images":["Imágenes"],"Import definitions":["Importar definiciones"],"In list":["En la lista"],"Inactive":["Inactivo"],"Installed":["Instalado"],"Instructions":["Instrucciones"],"It moves here from another group and keeps its stored values.":["Se mueve aquí desde otro grupo y conserva sus valores guardados."],"It moves to another group and keeps its stored values.":["Se mueve a otro grupo y conserva sus valores guardados."],"It moves to another group, so its stored values do not follow.":["Se mueve a otro grupo, así que sus valores guardados no le siguen."],"It reads a relation inside a container, and only an import can point it elsewhere.":["Lee una relación dentro de un contenedor, y solo una importación puede apuntarlo a otro sitio."],"It starts on %(type)s, and the rules may be edited afterwards.":["Empieza en %(type)s, y las reglas se pueden editar después."],"Items could not be loaded.":["No se han podido cargar los elementos."],"Its items sit inside one another, so it keeps nesting.":["Sus elementos están unos dentro de otros, así que sigue anidando."],"Its kind changed, so its stored values go with it.":["Su tipo ha cambiado, así que sus valores guardados se van con él."],"January":["enero"],"July":["julio"],"June":["junio"],"Keep %(field)s out of the list":["Dejar %(field)s fuera de la lista"],"Keep it":["Conservarlo"],"Keep it here":["Dejarlo aquí"],"Key":["Clave"],"Label":["Etiqueta"],"Language":["Idioma"],"Large":["Grande"],"Last checked on %(date)s at %(time)s.":["Última comprobación el %(date)s a las %(time)s."],"Leave empty if decorative.":["Déjalo vacío si es decorativo."],"Let items nest":["Permitir anidar"],"Linked from":["Enlazado desde"],"List view":["Vista de lista"],"Loading field groups.":["Cargando los grupos de campos."],"Loading the post.":["Cargando la entrada."],"Loading the screen.":["Cargando la pantalla."],"Loading themes.":["Cargando los temas."],"Loading users.":["Cargando los usuarios."],"Loading…":["Cargando…"],"Longest":["Largo máximo"],"Lowest":["Mínimo"],"Make %(field)s optional":["Hacer %(field)s opcional"],"Make default":["Establecer como predeterminado"],"Make default…":["Establecer como predeterminado…"],"Make optional":["Hacer opcional"],"Manage the categories on this site.":["Gestiona las categorías de este sitio."],"Manage the images and files this site holds.":["Gestiona las imágenes y los archivos que hay en este sitio."],"Manage the items of this content type.":["Gestiona los elementos de este tipo de contenido."],"Manage the pages on this site.":["Gestiona las páginas de este sitio."],"Manage the posts on this site.":["Gestiona las entradas de este sitio."],"Many targets":["Varios destinos"],"Many values":["Varios valores"],"March":["marzo"],"May":["mayo"],"Media %(id)s":["Medio %(id)s"],"Media Library":["Biblioteca de medios"],"Media file updated.":["Archivo de medios actualizado."],"Medium":["Mediano"],"Mobile":["Móvil"],"Modified: %s":["Modificado: %s"],"Most files":["Máximo de archivos"],"Most rows":["Máximo de filas"],"Move":["Mover"],"Move \"%(title)s\" to the trash?":["¿Mover «%(title)s» a la papelera?"],"Move %(field)s down":["Bajar %(field)s"],"Move %(field)s elsewhere":["Mover %(field)s a otro sitio"],"Move %(field)s up":["Subir %(field)s"],"Move %(group)s down":["Bajar %(group)s"],"Move %(group)s up":["Subir %(group)s"],"Move %(name)s down":["Bajar %(name)s"],"Move %(name)s up":["Subir %(name)s"],"Move %s item to the trash?":["¿Mover %s elemento a la papelera?","¿Mover %s de elementos a la papelera?","¿Mover %s elementos a la papelera?"],"Move every address":["Mover todas las direcciones"],"Move row down":["Bajar la fila"],"Move row up":["Subir la fila"],"Move the field":["Mover el campo"],"Move to trash":["Mover a la papelera"],"Name":["Nombre"],"Name updated.":["Nombre actualizado."],"Nests":["Anida"],"Newer posts":["Entradas más recientes"],"No":["No"],"No content types found.":["No se han encontrado tipos de contenido."],"No description":["Sin descripción"],"No file arrived with this upload. Choose a file and try again.":["No ha llegado ningún archivo con esta subida. Elige un archivo e inténtalo de nuevo."],"No items found.":["No se han encontrado elementos."],"No items yet.":["Todavía no hay elementos."],"No media chosen":["Ningún medio elegido"],"No media has been uploaded yet.":["Todavía no se ha subido ningún medio."],"No media items found.":["No se han encontrado archivos de medios."],"No media items yet.":["Todavía no hay archivos de medios."],"No new updates found.":["No se han encontrado actualizaciones nuevas."],"No page lives at this address.":["No existe ninguna página en esta dirección."],"No parent":["Sin elemento superior"],"No theme arrived with this upload. Choose a zip file and try again.":["No ha llegado ningún tema con esta subida. Elige un archivo zip e inténtalo de nuevo."],"No themes are installed.":["No hay ningún tema instalado."],"No title":["Sin título"],"None":["Ninguno"],"Not %(type)s":["Excepto %(type)s"],"Not found":["No encontrado"],"Not serving":["No está sirviendo"],"Nothing declares that role.":["Nada declara ese rol."],"Nothing points here yet.":["Todavía no apunta nada aquí."],"Nothing published here yet.":["Todavía no hay nada publicado aquí."],"Nothing published yet.":["Todavía no hay nada publicado."],"November":["noviembre"],"Nowhere":["En ningún sitio"],"Number":["Número"],"October":["octubre"],"Older posts":["Entradas anteriores"],"One frame of this animation holds more than %(max)s pixels, which is more than Gophenberg opens. Upload a smaller animation.":["Un fotograma de esta animación tiene más de %(max)s píxeles, más de lo que Gophenberg abre. Sube una animación más pequeña."],"One of the filters on this list is not one Gophenberg understands. Clear the filters and try again.":["Uno de los filtros de esta lista no es un filtro que Gophenberg entienda. Quita los filtros e inténtalo de nuevo."],"One of the items picked for %(field)s is not the kind of content that field points at. Reload the page and pick from the list the field offers.":["Uno de los elementos elegidos para %(field)s no es del tipo de contenido al que apunta ese campo. Recarga la página y elige de la lista que ofrece el campo."],"One of the items picked for %(field)s was not named in a way Gophenberg understands. Reload the page and pick the items again.":["Uno de los elementos elegidos para %(field)s no venía nombrado de una forma que Gophenberg entienda. Recarga la página y vuelve a elegir los elementos."],"One of the items picked no longer exists. Reload the page and pick again.":["Uno de los elementos elegidos ya no existe. Recarga la página y vuelve a elegir."],"One target":["Un destino"],"Only a relation field points at another content type or holds many items. Pick the Relation kind, or leave the target and the many option empty.":["Solo un campo de relación apunta a otro tipo de contenido o guarda varios elementos. Elige el tipo Relación, o deja vacío el destino y la opción de varios."],"Only one file may be placed here.":["Aquí solo se puede colocar un archivo."],"Only the content type at the root of your site may go without a route word. Give this type one and try again.":["Solo el tipo de contenido que está en la raíz de tu sitio puede ir sin palabra de ruta de URL. Dale una a este tipo e inténtalo de nuevo."],"Open %(field)s in a new tab":["Abrir %(field)s en una pestaña nueva"],"Order stored.":["Orden guardado."],"Other":["Otro"],"Out of list":["Fuera de la lista"],"Parent":["Elemento superior"],"Password":["Contraseña"],"Pending":["Pendiente"],"Pending Review":["Pendiente de revisión"],"Permanently delete…":["Eliminar permanentemente…"],"Picture quality":["Calidad de imagen"],"Picture quality runs from 1 to %(max)s, so %(value)s is not a quality Gophenberg stores at. Pick a number inside that range.":["La calidad de imagen va de 1 a %(max)s, así que %(value)s no es una calidad con la que Gophenberg guarde. Elige un número dentro de ese rango."],"Placeholder":["Texto de ejemplo"],"Plural name":["Nombre en plural"],"Points at":["Apunta a"],"Post published.":["Entrada publicada."],"Posts per page":["Entradas por página"],"Preview":["Vista previa"],"Private":["Privada"],"Publish":["Publicar"],"Published: %s":["Publicado: %s"],"Radio group":["Grupo de botones de radio"],"Re-install version %(version)s":["Reinstalar la versión %(version)s"],"Reads from":["Lee de"],"Redo":["Rehacer"],"Relation":["Relación"],"Reload the admin":["Recargar la administración"],"Remove":["Quitar"],"Remove %(name)s":["Quitar %(name)s"],"Remove %(title)s":["Quitar %(title)s"],"Remove row":["Quitar fila"],"Rename":["Renombrar"],"Rename %(field)s":["Renombrar %(field)s"],"Rename…":["Renombrar…"],"Require":["Hacer obligatorio"],"Require %(field)s":["Hacer %(field)s obligatorio"],"Required":["Obligatorio"],"Restarting Gophenberg…":["Reiniciando Gophenberg…"],"Restore":["Restaurar"],"Role changed.":["Rol cambiado."],"Roll back to %(theme)s":["Revertir a %(theme)s"],"Roll back to the built-in renderer":["Revertir al renderizador integrado"],"Route word":["Palabra de ruta"],"Rule %(number)s of set %(set)s":["Regla %(number)s del conjunto %(set)s"],"Rule set %(number)s":["Conjunto de reglas %(number)s"],"Rules":["Reglas"],"Rules showing %(field)s":["Reglas que muestran %(field)s"],"Run update:status on the server to see the backup taken before the update. Then restore that backup, or fix what failed and start Gophenberg again.":["Ejecuta update:status en el servidor para ver la copia de seguridad hecha antes de la actualización. Después, restaura esa copia de seguridad, o corrige lo que ha fallado y vuelve a arrancar Gophenberg."],"Save":["Guardar"],"Save draft":["Guardar el borrador"],"Save rules":["Guardar las reglas"],"Save settings":["Guardar los ajustes"],"Saved":["Guardado"],"Saving":["Guardando"],"Scheduled":["Programada"],"Scheduled: %s":["Programado: %s"],"Search %(type)s…":["Buscar %(type)s…"],"Search audio":["Buscar audios"],"Search images":["Buscar imágenes"],"Search media":["Buscar medios"],"Search videos":["Buscar vídeos"],"Select":["Seleccionar"],"September":["septiembre"],"Serving":["Atendiendo"],"Settings":["Ajustes"],"Settings of %(field)s":["Ajustes de %(field)s"],"Shadowed":["Eclipsado"],"Show %(field)s in the list":["Mostrar %(field)s en la lista"],"Showing %(held)s of %(total)s.":["Mostrando %(held)s de %(total)s."],"Singular name":["Nombre en singular"],"Slug":["Slug"],"Somebody must be able to manage users.":["Alguien tiene que poder gestionar los usuarios."],"Someone else changed this media item while you were editing it. Reload the page and make your change again.":["Otra persona ha cambiado este medio mientras lo editabas. Recarga la página y vuelve a hacer tu cambio."],"Someone else saved changes to this item while you were editing, so yours were not saved. Copy your text somewhere safe, then reload the item and put your changes back in.":["Otra persona ha guardado cambios en este elemento mientras editabas, así que los tuyos no se han guardado. Copia tu texto a un lugar seguro, recarga el elemento y vuelve a colocarlos de vuelta."],"Something went wrong inside Gophenberg. Try again in a moment, and tell whoever looks after your site if it keeps happening.":["Algo ha fallado dentro de Gophenberg. Inténtalo de nuevo en un momento, y avisa a quien gestione tu sitio si sigue pasando."],"Something went wrong.":["Algo ha ido mal."],"Something went wrong. Try again.":["Algo ha ido mal. Inténtalo de nuevo."],"Sorry, you are not allowed to access this page.":["Lo siento, no tienes permisos para acceder a esta página."],"Source":["Origen"],"Steps of":["Pasos de"],"Stop nesting":["Dejar de anidar"],"Tablet":["Tableta"],"Text":["Texto"],"Text area":["Área de texto"],"That email is already in use.":["Ese correo electrónico ya está en uso."],"That field group no longer exists. Reload the page to see the groups your site holds now.":["Ese grupo de campos ya no existe. Recarga la página para ver los grupos que tiene ahora tu sitio."],"That field is not on this content type any more. Reload the page to see the fields it has now.":["Ese campo ya no está en este tipo de contenido. Recarga la página para ver los campos que tiene ahora."],"That revision does not exist, and older ones drop off once a type holds more than it keeps. Open the item to see which revisions are left.":["Esa revisión no existe, y las más antiguas se pierden cuando un tipo guarda más de las que conserva. Abre el elemento para ver qué revisiones quedan."],"That role holds more than your own.":["Ese rol abarca más que el tuyo."],"That web address does not name a media item Gophenberg can look up. Open the media library and pick the item from there.":["Esa dirección web no nombra ningún medio que Gophenberg pueda encontrar. Abre la biblioteca de medios y elige el elemento desde ahí."],"That web address does not name a revision Gophenberg can look up. Open the item and pick a revision from its history.":["Esa dirección web no alude a ninguna revisión que Gophenberg pueda identificar. Abre el elemento y elige una revisión de su historial."],"That web address does not name an item Gophenberg can look up. Go back to the list and open the item from there.":["Esa dirección web no alude a ningún elemento que Gophenberg pueda identificar. Vuelve a la lista y abre el elemento desde ahí."],"The %(count)s item in the trash is deleted for good. This cannot be undone.":["%(count)s elemento de la papelera se borrará permanentemente. Esto no se puede deshacer.","%(count)s de elementos de la papelera se borrarán permanentemente. Esto no se puede deshacer.","Los %(count)s elementos de la papelera se borrarán permanentemente. Esto no se puede deshacer."],"The %(file)s calls this theme %(declared)s, but it is being installed as %(installed)s. Rename the zip file to match, or change the name inside %(file)s.":["El archivo %(file)s llama a este tema %(declared)s, pero se está instalando como %(installed)s. Renombra el zip para que coincida, o cambia el nombre dentro de %(file)s."],"The %(file)s inside %(name)s is not valid JSON, so it could not be read. Fix that file and package the theme again.":["El archivo %(file)s dentro de %(name)s no es JSON válido, así que no se ha podido leer. Corrige ese archivo y vuelve a empaquetar el tema."],"The %(file)s inside %(name)s names its theme kit as %(declared)s, which is not a version number. Build the theme again, and the build will fill that in.":["El %(file)s dentro de %(name)s identifica su kit de temas como %(declared)s, que no srive como número de versión. Compila el tema de nuevo y la compilación lo rellenará."],"The %(origin)s plugin declared this, so it can only be changed in that plugin. Turning it off is still yours to do.":["El plugin %(origin)s lo declaró, así que solo se puede cambiar en ese plugin. Desactivarlo sigue estando en tu mano."],"The %(plugin)s plugin also declares %(name)s, and the site keeps the key.":["El plugin %(plugin)s también declara %(name)s, y el sitio se queda con la clave."],"The %(plugin)s plugin declared these fields, so they change only in its code.":["El plugin %(plugin)s declaró estos campos, así que solo cambian en su código."],"The %(plugin)s plugin declares %(name)s flat, and the site keeps it nesting while its items sit inside another.":["El plugin %(plugin)s declara %(name)s sin anidar, y el sitio lo mantiene anidando mientras sus elementos están dentro de otro."],"The browser kept an unsaved version of this post.":["El navegador ha guardado una versión sin guardar de esta entrada."],"The built-in renderer is now serving the public site.":["El renderizador integrado ya presta servicio al sitio público."],"The built-in renderer is serving the public site.":["El renderizador integrado presta servicio al sitio público."],"The check on %(date)s at %(time)s failed: %(error)s":["La comprobación del %(date)s a las %(time)s ha fallado: %(error)s"],"The content type this field points at is not named in a shape Gophenberg accepts. Give it a key that starts with a lowercase letter and then holds only lowercase letters, numbers and hyphens.":["El tipo de contenido al que apunta este campo no está nombrado con un formato que Gophenberg acepte. Dale una clave que empiece por una letra minúscula y contenga solo letras minúsculas, números y guiones."],"The content types could not be loaded, so where these groups appear and which fields they shadow are not shown.":["No se han podido cargar los tipos de contenido, así que no se muestra dónde aparecen estos grupos ni qué campos eclipsan."],"The content types could not be loaded.":["No se han podido cargar los tipos de contenido."],"The content types could not be refreshed, so where these groups appear and what they shadow may be out of date.":["No se han podido actualizar los tipos de contenido, así que dónde aparecen estos grupos y qué eclipsan puede estar desactualizado."],"The draft could not be created.":["No se ha podido crear el borrador."],"The entry %(entry)s in this zip would be written outside the theme folder, so nothing was installed. Package the theme again.":["La entrada %(entry)s de este zip se escribiría fuera de la carpeta del tema, así que no se ha instalado nada. Vuelve a empaquetar el tema."],"The field %(field)s cannot go, because %(by)s reads it. Change %(by)s first.":["El campo %(field)s no se puede quitar, porque %(by)s lo lee. Cambia antes %(by)s."],"The field %(field)s cannot hold the value it was given. Check what kind of field it is and enter a value that matches.":["El campo %(field)s no puede guardar el valor que se le ha dado. Comprueba de qué tipo de campo se trata e introduce un valor que encaje."],"The field %(field)s has to hold a value before this item can be published. Fill it in, or leave the item as a draft.":["El campo %(field)s tiene que tener un valor antes de poder publicar este elemento. Rellénalo, o deja el elemento como borrador."],"The field %(field)s in %(group)s still points at this content type. Delete that field first, then delete this type.":["El campo %(field)s de %(group)s todavía apunta a este tipo de contenido. Borra antes ese campo y luego borra este tipo."],"The field %(field)s is hidden by its own rules right now, so it cannot hold a value. Show it again before filling it in.":["El campo %(field)s está oculto por sus propias reglas ahora mismo, así que no puede guardar ningún valor. Vuelve a mostrarlo antes de rellenarlo."],"The field %(field)s points at one item only. Remove the extra choices and keep one.":["El campo %(field)s apunta a un solo elemento. Quita las opciones de más y deja una."],"The field %(field)s points at other items, so it does not take a plain value. Pick the items it points at instead.":["El campo %(field)s apunta a otros elementos, así que no admite un valor suelto. Elige en su lugar los elementos a los que apunta."],"The field %(field)s takes a list of items, and what arrived was not a list. Reload the page and pick the items again.":["El campo %(field)s admite una lista de elementos, y lo que ha llegado no era una lista. Recarga la página y vuelve a elegir los elementos."],"The field %(source)s cannot hold the value %(value)s, so no rule can compare it. Write a value of the kind %(source)s stores.":["El campo %(source)s no puede guardar el valor %(value)s, así que ninguna regla puede compararlo. Escribe un valor de la clase que %(source)s guarda."],"The field groups could not be loaded.":["No se han podido cargar los grupos de campos."],"The field groups could not be reached.":["No se ha podido contactar con los grupos de campos."],"The field keeps its values on the content both groups reach.":["El campo conserva sus valores en el contenido al que llegan ambos grupos."],"The fields this group holds go with it, and so do the values every item stored in them.":["Los campos que contiene este grupo se van con él, y también los valores que cada elemento guardó en ellos."],"The groups were reordered.":["Los grupos se han reordenado."],"The item could not be duplicated.":["No se ha podido duplicar el elemento."],"The item could not be moved to the trash.":["No se ha podido mover el elemento a la papelera."],"The item could not be permanently deleted.":["No se ha podido borrar permanentemente el elemento."],"The item could not be restored.":["No se ha podido restaurar el elemento."],"The item you picked as parent holds another kind of content. Pick a parent of the same content type as this item.":["El elemento que has elegido como superior tiene otro tipo de contenido. Elige un elemento superior del mismo tipo de contenido que este elemento."],"The item you picked as parent is in the trash. Restore it, or pick another parent.":["El elemento que has elegido como superior está en la papelera. Restáuralo, o elige otro elemento superior."],"The item you picked as parent no longer exists. Reload the page and pick another parent.":["El elemento que has elegido como superior ya no existe. Recarga la página y elige otro."],"The media library could not be loaded.":["No se ha podido cargar la biblioteca de medios."],"The name changes. Nothing stored under this field moves.":["El nombre cambia. Nada de lo guardado en este campo se mueve."],"The name could not be updated.":["No se ha podido actualizar el nombre."],"The new order has to name every field group exactly once. Reload the page and move the groups again.":["El nuevo orden tiene que nombrar cada grupo de campos exactamente una vez. Recarga la página y mueve los grupos otra vez."],"The new order has to name every field of this content type exactly once. Reload the page and move the fields again.":["El nuevo orden tiene que nombrar cada campo de este tipo de contenido exactamente una vez. Recarga la página y mueve los campos de nuevo."],"The next check runs in %(time)s.":["La próxima comprobación será dentro de %(time)s."],"The number of revisions to keep has to be a whole number, and it cannot be negative. Enter a different number.":["El número de revisiones que se conservan tiene que ser un número entero, y no puede ser negativo. Introduce otro número."],"The registry could not be reached.":["No se ha podido acceder al registro."],"The role could not be changed.":["No se ha podido cambiar el rol."],"The rule on %(source)s names nothing to match. Pick a value, or remove the rule.":["La regla sobre %(source)s no nombra nada con lo que coincidir. Elige un valor, o quita la regla."],"The rules could not be loaded.":["No se han podido cargar las reglas."],"The rules on %(field)s lead back to %(field)s itself, so nothing can decide whether to show it. Point one of them at another field.":["Las reglas de %(field)s vuelven al propio %(field)s, así que nada puede decidir si mostrarlo. Apunta una de ellas a otro campo."],"The same item was picked twice for %(field)s. Pick each item once.":["El mismo elemento se ha elegido dos veces para %(field)s. Elige cada elemento una sola vez."],"The server could not be reached, so nothing was changed.":["No se ha podido acceder al servidor, así que no se ha cambiado nada."],"The server could not be reached, so nothing was saved.":["No se ha podido acceder al servidor, así que no se ha guardado nada."],"The server could not be reached, so nothing was uploaded.":["No se ha podido acceder al servidor, así que no se ha subido nada."],"The setting %(setting)s cannot hold the value it was given. Check what this setting takes and try again.":["El ajuste %(setting)s no puede contener el valor que se le dio. Comprueba qué acepta este ajuste y prueba de nuevo."],"The setting %(setting)s falls outside the others. Keep min below max and the default inside the bounds.":["El ajuste %(setting)s queda fuera de los demás. Mantén min por debajo de max y el valor por defecto dentro de los límites."],"The settings could not be read, so nothing can be changed here yet.":["No se han podido leer los ajustes, así que todavía no se puede cambiar nada aquí."],"The site default":["El idioma por defecto del sitio"],"The site may already hold part of this file. Import it again to see what is left.":["Puede que el sitio ya tenga parte de este archivo. Impórtalo de nuevo para ver lo que queda."],"The source %(source)s does not offer %(operator)s. Pick one of the comparisons it does offer.":["La fuente %(source)s no ofrece %(operator)s. Elige una de las comparaciones que sí ofrece."],"The theme %(name)s carries no %(file)s, so Gophenberg cannot tell what it is. Put that file at the top level of the zip and package the theme again.":["El tema %(name)s no lleva ningún %(file)s, así que Gophenberg no puede saber qué es. Pon ese archivo en el primer nivel del zip y vuelve a empaquetar el tema."],"The theme %(name)s could not be read, so it cannot serve your site. Upload it again, or choose another theme.":["El tema %(name)s no se ha podido leer, así que no puede servir tu sitio. Vuelve a subirlo, o elige otro tema."],"The theme %(name)s did not start, so your site is still served by the theme it had. Ask whoever looks after your site to check the server log for what the theme reported.":["El tema %(name)s no ha arrancado, así que tu sitio lo sigue sirviendo el tema que tenía. Pide a quien gestiona tu sitio que mire en el registro del servidor para saber qué problema ha informado el tema."],"The theme %(name)s does not carry %(path)s as a file, so there is nothing to run. Package the built theme rather than its source.":["El tema %(name)s no lleva %(path)s como archivo, así que no hay nada que ejecutar. Empaqueta el tema ya construido, no su código fuente."],"The theme %(name)s does not carry %(path)s as a folder, so its styles and scripts are missing. Package the built theme rather than its source.":["El tema %(name)s no lleva %(path)s como carpeta, así que le faltan los estilos y los scripts. Empaqueta el tema ya construido, no su código fuente."],"The theme %(name)s holds a link to another file at %(path)s, and a theme may only carry real files. Replace it and package the theme again.":["El tema %(name)s lleva un enlace a otro archivo en %(path)s, y un tema solo puede llevar archivos de verdad. Sustitúyelo y vuelve a empaquetar el tema."],"The theme %(name)s is serving your site right now, so it cannot be replaced. Deactivate it first, or install this copy under another name.":["El tema %(name)s sirve tu sitio ahora mismo, así que no se puede sustituir. Desactívalo primero, o instala esta copia con otro nombre."],"The theme %(name)s is the one chosen, but it is not installed, so your site is served by the built-in renderer. Upload the theme again, or choose another one.":["El tema %(name)s es el elegido, pero no está instalado, así que el renderizador integrado está prestando servicio a tu sitio. Vuelve a subir el tema, o elige otro."],"The theme %(name)s was built on theme kit %(declared)s, and this site serves %(served)s. Build the theme again against a kit this site serves, then install it.":["El tema %(name)s se compiló con el kit de temas %(declared)s y este sitio sirve %(served)s. Compila el tema de nuevo con un kit que este sitio sirva y después instálalo."],"The trash could not be emptied.":["No se ha podido vaciar la papelera."],"The update failed before anything changed.":["La actualización ha fallado antes de cambiar nada."],"The update to %(to)s failed its start check, and Gophenberg cannot go back to %(from)s on its own.":["La actualización a %(to)s no ha superado su comprobación de arranque, y Gophenberg no puede volver a %(from)s por su cuenta."],"The update to %(to)s failed.":["La actualización a %(to)s ha fallado."],"The update to Gophenberg %(version)s failed to complete. Please attempt the update again now.":["No se ha podido completar la actualización a Gophenberg %(version)s. Por favor, vuelve a intentarlo."],"The updates could not be read, so nothing can be updated here yet.":["No se han podido leer las actualizaciones, así que todavía no se puede actualizar nada aquí."],"The user could not be created.":["No se ha podido crear el usuario."],"The values stored under it do not follow.":["Los valores guardados debajo no le siguen."],"Theme":["Tema"],"Themes":["Temas"],"Themes could not be loaded.":["No se han podido cargar los temas."],"There is no content type called %(value)s. Pick a type your site holds, or register it first.":["No existe ningún tipo de contenido llamado %(value)s. Elige un tipo que tenga tu sitio, o regístralo primero."],"There is no content type called %(value)s. Pick one of the types your site holds and try again.":["No existe ningún tipo de contenido llamado %(value)s. Elige uno de los tipos que tiene tu sitio e inténtalo de nuevo."],"There is no kind of field called %(value)s. Pick one of these instead: %(allowed)s.":["No existe ningún tipo de campo llamado %(value)s. Elige uno de estos: %(allowed)s."],"There is no page kind called %(value)s. Pick one of these instead: %(allowed)s.":["No existe ningún tipo de página llamado %(value)s. Elige uno de estos: %(allowed)s."],"There is no status called %(value)s. Pick one of these instead: %(allowed)s.":["No existe ningún estado llamado %(value)s. Elige uno de estos: %(allowed)s."],"There is nothing at this address. Check the link and try again.":["No hay nada en esta dirección. Comprueba el enlace e inténtalo de nuevo."],"There is nothing to roll back to, because your site has not been through a theme change yet. Install a theme first, then a rollback has somewhere to go.":["No hay nada a lo que retornar, porque tu sitio todavía no ha cambiado de tema. Instala un tema primero y así el retorno tendrá adónde ir."],"These files could not be read.":["No se han podido leer estos archivos."],"These were left alone, because nobody confirmed losing them.":["Estos se han dejado como estaban, porque nadie confirmó perderlos."],"This content type does not exist any more. Reload the page to see the types your site holds now.":["Este tipo de contenido ya no existe. Recarga la página para ver los tipos que tiene ahora tu sitio."],"This content type does not nest, so one of its items cannot sit inside another. Mark the type as Nests first.":["Este tipo de contenido no anida, así que uno de sus elementos no puede estar dentro de otro. Marca el tipo como Anida primero."],"This content type has no field called %(field)s. Check the name, or declare the field on the type first.":["Este tipo de contenido no tiene ningún campo llamado %(field)s. Comprueba el nombre, o declara antes el campo en el tipo."],"This content type is turned off, so its content is not served or edited. Activate it first.":["Este tipo de contenido está desactivado, así que su contenido ni se sirve ni se edita. Actívalo primero."],"This content type still holds content, so it cannot be deleted. Move or delete its items first.":["Este tipo de contenido todavía tiene contenido, así que no se puede borrar. Mueve o borra antes sus elementos."],"This definitions file is larger than the %(max)s bytes Gophenberg reads in one request. Split it, or raise the limit your site runs with.":["Este archivo de definiciones es mayor que los %(max)s bytes que Gophenberg lee en una petición. Divídelo, o sube el límite con el que funciona tu sitio."],"This field holds no layouts yet.":["Este campo todavía no tiene diseños."],"This field would stand inside too many containers. Put it nearer the top and try again.":["Este campo quedaría dentro de demasiados contenedores. Ponlo más cerca del nivel superior e inténtalo de nuevo."],"This file could not be opened as a zip. Package the theme again and upload the new file.":["Este archivo no se ha podido abrir como zip. Vuelve a empaquetar el tema y sube el archivo nuevo."],"This file is larger than the upload limit. Upload a smaller file.":["Este archivo es más grande que el límite de subida. Sube un archivo más pequeño."],"This file is named %(extension)s but it holds %(detected)s content. Upload it under a name that matches what is inside it.":["Este archivo se llama %(extension)s pero lleva contenido %(detected)s. Súbelo con un nombre que coincida con lo que lleva dentro."],"This file matches the site, so there is nothing to change.":["Este archivo coincide con el sitio, así que no hay nada que cambiar."],"This file says it was written in format %(declared)s, which is not a version Gophenberg can read. Export the definitions again from the site they came from.":["Este archivo dice estar escrito en el formato %(declared)s, que no es una versión que Gophenberg pueda leer. Vuelve a exportar las definiciones desde el sitio del que vinieron."],"This file was written in format %(declared)s, and this release reads %(served)s. Upgrade the site the file came from, or this one.":["Este archivo está escrito en el formato %(declared)s, y esta versión lee %(served)s. Actualiza el sitio del que viene el archivo, o este."],"This group holds no fields yet.":["Este grupo todavía no tiene campos."],"This install of Gophenberg has no install root, so it updates by hand.":["Esta instalación de Gophenberg no tiene raíz de instalación, así que se actualiza a mano."],"This install of Gophenberg updates by hand.":["Esta instalación de Gophenberg se actualiza a mano."],"This is a custom build of Gophenberg, so it updates by hand.":["Esta es una compilación propia de Gophenberg, así que se actualiza a mano."],"This item cannot go straight to that status from the one it holds now. Save it as a draft first, then try again.":["Este elemento no puede pasar directamente a ese estado desde el que tiene ahora. Guárdalo antes como borrador e inténtalo de nuevo."],"This item does not exist, and it may have been deleted. Go back to the list to see what is there.":["Este elemento no existe, y puede que se haya borrado. Vuelve a la lista para ver qué hay."],"This item is already in the trash. Restore it first to work on it again.":["Este elemento ya está en la papelera. Restáuralo primero para volver a trabajar en él."],"This item is in the trash. Restore it first to work on it again.":["Este elemento está en la papelera. Restáuralo primero para volver a trabajar en él."],"This item is not in the trash, so there is nothing to restore. Open it from the list to work on it as it is.":["Este elemento no está en la papelera, así que no hay nada que restaurar. Ábrelo desde la lista para trabajar en él tal como está."],"This item still holds items nested inside it. Move or delete those first.":["Este elemento todavía tiene elementos anidados dentro. Mueve o borra antes esos."],"This kind of field holds no fields inside it. Put the field in a section or a repeater instead.":["Este tipo de campo no contiene campos dentro. Pon el campo en una sección o en un repetidor."],"This media item is not in the library, and someone may have deleted it. Reload the page to see what is there now.":["Este medio no está en la biblioteca, y puede que alguien lo haya borrado. Recarga la página para ver qué hay ahora."],"This picture could not be read, so nothing was stored. The file may be damaged, so open it on your computer and upload it again.":["Esta imagen no se ha podido leer, así que no se ha guardado nada. Puede que el archivo esté dañado, así que ábrelo en tu ordenador y vuelve a subirlo."],"This picture is %(width)s by %(height)s pixels, over the limit of %(max)s pixels in all. Make it smaller and upload it again.":["Esta imagen tiene %(width)s por %(height)s píxeles, por encima del límite de %(max)s píxeles en total. Hazla más pequeña y vuelve a subirla."],"This post changed elsewhere. Reload before saving again.":["Esta entrada ha cambiado en otro sitio. Recarga antes de volver a guardar."],"This request came from a page on another site, so it was refused. Open the admin on this site and try again.":["Esta petición vino de una página de otro sitio, así que se rechazó. Abre la administración en este sitio e inténtalo de nuevo."],"This request carried %(attribute)s, which fields do not take. Reload the page so the admin and the server agree again.":["Esta petición llevaba %(attribute)s, que los campos no aceptan. Recarga la página para que la administración y el servidor vuelvan a coincidir."],"This request left out %(field)s, which Gophenberg needs. Reload the page and try again.":["En esta petición faltaba %(field)s, que Gophenberg necesita. Recarga la página e inténtalo de nuevo."],"This rule reads a source called %(source)s, and nothing on your site declares one. A plugin that added it may have been removed.":["Esta regla lee una fuente llamada %(source)s, y nada en tu sitio declara ninguna. Puede que se haya quitado un plugin que la añadía."],"This site cannot write to its themes folder, so no theme can be installed. Ask whoever looks after your site to make the folder that %(setting)s points at writable. A read-only mount is the usual cause.":["Este sitio no puede escribir en su carpeta de temas, así que no se puede instalar ninguno. Pide a quien gestione tu sitio que haga escribible la carpeta a la que apunta %(setting)s. La causa habitual es un montaje de solo lectura."],"This site does not check for updates on its own.":["Este sitio no busca actualizaciones por su cuenta."],"This site has nowhere to keep themes, so no theme can be installed. Ask whoever looks after your site to point %(setting)s at a folder the server can write to.":["Este sitio no tiene dónde guardar los temas, así que no se puede instalar ninguno. Pide a quien gestione tu sitio que apunte %(setting)s a una carpeta en la que el servidor pueda escribir."],"This site has nowhere to store uploads, so nothing can be uploaded. Ask whoever looks after your site to point %(setting)s at a folder the server can write to.":["Este sitio no tiene dónde guardar las subidas, así que no se puede subir nada. Pide a quien gestione tu sitio que apunte %(setting)s a una carpeta en la que el servidor pueda escribir."],"This site will not receive automatic updates for new versions of Gophenberg.":["Este sitio no recibirá actualizaciones automáticas de nuevas versiones de Gophenberg."],"This theme is over the limit of %(max)s bytes, packed or unpacked. Leave out what the theme does not need and package it again.":["Este tema pasa del límite de %(max)s bytes, comprimido o sin comprimir. Saca lo que el tema no necesite y vuelve a empaquetarlo."],"This type will answer under /%(word)s.":["Este tipo responderá como /%(word)s."],"This update needs a backup of the database, and the site stays down if the new version does not start.":["Esta actualización necesita una copia de seguridad de la base de datos, y el sitio deja de funcionar si la nueva versión no arranca."],"This zip holds %(entries)s files, more than the %(max)s a theme may carry. Package only the built theme.":["Este zip lleva %(entries)s archivos, más de los %(max)s que puede llevar un tema. Empaqueta solo el tema ya construido."],"Through":["A través de"],"Thumbnail":["Miniatura"],"Title":["Título"],"Two field groups in this file share the key %(key)s. Give one of them a different key and import again.":["Dos grupos de campos de este archivo comparten la clave %(key)s. Dale una clave distinta a uno de ellos e importa de nuevo."],"Two rule sources are registered under the name %(param)s. A plugin is declaring a source your site already holds.":["Hay dos fuentes de reglas registradas con el nombre %(param)s. Un plugin declara una fuente que tu sitio ya tiene."],"Type":["Tipo"],"Type a whole number in both boxes before saving.":["Escribe un número entero en las dos casillas antes de guardar."],"Undo":["Deshacer"],"Unpacking the update…":["Descomprimiendo la actualización…"],"Unsaved changes":["Cambios sin guardar"],"Update":["Actualizar"],"Update failed.":["No se ha podido actualizar."],"Update to Gophenberg %(version)s?":["¿Actualizar a Gophenberg %(version)s?"],"Update to version %(version)s":["Actualizar a la versión %(version)s"],"Updates":["Actualizaciones"],"Upload theme":["Subir tema"],"Uploaded %s file.":["%s archivo subido.","%s de archivos subidos.","%s archivos subidos."],"Users":["Usuarios"],"Users could not be loaded.":["No se han podido cargar los usuarios."],"Value":["Valor"],"Verifying the unpacked files…":["Verificando los archivos descomprimidos…"],"Version":["Versión"],"Videos":["Vídeos"],"Visit Site":["Visitar el sitio"],"Web address":["Dirección web"],"What each Linked from field reads":["Qué lee cada campo Enlazado desde"],"What it points at changed, so its stored values go with it.":["Aquello a lo que apunta ha cambiado, así que sus valores guardados se van con él."],"Where %(group)s appears":["Dónde aparece %(group)s"],"While your site is being updated, it keeps serving until Gophenberg restarts on the new version.":["Mientras tu sitio está siendo actualizado, sigue funcionando hasta que Gophenberg se reinicia con la nueva versión."],"Without a rule this field always shows.":["Sin ninguna regla este campo siempre se muestra."],"Without a rule this group appears nowhere.":["Sin una regla este grupo no aparece en ningún sitio."],"Yes":["Sí"],"Yes or no":["Sí o no"],"You can update from Gophenberg %(running)s to Gophenberg %(version)s manually:":["Puedes actualizar desde Gophenberg %(running)s a Gophenberg %(version)s manualmente:"],"You cannot change your own role.":["No puedes cambiar tu propio rol."],"You cannot update because Gophenberg %(version)s requires PostgreSQL version %(postgresql)s or higher.":["No puedes actualizar porque Gophenberg %(version)s necesita la versión %(postgresql)s o superior de PostgreSQL."],"You have the latest version of Gophenberg.":["Tienes la última versión de Gophenberg."],"Your language":["Tu idioma"],"Your role does not allow %(capability)s.":["Tu rol no permite %(capability)s."],"Your server pins the site to the theme %(name)s, so themes cannot be changed here. Ask whoever looks after your site to remove the pin.":["Tu servidor bloque el sitio al tema %(name)s, así que los temas no se pueden cambiar desde aquí. Pide a quien gestiona tu sitio que quite ese bloqueo."],"Your site always needs one default content type, so this one cannot be turned off or deleted. Make another type the default first.":["Tu sitio siempre necesita un tipo de contenido por defecto, así que este no se puede desactivar ni borrar. Haz antes que otro tipo sea el que está por defecto."],"a content type":["un tipo de contenido"],"account\u0004Role":["Rol"],"account\u0004Status":["Estado"],"action label\u0004Duplicate":["Duplicar"],"action label\u0004Duplicate…":["Duplicar…"],"address":["dirección"],"admin section\u0004Content Types":["Tipos de contenido"],"admin section\u0004Field Groups":["Grupos de campos"],"admin section\u0004Language":["Idioma"],"admin section\u0004Media":["Medios"],"admin section\u0004Settings":["Ajustes"],"admin section\u0004Themes":["Temas"],"column\u0004Date":["Fecha"],"content type\u0004\"%s\" permanently deleted.":["Se ha borrado permanentemente el tipo de contenido «%s»."],"content type\u0004\"%s\" successfully created.":["Se ha creado correctamente el tipo de contenido «%s»."],"content type\u0004Status":["Estado"],"field\u0004Name":["Nombre"],"field group\u0004Status":["Estado"],"field type\u0004Choice":["Elección"],"field type\u0004Color":["Color"],"field type\u0004Date":["Fecha"],"field type\u0004Flexible content":["Contenido flexible"],"field type\u0004Gallery":["Galería"],"field type\u0004Kind":["Tipo"],"field type\u0004Layout":["Diseño"],"field type\u0004Link":["Enlace"],"field type\u0004Media":["Medio"],"field type\u0004Range":["Rango"],"field type\u0004Repeater":["Repetidor"],"field type\u0004Section":["Sección"],"field type\u0004Select":["Desplegable"],"file size\u0004%1$s %2$s":["%1$s %2$s"],"file type group\u0004Archives":["Archivos"],"file type group\u0004Audio":["Audio"],"file type group\u0004Video":["Vídeo"],"holds":["contiene"],"holds anything":["contiene algo"],"https://www.w3.org/WAI/tutorials/images/decision-tree/":["https://www.w3.org/WAI/tutorials/images/decision-tree/"],"image dimensions\u0004%1$s × %2$s":["%1$s × %2$s"],"is":["es"],"is above":["es mayor que"],"is below":["es menor que"],"is empty":["está vacío"],"is not":["no es"],"panel button label\u0004Settings":["Ajustes"],"person\u0004Name":["Nombre"],"post\u0004%s (Copy)":["%s (copia)"],"post\u0004Status":["Estado"],"post status\u0004Draft":["Borrador"],"post status\u0004Published":["Publicada"],"post status\u0004Trash":["Papelera"],"post type general name\u0004Pages":["Páginas"],"post type general name\u0004Posts":["Entradas"],"post type singular name\u0004Page":["Página"],"post type singular name\u0004Post":["Entrada"],"relation target\u0004None":["Ninguno"],"role\u0004Administrator":["Administrador"],"role\u0004Author":["Autor"],"role\u0004Editor":["Editor"],"role\u0004Member":["Miembro"],"role\u0004No role":["Sin rol"],"status filter\u0004All":["Todo"],"taxonomy general name\u0004Categories":["Categorías"],"taxonomy singular name\u0004Category":["Categoría"],"theme\u0004Status":["Estado"],"trash\u0004Restore":["Restaurar"],"unit symbol\u0004B":["B"],"unit symbol\u0004EB":["EB"],"unit symbol\u0004GB":["GB"],"unit symbol\u0004KB":["KB"],"unit symbol\u0004MB":["MB"],"unit symbol\u0004PB":["PB"],"unit symbol\u0004TB":["TB"],"unit symbol\u0004YB":["YB"],"unit symbol\u0004ZB":["ZB"],"v%(version)s":["v%(version)s"],"verb\u0004Trash…":["Papelera…"],"verb\u0004View":["Ver"],"{day} {month} {year}":["{day} de {month} de {year}"]} diff --git a/internal/i18n/catalogs/fr-FR.json b/internal/i18n/catalogs/fr-FR.json index 89c8e8dd..2d9e2579 100644 --- a/internal/i18n/catalogs/fr-FR.json +++ b/internal/i18n/catalogs/fr-FR.json @@ -1 +1 @@ -{"":{"lang":"fr","plural-forms":"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"}," and ":[" et "]," or ":[" ou "],"\"%s\" activated.":["Type de contenu « %s » activé."],"\"%s\" deactivated.":["Type de contenu « %s » désactivé."],"\"%s\" has been restored.":["« %s » a été rétabli."],"\"%s\" moved to the trash.":["« %s » déplacé dans la corbeille."],"\"%s\" permanently deleted.":["Suppression définitive de « %s »."],"\"%s\" successfully created.":["« %s » créé avec succès."],"\"%s\" uploaded.":["« %s » téléversé."],"%(field)s address":["Adresse de %(field)s"],"%(field)s cannot move inside itself. Pick a container that is not one of its own.":["%(field)s ne peut pas être déplacé à l'intérieur de lui-même. Choisissez un conteneur qui n'est pas l'un des siens."],"%(field)s declared.":["%(field)s déclaré."],"%(field)s deleted.":["%(field)s supprimé."],"%(field)s does not match the format its field asks for. Check it and save again.":["%(field)s ne respecte pas le format demandé par son champ. Vérifiez-le et enregistrez de nouveau."],"%(field)s goes no higher than %(limit)s. Lower the value and save again.":["%(field)s ne dépasse pas %(limit)s. Baissez la valeur et enregistrez de nouveau."],"%(field)s goes no lower than %(limit)s. Raise the value and save again.":["%(field)s ne descend pas sous %(limit)s. Augmentez la valeur et enregistrez de nouveau."],"%(field)s holds no value of its own, so it cannot be required. Make it optional.":["%(field)s ne contient aucune valeur propre, il ne peut donc pas être obligatoire. Rendez-le facultatif."],"%(field)s is optional again.":["%(field)s est de nouveau facultatif."],"%(field)s is required now.":["%(field)s est maintenant obligatoire."],"%(field)s moved.":["%(field)s déplacé."],"%(field)s names the same one twice. Remove the repeat and save again.":["%(field)s nomme le même deux fois. Retirez la répétition et enregistrez de nouveau."],"%(field)s needs at least %(limit)s files. Add one and save again.":["%(field)s demande au moins %(limit)s fichiers. Ajoutez-en un et enregistrez."],"%(field)s needs at least %(limit)s rows. Add one and save again.":["%(field)s demande au moins %(limit)s lignes. Ajoutez-en une et enregistrez."],"%(field)s only takes one of its listed choices. Pick one and save again.":["%(field)s accepte uniquement un des choix de sa liste. Choisissez-en un et enregistrez de nouveau."],"%(field)s reads a relation field that is not there. Pick a group and a relation field it holds.":["%(field)s lit un champ de relation qui n'existe pas. Choisissez un groupe et un champ de relation qu'il contient."],"%(field)s reads a relation pointing at %(type)s, so it would list nothing here. Pick a relation pointing at the items this group is shown on.":["%(field)s lit une relation qui pointe vers %(type)s, elle n'afficherait donc rien ici. Choisissez une relation qui pointe vers les éléments où ce groupe s'affiche."],"%(field)s renamed.":["%(field)s renommé."],"%(field)s settled.":["%(field)s réglé."],"%(field)s shows by its rules now.":["%(field)s s'affiche désormais selon ses règles."],"%(field)s stands in the list.":["%(field)s figure dans la liste."],"%(field)s stays out of the list.":["%(field)s reste hors de la liste."],"%(field)s takes at most %(limit)s files. Remove one and save again.":["%(field)s accepte au plus %(limit)s fichiers. Retirez-en un et enregistrez."],"%(field)s takes at most %(limit)s letters. Shorten what you wrote and save again.":["%(field)s accepte au plus %(limit)s lettres. Raccourcissez ce que vous avez écrit et enregistrez de nouveau."],"%(field)s takes at most %(limit)s rows. Remove one and save again.":["%(field)s accepte au plus %(limit)s lignes. Retirez-en une et enregistrez."],"%(field)s title":["Titre de %(field)s"],"%(file)s is larger than one upload may be.":["%(file)s dépasse la taille maximale d'un téléversement."],"%(file)s is not a file this block accepts.":["%(file)s n'est pas un fichier que ce bloc accepte."],"%(file)s: %(reason)s":["%(file)s : %(reason)s"],"%(group)s created.":["%(group)s créé."],"%(group)s now appears where you said.":["%(group)s apparaît maintenant là où vous avez dit."],"%(group)s removed.":["%(group)s supprimé."],"%(group)s updated.":["%(group)s mis à jour."],"%(key)s is served by %(winner)s, so %(loser)s does not show it on %(where)s.":["%(key)s est servi par %(winner)s, donc %(loser)s ne le montre pas sur %(where)s."],"%(name)s %(version)s is serving the public site.":["%(name)s %(version)s sert le site public."],"%(name)s belongs to the site now.":["%(name)s appartient désormais au site."],"%(name)s came from the %(plugin)s plugin, which no longer declares it.":["%(name)s venait de l'extension %(plugin)s, qui ne le déclare plus."],"%(name)s cannot be used as a theme name. Name the zip file after the theme, with no dot at the start and no slashes in it.":["%(name)s ne peut pas servir de nom de thème. Nommez le fichier zip comme le thème, sans point au début et sans barre oblique."],"%(name)s moves to /%(word)s. Every address of both types changes.":["Le type %(name)s passe à /%(word)s. Toutes les adresses des deux types changent."],"%(name)s would move to /%(word)s, which Gophenberg keeps for itself. Change its plural name and try again.":["Le type %(name)s passerait à /%(word)s, que Gophenberg garde pour lui. Modifiez son nom au pluriel et réessayez."],"%(source)s is %(value)s":["%(source)s est %(value)s"],"%(theme)s failed to start, so the built-in renderer is serving.":["%(theme)s n'a pas pu démarrer, le moteur de rendu intégré sert donc le site."],"%(theme)s is now serving the public site.":["%(theme)s sert désormais le site public."],"%(theme)s is serving the public site.":["%(theme)s sert le site public."],"%(theme)s is still starting, so the built-in renderer is serving.":["%(theme)s démarre encore, le moteur de rendu intégré sert donc le site."],"%(theme)s was installed.":["%(theme)s a été installé."],"%(theme)s will not load, so the built-in renderer is serving.":["%(theme)s ne se charge pas, le moteur de rendu intégré sert donc le site."],"%(type)s answers on a new address, and stored links move with it.":["%(type)s répond à une nouvelle adresse, et les liens enregistrés la suivent."],"%(type)s becomes the type the site opens on, and the old one takes an address.":["%(type)s devient le type sur lequel le site ouvre, et l'ancien prend une adresse."],"%(type)s keeps nesting while %(items)s of its items sit inside another. Move those to the top level first, the ones in the trash included.":["%(type)s continue de s'imbriquer tant que %(items)s de ses éléments se trouvent dans un autre. Déplacez-les d'abord au niveau supérieur, ceux de la corbeille compris."],"%(type)s keeps nesting, because some of its items sit inside another.":["%(type)s continue de s'imbriquer, car certains de ses éléments se trouvent dans un autre."],"%(type)s will answer at the root.":["Le type %(type)s répondra à la racine."],"%s content type activated.":["%s type de contenu activé.","%s types de contenu activés.","%s types de contenu activés."],"%s content type could not be activated.":["%s type de contenu n'a pas pu être activé.","%s types de contenu n'ont pas pu être activés.","%s types de contenu n'ont pas pu être activés."],"%s content type could not be deactivated.":["%s type de contenu n'a pas pu être désactivé.","%s types de contenu n'ont pas pu être désactivés.","%s types de contenu n'ont pas pu être désactivés."],"%s content type could not be permanently deleted.":["%s type de contenu n'a pas pu être supprimé définitivement.","%s types de contenu n'ont pas pu être supprimés définitivement.","%s types de contenu n'ont pas pu être supprimés définitivement."],"%s content type deactivated.":["%s type de contenu désactivé.","%s types de contenu désactivés.","%s types de contenu désactivés."],"%s content type permanently deleted.":["%s type de contenu supprimé définitivement.","%s types de contenu supprimés définitivement.","%s types de contenu supprimés définitivement."],"%s item could not be moved to the trash.":["%s élément n'a pas pu être déplacé dans la corbeille.","%s éléments n'ont pas pu être déplacés dans la corbeille.","%s éléments n'ont pas pu être déplacés dans la corbeille."],"%s item could not be permanently deleted.":["%s élément n'a pas pu être supprimé définitivement.","%s éléments n'ont pas pu être supprimés définitivement.","%s éléments n'ont pas pu être supprimés définitivement."],"%s item could not be restored.":["%s élément n'a pas pu être rétabli.","%s éléments n'ont pas pu être rétablis.","%s éléments n'ont pas pu être rétablis."],"%s item moved to the trash.":["%s élément déplacé dans la corbeille.","%s éléments déplacés dans la corbeille.","%s éléments déplacés dans la corbeille."],"%s item permanently deleted.":["%s élément supprimé définitivement.","%s éléments supprimés définitivement.","%s éléments supprimés définitivement."],"%s item stays in the trash.":["%s élément reste dans la corbeille.","%s éléments restent dans la corbeille.","%s éléments restent dans la corbeille."],"%s page has been restored.":["%s page a été rétablie.","%s pages ont été rétablies.","%s pages ont été rétablies."],"%s post has been restored.":["%s article a été rétabli.","%s articles ont été rétablis.","%s articles ont été rétablis."],"(no title)":["(pas de titre)"],"A %(kind)s field does not take a setting called %(setting)s. Remove it and try again.":["Un champ %(kind)s n'accepte pas de réglage nommé %(setting)s. Retirez-le et réessayez."],"A Linked from field stands on its own, not inside a section or a repeater. Declare %(field)s beside the container.":["Un champ Lié depuis se place seul, ni dans une section ni dans un répéteur. Déclarez %(field)s à côté du conteneur."],"A content type needs a singular and a plural name, like Guide and Guides. Fill both in and try again.":["Un type de contenu a besoin d'un nom au singulier et d'un nom au pluriel, comme Guide et Guides. Remplissez les deux et réessayez."],"A descriptive summary of the content type.":["Un résumé descriptif du type de contenu."],"A field group key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Rename the group in the file so its key comes out in that shape.":["La clé d'un groupe de champs doit commencer par une lettre minuscule puis ne contenir que des lettres minuscules, des chiffres et des tirets. Renommez le groupe dans le fichier pour que sa clé prenne cette forme."],"A field key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Rename the field so its key comes out in that shape.":["La clé d'un champ doit commencer par une lettre minuscule et ne contenir ensuite que des lettres minuscules, des chiffres et des tirets. Renommez le champ pour que sa clé prenne cette forme."],"A field needs a name. Type one and try again.":["Un champ a besoin d'un nom. Saisissez-en un et réessayez."],"A field with that name already exists on the items this group reaches. Pick another name.":["Un champ portant ce nom existe déjà sur les éléments que ce groupe atteint. Choisissez un autre nom."],"A flexible content field holds layouts, and %(field)s is not one. Add a layout first, then declare the field inside that layout.":["Un champ de contenu flexible contient des dispositions, et %(field)s n'en est pas une. Ajoutez d'abord une disposition, puis déclarez le champ dans cette disposition."],"A higher quality stores larger files, and it applies to pictures uploaded from now on.":["Une qualité plus élevée stocke des fichiers plus grands, et elle s'applique aux images téléversées à partir de maintenant."],"A layout stands inside a flexible content field only. Put %(field)s inside one of those instead.":["Une disposition ne se place que dans un champ de contenu flexible. Placez %(field)s dans l'un d'eux."],"A layout stands inside a flexible content field, never on its own. Declare a flexible content field first, then add %(field)s inside it.":["Une disposition se place dans un champ de contenu flexible, jamais seule. Déclarez d'abord un champ de contenu flexible, puis ajoutez %(field)s dedans."],"A listing carries between 1 and %(max)s items, so %(value)s is not a size Gophenberg takes. Pick a number inside that range.":["Une liste affiche entre 1 et %(max)s éléments, donc %(value)s n'est pas une taille que Gophenberg accepte. Choisissez un nombre dans cet intervalle."],"A relation field has to say which content type it points at. Pick that type and try again.":["Un champ de relation doit indiquer le type de contenu qu'il vise. Choisissez ce type et réessayez."],"A reload shows the admin in the language you chose.":["Un rechargement affiche l'administration dans la langue que vous avez choisie."],"A route word has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Change it and try again.":["Un mot de route doit commencer par une lettre minuscule et ne contenir ensuite que des lettres minuscules, des chiffres et des tirets. Modifiez-le et réessayez."],"A row of %(field)s has to name the layout it takes. Pick a layout for the row, or remove the row.":["Une ligne de %(field)s doit nommer la disposition qu'elle prend. Choisissez une disposition pour la ligne, ou retirez la ligne."],"A row of %(field)s takes one layout and no more. Reload the page and build the row again.":["Une ligne de %(field)s prend une seule disposition. Rechargez la page et reconstruisez la ligne."],"A rule matching any %(source)s cannot be turned into an exclusion. Leave it as is, or name the ones to leave out instead.":["Une règle valable pour n'importe quel %(source)s ne peut pas devenir une exclusion. Laissez-la telle quelle, ou nommez ceux à écarter."],"A theme naming its own page size uses that instead.":["Un thème qui indique sa propre taille de page utilise celle-ci à la place."],"A type key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Change the key and try again.":["La clé d'un type doit commencer par une lettre minuscule et ne contenir ensuite que des lettres minuscules, des chiffres et des tirets. Modifiez la clé et réessayez."],"Actions":["Actions"],"Activate":["Activer"],"Activate %(theme)s":["Activer %(theme)s"],"Active":["Actif"],"Add":["Ajouter"],"Add %(layout)s":["Ajouter %(layout)s"],"Add %(name)s":["Ajouter %(name)s"],"Add %(type)s":["Ajouter %(type)s"],"Add Category":["Ajouter une catégorie"],"Add Content Type":["Ajouter un type de contenu"],"Add Field Group":["Ajouter un groupe de champs"],"Add Media File":["Ajouter un fichier média"],"Add Page":["Ajouter une page"],"Add Post":["Ajouter un article"],"Add User":["Ajouter un utilisateur"],"Add block":["Ajouter un bloc"],"Add choice":["Ajouter un choix"],"Add condition":["Ajouter une condition"],"Add field":["Ajouter un champ"],"Add field to %(field)s":["Ajouter un champ à %(field)s"],"Add layout":["Ajouter une disposition"],"Add layout to %(field)s":["Ajouter une disposition à %(field)s"],"Add one with %(button)s.":["Ajoutez un élément avec %(button)s."],"Add row":["Ajouter une ligne"],"Add rule set":["Ajouter un ensemble de règles"],"Add title":["Ajouter un titre"],"Add to %(field)s":["Ajouter à %(field)s"],"Address":["Adresse"],"Address updated.":["Adresse mise à jour."],"Adopt":["Adopter"],"Allow custom":["Autoriser les valeurs libres"],"Allow empty":["Autoriser le vide"],"Alt text":["Texte alternatif"],"An item cannot point at itself. Pick a different item for %(field)s.":["Un élément ne peut pas se viser lui-même. Choisissez un autre élément pour %(field)s."],"An item cannot sit inside itself, or inside one of the items nested under it. Pick a parent outside this branch.":["Un élément ne peut pas se trouver dans lui-même, ni dans un élément imbriqué sous lui. Choisissez un parent hors de cette branche."],"Another account wrote this, and only its author, an editor or an administrator may change it. You can still read it.":["Un autre compte a écrit ceci, et seuls son auteur, un éditeur ou un administrateur peuvent le modifier. Vous pouvez toujours le lire."],"Another account wrote this, so you are reading it rather than editing it.":["Un autre compte a écrit ceci, alors vous le lisez au lieu de le modifier."],"Another content type already answers under this route word. Pick a different word.":["Un autre type de contenu répond déjà sous ce mot de route. Choisissez un autre mot."],"Another content type already lives at the root of your site, and only one can. Give this type a route word, or hand the root over with Make default.":["Un autre type de contenu occupe déjà la racine de votre site, et un seul le peut. Donnez un mot de route à ce type, ou cédez la racine avec Rendre par défaut."],"Another content type already uses this key. Give this type a different name.":["Un autre type de contenu utilise déjà cette clé. Donnez un autre nom à ce type."],"Another item of this content type already uses that address. Pick a different slug and save again.":["Un autre élément de ce type de contenu utilise déjà cette adresse. Choisissez un autre slug et enregistrez de nouveau."],"Another update is currently in progress.":["Une autre mise à jour est actuellement en cours."],"Appears on":["Apparaît sur"],"Apply":["Appliquer"],"April":["avril"],"Are you sure you want to move \"%s\" to the trash?":["Voulez-vous vraiment déplacer « %s » dans la corbeille ?"],"Audio":["Audio"],"August":["août"],"Author":["Auteur/autrice"],"Back to %(type)s":["Retour aux %(type)s"],"Back to the latest posts":["Retour aux derniers articles"],"Block":["Bloc"],"Broken":["Cassé"],"Bundles of fields, shown where their rules place them.":["Ensembles de champs, affichés là où leurs règles les placent."],"Button group":["Groupe de boutons"],"Cancel":["Annuler"],"Caption":["Légende"],"Change %(name)s":["Modifier %(name)s"],"Change address":["Changer l'adresse"],"Change address…":["Changer l'adresse…"],"Change role":["Changer le rôle"],"Change the role of %(name)s":["Changer le rôle de %(name)s"],"Checkbox group":["Groupe de cases à cocher"],"Choices":["Choix"],"Choose %(field)s":["Choisir %(field)s"],"Choose how the site serves its content.":["Choisissez comment le site sert son contenu."],"Choose the language the admin reads in.":["Choisissez la langue dans laquelle se lit l'administration."],"Choose the role of %(name)s.":["Choisissez le rôle de %(name)s."],"Choose the version to update to.":["Choisissez la version vers laquelle mettre à jour."],"Clear %(field)s":["Vider %(field)s"],"Close":["Fermer"],"Close Settings":["Fermer les réglages"],"Closed":["Fermé"],"Condition":["Condition"],"Content":["Contenu"],"Content Types":["Types de contenu"],"Content nests at most %(max)s levels deep, and this item would sit deeper. Pick a parent closer to the top.":["Le contenu s'imbrique sur au plus %(max)s niveaux, et cet élément irait plus profond. Choisissez un parent plus proche du sommet."],"Content type":["Type de contenu"],"Content type updated.":["Type de contenu mis à jour."],"Could not load that post.":["Impossible de charger cet article."],"Could not save image. %s":["Impossible d’enregistrer le média. %s"],"Could not save media. %s":["Impossible d’enregistrer le média. %s"],"Could not save that post.":["Impossible d'enregistrer cet article."],"Create":["Créer"],"Create a field group":["Créer un groupe de champs"],"Create user":["Créer l'utilisateur"],"Created":["Date de création"],"Date added":["Date d’ajout"],"Date modified":["Date de modification"],"Deactivate":["Désactiver"],"Deactivate %(theme)s":["Désactiver %(theme)s"],"December":["décembre"],"Default":["Par défaut"],"Default content type updated.":["Type de contenu par défaut mis à jour."],"Definitions file":["Fichier de définitions"],"Delete":["Supprimer"],"Delete \"%(title)s\" for good? This cannot be undone.":["Supprimer « %(title)s » définitivement ? Cette action est irréversible."],"Delete %(field)s":["Supprimer %(field)s"],"Delete %(group)s":["Supprimer %(group)s"],"Delete %s content type for good? This cannot be undone.":["Supprimer %s type de contenu définitivement ? Cette action est irréversible.","Supprimer %s types de contenu définitivement ? Cette action est irréversible.","Supprimer %s types de contenu définitivement ? Cette action est irréversible."],"Delete %s item for good? This cannot be undone.":["Supprimer %s élément définitivement ? Cette action est irréversible.","Supprimer %s éléments définitivement ? Cette action est irréversible.","Supprimer %s éléments définitivement ? Cette action est irréversible."],"Delete permanently":["Supprimer définitivement"],"Delete the field":["Supprimer le champ"],"Delete the group":["Supprimer le groupe"],"Delete…":["Supprimer…"],"Describe":["Décrire"],"Describe the purpose of the image.":["Décrivez la fonction de l’image."],"Describe…":["Décrire…"],"Description":["Description"],"Description updated.":["Description mise à jour."],"Desktop":["Ordinateur"],"Destination":["Destination"],"Dimensions":["Dimensions"],"Disable":["Désactiver"],"Disable %(name)s":["Désactiver %(name)s"],"Disabled":["Désactivé"],"Dismiss":["Ignorer"],"Document":["Document"],"Documents":["Documents"],"Done. The site now holds what the file describes.":["Terminé. Le site contient maintenant ce que décrit le fichier."],"Draft saved.":["Brouillon enregistré."],"Drop files to upload":["Déposez vos fichiers pour les téléverser"],"Edit media":["Modifier le média"],"Edit…":["Modifier…"],"Email":["E-mail"],"Empty Trash":["Vider la corbeille"],"Empty trash":["Vider la corbeille"],"Enable":["Activer"],"Enable %(name)s":["Activer %(name)s"],"Every address of this type moves. Links kept elsewhere to the old addresses stop working.":["Toutes les adresses de ce type changent. Les liens conservés ailleurs vers les anciennes adresses cessent de fonctionner."],"Every content type":["Tous les types de contenu"],"Every field group needs a title. Give it a name and save again.":["Chaque groupe de champs a besoin d'un titre. Donnez-lui un nom et enregistrez à nouveau."],"Every item needs an author who exists. Pick one from the list and save again.":["Chaque élément a besoin d'un auteur existant. Choisissez-en un dans la liste et enregistrez de nouveau."],"Every kind of content this site holds.":["Toutes les sortes de contenu que ce site contient."],"Every value stored under this field goes with it, in every item the group reaches and in the revisions behind them.":["Toutes les valeurs enregistrées dans ce champ partent avec lui, dans chaque élément que le groupe atteint et dans les révisions qui les suivent."],"Excerpt":["Extrait"],"Export definitions":["Exporter les définitions"],"February":["février"],"Fewest files":["Minimum de fichiers"],"Fewest rows":["Minimum de lignes"],"Field":["Champ"],"Field Groups":["Groupes de champs"],"Field group":["Groupe de champs"],"Fields":["Champs"],"Fields of %(group)s":["Champs de %(group)s"],"File name":["Nom de fichier"],"File size":["Taille du fichier"],"File type":["Type de fichier"],"Filter by status":["Filtrer par état"],"Follow the browser":["Suivre le navigateur"],"From %(plugin)s":["De %(plugin)s"],"Full Size":["Taille originale"],"Gophenberg cannot start this update: %(reason)s":["Gophenberg ne peut pas lancer cette mise à jour : %(reason)s"],"Gophenberg checked for updates moments ago. Try again later.":["Gophenberg a cherché des mises à jour il y a un instant. Réessayez plus tard."],"Gophenberg could not read what your browser sent. Reload the page and try again, and tell whoever looks after your site if it keeps happening.":["Gophenberg n'a pas pu lire ce que votre navigateur a envoyé. Rechargez la page et réessayez, et prévenez la personne qui s'occupe de votre site si cela continue."],"Gophenberg could not read which item you picked as parent. Reload the page and pick it again.":["Gophenberg n'a pas pu lire quel élément vous avez choisi comme parent. Rechargez la page et choisissez-le de nouveau."],"Gophenberg does not accept %(extension)s files. Upload a picture, a video, an audio file, a PDF or a zip instead.":["Gophenberg n'accepte pas les fichiers %(extension)s. Téléversez plutôt une image, une vidéo, un fichier audio, un PDF ou un zip."],"Gophenberg does not answer in %(value)s. Pick one of the languages on the list.":["Gophenberg ne répond pas en %(value)s. Choisissez une des langues de la liste."],"Gophenberg has no autosave of yours for this item. Open the item to see the version that is stored.":["Gophenberg n'a aucun enregistrement automatique de vous pour cet élément. Ouvrez l'élément pour voir la version stockée."],"Gophenberg holds no kind of definition called %(subject)s, so nothing was taken over. Reload the page so the admin and the server agree again.":["Gophenberg ne connaît aucune sorte de définition nommée %(subject)s, rien n'a donc été repris. Rechargez la page pour que l'admin et le serveur se rejoignent à nouveau."],"Gophenberg keeps /%(path)s for itself or for another content type, so your content cannot answer there. Give the item a different slug.":["Gophenberg garde l'adresse /%(path)s pour lui ou pour un autre type de contenu, votre contenu ne peut donc pas y répondre. Donnez un autre slug à l'élément."],"Gophenberg keeps this word for itself, so no content type can answer under it. Pick a different route word.":["Gophenberg garde ce mot pour lui, aucun type de contenu ne peut donc répondre sous ce mot. Choisissez un autre mot de route."],"Group":["Groupe"],"Highest":["Maximum"],"Holds":["Contient"],"Images":["Images"],"Import definitions":["Importer les définitions"],"In list":["Dans la liste"],"Inactive":["Inactif"],"Installed":["Installé"],"Instructions":["Instructions"],"It moves here from another group and keeps its stored values.":["Il arrive ici depuis un autre groupe et garde ses valeurs enregistrées."],"It moves to another group and keeps its stored values.":["Il passe dans un autre groupe et garde ses valeurs enregistrées."],"It moves to another group, so its stored values do not follow.":["Il passe dans un autre groupe, donc ses valeurs enregistrées ne le suivent pas."],"It reads a relation inside a container, and only an import can point it elsewhere.":["Il lit une relation dans un conteneur, et seule une importation peut le faire pointer ailleurs."],"It starts on %(type)s, and the rules may be edited afterwards.":["Il commence sur %(type)s, et les règles peuvent être modifiées ensuite."],"Items could not be loaded.":["Les éléments n'ont pas pu être chargés."],"Its items sit inside one another, so it keeps nesting.":["Ses éléments se trouvent les uns dans les autres, donc il continue de s'imbriquer."],"Its kind changed, so its stored values go with it.":["Son type a changé, donc ses valeurs enregistrées partent avec lui."],"January":["janvier"],"July":["juillet"],"June":["juin"],"Keep %(field)s out of the list":["Garder %(field)s hors de la liste"],"Keep it":["Le conserver"],"Keep it here":["Le laisser ici"],"Key":["Clé"],"Label":["Libellé"],"Language":["Langue"],"Large":["Grande"],"Leave empty if decorative.":["Laissez vide si l’image est décorative"],"Let items nest":["Autoriser l'imbrication"],"Linked from":["Lié depuis"],"List view":["Vue en liste"],"Loading field groups.":["Chargement des groupes de champs."],"Loading the post.":["Chargement de l'article."],"Loading the screen.":["Chargement de l'écran."],"Loading themes.":["Chargement des thèmes."],"Loading users.":["Chargement des utilisateurs."],"Loading…":["Chargement…"],"Longest":["Longueur maximale"],"Lowest":["Minimum"],"Make %(field)s optional":["Rendre %(field)s facultatif"],"Make default":["Rendre par défaut"],"Make default…":["Rendre par défaut…"],"Make optional":["Rendre facultatif"],"Manage the categories on this site.":["Gérez les catégories de ce site."],"Manage the images and files this site holds.":["Gérez les images et les fichiers que ce site contient."],"Manage the items of this content type.":["Gérez les éléments de ce type de contenu."],"Manage the pages on this site.":["Gérez les pages de ce site."],"Manage the posts on this site.":["Gérez les articles de ce site."],"Many targets":["Plusieurs cibles"],"Many values":["Plusieurs valeurs"],"March":["mars"],"May":["mai"],"Media %(id)s":["Média %(id)s"],"Media Library":["Médiathèque"],"Media file updated.":["Fichier média mis à jour."],"Medium":["Moyenne"],"Mobile":["Mobile"],"Modified: %s":["Modifié : %s"],"Most files":["Maximum de fichiers"],"Most rows":["Maximum de lignes"],"Move":["Déplacer"],"Move \"%(title)s\" to the trash?":["Déplacer « %(title)s » dans la corbeille ?"],"Move %(field)s down":["Descendre %(field)s"],"Move %(field)s elsewhere":["Déplacer %(field)s ailleurs"],"Move %(field)s up":["Monter %(field)s"],"Move %(group)s down":["Descendre %(group)s"],"Move %(group)s up":["Monter %(group)s"],"Move %(name)s down":["Descendre %(name)s"],"Move %(name)s up":["Monter %(name)s"],"Move %s item to the trash?":["Déplacer %s élément dans la corbeille ?","Déplacer %s éléments dans la corbeille ?","Déplacer %s éléments dans la corbeille ?"],"Move every address":["Déplacer toutes les adresses"],"Move row down":["Descendre la ligne"],"Move row up":["Monter la ligne"],"Move the field":["Déplacer le champ"],"Move to trash":["Déplacer dans la corbeille"],"Name":["Nom"],"Name updated.":["Nom mis à jour."],"Nests":["Imbriqué"],"Newer posts":["Articles plus récents"],"No":["Non"],"No content types found.":["Aucun type de contenu trouvé."],"No description":["Aucune description"],"No file arrived with this upload. Choose a file and try again.":["Aucun fichier n'est arrivé avec ce téléversement. Choisissez un fichier et réessayez."],"No items found.":["Aucun élément trouvé."],"No items yet.":["Aucun élément pour l'instant."],"No media chosen":["Aucun média choisi"],"No media has been uploaded yet.":["Aucun média n'a encore été téléversé."],"No media items found.":["Aucun média n’a été trouvé."],"No media items yet.":["Aucun fichier média pour l’instant."],"No page lives at this address.":["Aucune page n'existe à cette adresse."],"No parent":["Pas de parent"],"No theme arrived with this upload. Choose a zip file and try again.":["Aucun thème n'est arrivé avec ce téléversement. Choisissez un fichier zip et réessayez."],"No themes are installed.":["Aucun thème n'est installé."],"No title":["Aucun titre"],"None":["Aucun"],"Not %(type)s":["Sauf %(type)s"],"Not found":["Introuvable"],"Not serving":["Hors service"],"Nothing declares that role.":["Rien ne déclare ce rôle."],"Nothing points here yet.":["Rien ne pointe encore ici."],"Nothing published here yet.":["Rien n'est encore publié ici."],"Nothing published yet.":["Rien n'est encore publié."],"November":["novembre"],"Nowhere":["Nulle part"],"Number":["Nombre"],"October":["octobre"],"Older posts":["Articles plus anciens"],"One frame of this animation holds more than %(max)s pixels, which is more than Gophenberg opens. Upload a smaller animation.":["Une image de cette animation dépasse %(max)s pixels, plus que ce que Gophenberg ouvre. Téléversez une animation plus petite."],"One of the filters on this list is not one Gophenberg understands. Clear the filters and try again.":["Un des filtres de cette liste n'est pas un filtre que Gophenberg comprend. Videz les filtres et réessayez."],"One of the items picked for %(field)s is not the kind of content that field points at. Reload the page and pick from the list the field offers.":["Un des éléments choisis pour %(field)s n'est pas le genre de contenu que vise ce champ. Rechargez la page et choisissez dans la liste que le champ propose."],"One of the items picked for %(field)s was not named in a way Gophenberg understands. Reload the page and pick the items again.":["Un des éléments choisis pour %(field)s n'était pas nommé d'une façon que Gophenberg comprend. Rechargez la page et choisissez de nouveau les éléments."],"One of the items picked no longer exists. Reload the page and pick again.":["Un des éléments choisis n'existe plus. Rechargez la page et choisissez de nouveau."],"One target":["Une cible"],"Only a relation field points at another content type or holds many items. Pick the Relation kind, or leave the target and the many option empty.":["Seul un champ de relation vise un autre type de contenu ou contient plusieurs éléments. Choisissez le genre Relation, ou laissez vides la cible et l'option plusieurs."],"Only one file may be placed here.":["Un seul fichier peut être placé ici."],"Only the content type at the root of your site may go without a route word. Give this type one and try again.":["Seul le type de contenu à la racine de votre site peut se passer de mot de route. Donnez-en un à ce type et réessayez."],"Open %(field)s in a new tab":["Ouvrir %(field)s dans un nouvel onglet"],"Order stored.":["Ordre enregistré."],"Other":["Autre"],"Out of list":["Hors de la liste"],"Parent":["Parent"],"Password":["Mot de passe"],"Pending":["En attente"],"Pending Review":["En attente de relecture"],"Permanently delete…":["Supprimer définitivement…"],"Picture quality":["Qualité d'image"],"Picture quality runs from 1 to %(max)s, so %(value)s is not a quality Gophenberg stores at. Pick a number inside that range.":["La qualité d'image va de 1 à %(max)s, donc %(value)s n'est pas une qualité avec laquelle Gophenberg enregistre. Choisissez un nombre dans cet intervalle."],"Placeholder":["Texte indicatif"],"Plural name":["Nom au pluriel"],"Points at":["Vise"],"Post published.":["Article publié."],"Posts per page":["Articles par page"],"Preview":["Prévisualiser"],"Private":["Privé"],"Publish":["Publier"],"Published: %s":["Publié : %s"],"Radio group":["Groupe de boutons radio"],"Reads from":["Lit depuis"],"Redo":["Rétablir"],"Relation":["Relation"],"Remove":["Retirer"],"Remove %(name)s":["Retirer %(name)s"],"Remove %(title)s":["Retirer %(title)s"],"Remove row":["Retirer la ligne"],"Rename":["Renommer"],"Rename %(field)s":["Renommer %(field)s"],"Rename…":["Renommer…"],"Require":["Rendre obligatoire"],"Require %(field)s":["Rendre %(field)s obligatoire"],"Required":["Obligatoire"],"Restore":["Rétablir"],"Role changed.":["Rôle modifié."],"Roll back to %(theme)s":["Revenir à %(theme)s"],"Roll back to the built-in renderer":["Revenir au moteur de rendu intégré"],"Route word":["Mot de route"],"Rule %(number)s of set %(set)s":["Règle %(number)s de l'ensemble %(set)s"],"Rule set %(number)s":["Ensemble de règles %(number)s"],"Rules":["Règles"],"Rules showing %(field)s":["Règles affichant %(field)s"],"Save":["Enregistrer"],"Save draft":["Enregistrer le brouillon"],"Save rules":["Enregistrer les règles"],"Save settings":["Enregistrer les réglages"],"Saved":["Enregistré"],"Saving":["Enregistrement"],"Scheduled":["Planifié"],"Scheduled: %s":["Planifié : %s"],"Search %(type)s…":["Rechercher des %(type)s…"],"Search audio":["Rechercher un audio"],"Search images":["Rechercher des images"],"Search media":["Rechercher des médias"],"Search videos":["Rechercher des vidéos"],"Select":["Sélectionner"],"September":["septembre"],"Serving":["En service"],"Settings":["Réglages"],"Settings of %(field)s":["Réglages de %(field)s"],"Shadowed":["Masqué"],"Show %(field)s in the list":["Afficher %(field)s dans la liste"],"Showing %(held)s of %(total)s.":["Affichage de %(held)s sur %(total)s."],"Singular name":["Nom au singulier"],"Slug":["Slug"],"Somebody must be able to manage users.":["Quelqu'un doit pouvoir gérer les utilisateurs."],"Someone else changed this media item while you were editing it. Reload the page and make your change again.":["Quelqu'un d'autre a modifié ce média pendant que vous le modifiiez. Rechargez la page et refaites votre modification."],"Someone else saved changes to this item while you were editing, so yours were not saved. Copy your text somewhere safe, then reload the item and put your changes back in.":["Quelqu'un d'autre a enregistré des modifications sur cet élément pendant que vous éditiez, les vôtres n'ont donc pas été enregistrées. Copiez votre texte en lieu sûr, puis rechargez l'élément et remettez vos modifications."],"Something went wrong inside Gophenberg. Try again in a moment, and tell whoever looks after your site if it keeps happening.":["Quelque chose a mal tourné dans Gophenberg. Réessayez dans un instant, et prévenez la personne qui s'occupe de votre site si cela continue."],"Something went wrong.":["Quelque chose a mal tourné."],"Something went wrong. Try again.":["Quelque chose a mal tourné. Réessayez."],"Sorry, you are not allowed to access this page.":["Désolé, vous n’avez pas l’autorisation d’accéder à cette page."],"Source":["Source"],"Steps of":["Pas de"],"Stop nesting":["Arrêter l'imbrication"],"Tablet":["Tablette"],"Text":["Texte"],"Text area":["Zone de texte"],"That email is already in use.":["Cet e-mail est déjà utilisé."],"That field group no longer exists. Reload the page to see the groups your site holds now.":["Ce groupe de champs n'existe plus. Rechargez la page pour voir les groupes que votre site contient maintenant."],"That field is not on this content type any more. Reload the page to see the fields it has now.":["Ce champ n'est plus sur ce type de contenu. Rechargez la page pour voir les champs qu'il possède maintenant."],"That revision does not exist, and older ones drop off once a type holds more than it keeps. Open the item to see which revisions are left.":["Cette révision n'existe pas, et les plus anciennes disparaissent quand un type en détient plus qu'il n'en conserve. Ouvrez l'élément pour voir les révisions restantes."],"That role holds more than your own.":["Ce rôle va au-delà du vôtre."],"That web address does not name a media item Gophenberg can look up. Open the media library and pick the item from there.":["Cette adresse web ne désigne aucun média que Gophenberg puisse trouver. Ouvrez la bibliothèque de médias et choisissez l'élément depuis là."],"That web address does not name a revision Gophenberg can look up. Open the item and pick a revision from its history.":["Cette adresse web ne désigne aucune révision que Gophenberg puisse trouver. Ouvrez l'élément et choisissez une révision dans son historique."],"That web address does not name an item Gophenberg can look up. Go back to the list and open the item from there.":["Cette adresse web ne désigne aucun élément que Gophenberg puisse trouver. Revenez à la liste et ouvrez l'élément depuis là."],"The %(count)s item in the trash is deleted for good. This cannot be undone.":["%(count)s élément de la corbeille est supprimé définitivement. Cette action est irréversible.","Les %(count)s éléments de la corbeille sont supprimés définitivement. Cette action est irréversible.","Les %(count)s éléments de la corbeille sont supprimés définitivement. Cette action est irréversible."],"The %(file)s calls this theme %(declared)s, but it is being installed as %(installed)s. Rename the zip file to match, or change the name inside %(file)s.":["Le fichier %(file)s appelle ce thème %(declared)s, mais il s'installe sous %(installed)s. Renommez le fichier zip pour qu'ils correspondent, ou changez le nom dans %(file)s."],"The %(file)s inside %(name)s is not valid JSON, so it could not be read. Fix that file and package the theme again.":["Le fichier %(file)s dans %(name)s n'est pas du JSON valide, il n'a donc pas pu être lu. Corrigez ce fichier et réempaquetez le thème."],"The %(file)s inside %(name)s names its theme kit as %(declared)s, which is not a version number. Build the theme again, and the build will fill that in.":["Le %(file)s dans %(name)s indique son kit de thèmes comme %(declared)s, ce qui n'est pas un numéro de version. Compilez le thème à nouveau et la compilation le renseignera."],"The %(origin)s plugin declared this, so it can only be changed in that plugin. Turning it off is still yours to do.":["L'extension %(origin)s l'a déclaré, donc il ne peut être modifié que dans cette extension. Le désactiver reste entre vos mains."],"The %(plugin)s plugin also declares %(name)s, and the site keeps the key.":["L'extension %(plugin)s déclare aussi %(name)s, et le site garde la clé."],"The %(plugin)s plugin declared these fields, so they change only in its code.":["L'extension %(plugin)s a déclaré ces champs, donc ils ne changent que dans son code."],"The %(plugin)s plugin declares %(name)s flat, and the site keeps it nesting while its items sit inside another.":["L'extension %(plugin)s déclare %(name)s sans imbrication, et le site continue de l'imbriquer tant que ses éléments se trouvent dans un autre."],"The browser kept an unsaved version of this post.":["Le navigateur a gardé une version non enregistrée de cet article."],"The built-in renderer is now serving the public site.":["Le moteur de rendu intégré sert désormais le site public."],"The built-in renderer is serving the public site.":["Le moteur de rendu intégré sert le site public."],"The content type this field points at is not named in a shape Gophenberg accepts. Give it a key that starts with a lowercase letter and then holds only lowercase letters, numbers and hyphens.":["Le type de contenu que vise ce champ n'est pas nommé sous une forme que Gophenberg accepte. Donnez-lui une clé qui commence par une lettre minuscule et ne contient ensuite que des lettres minuscules, des chiffres et des tirets."],"The content types could not be loaded, so where these groups appear and which fields they shadow are not shown.":["Les types de contenu n'ont pas pu être chargés, donc où ces groupes apparaissent et quels champs ils masquent ne sont pas affichés."],"The content types could not be loaded.":["Les types de contenu n'ont pas pu être chargés."],"The content types could not be refreshed, so where these groups appear and what they shadow may be out of date.":["Les types de contenu n'ont pas pu être actualisés, donc où ces groupes apparaissent et ce qu'ils masquent peut être obsolète."],"The draft could not be created.":["Le brouillon n'a pas pu être créé."],"The entry %(entry)s in this zip would be written outside the theme folder, so nothing was installed. Package the theme again.":["L'entrée %(entry)s de ce zip s'écrirait hors du dossier du thème, rien n'a donc été installé. Réempaquetez le thème."],"The field %(field)s cannot go, because %(by)s reads it. Change %(by)s first.":["Le champ %(field)s ne peut pas être retiré, car %(by)s le lit. Modifiez d'abord %(by)s."],"The field %(field)s cannot hold the value it was given. Check what kind of field it is and enter a value that matches.":["Le champ %(field)s ne peut pas contenir la valeur qui lui a été donnée. Vérifiez de quel genre de champ il s'agit et saisissez une valeur qui convient."],"The field %(field)s has to hold a value before this item can be published. Fill it in, or leave the item as a draft.":["Le champ %(field)s doit contenir une valeur avant que cet élément puisse être publié. Remplissez-le, ou laissez l'élément en brouillon."],"The field %(field)s in %(group)s still points at this content type. Delete that field first, then delete this type.":["Le champ %(field)s dans %(group)s vise encore ce type de contenu. Supprimez d'abord ce champ, puis supprimez ce type."],"The field %(field)s is hidden by its own rules right now, so it cannot hold a value. Show it again before filling it in.":["Le champ %(field)s est masqué par ses propres règles pour le moment, il ne peut donc contenir aucune valeur. Affichez-le de nouveau avant de le remplir."],"The field %(field)s points at one item only. Remove the extra choices and keep one.":["Le champ %(field)s ne vise qu'un seul élément. Retirez les choix en trop et gardez-en un."],"The field %(field)s points at other items, so it does not take a plain value. Pick the items it points at instead.":["Le champ %(field)s vise d'autres éléments, il n'accepte donc pas une valeur simple. Choisissez plutôt les éléments qu'il vise."],"The field %(field)s takes a list of items, and what arrived was not a list. Reload the page and pick the items again.":["Le champ %(field)s attend une liste d'éléments, et ce qui est arrivé n'était pas une liste. Rechargez la page et choisissez de nouveau les éléments."],"The field %(source)s cannot hold the value %(value)s, so no rule can compare it. Write a value of the kind %(source)s stores.":["Le champ %(source)s ne peut pas contenir la valeur %(value)s, aucune règle ne peut donc la comparer. Écrivez une valeur du type que %(source)s enregistre."],"The field groups could not be loaded.":["Les groupes de champs n'ont pas pu être chargés."],"The field groups could not be reached.":["Les groupes de champs n'ont pas pu être joints."],"The field keeps its values on the content both groups reach.":["Le champ garde ses valeurs sur le contenu que les deux groupes atteignent."],"The fields this group holds go with it, and so do the values every item stored in them.":["Les champs que ce groupe contient partent avec lui, ainsi que les valeurs que chaque élément y a enregistrées."],"The groups were reordered.":["Les groupes ont été réordonnés."],"The item could not be duplicated.":["L'élément n'a pas pu être dupliqué."],"The item could not be moved to the trash.":["L'élément n'a pas pu être déplacé dans la corbeille."],"The item could not be permanently deleted.":["L'élément n'a pas pu être supprimé définitivement."],"The item could not be restored.":["L'élément n'a pas pu être rétabli."],"The item you picked as parent holds another kind of content. Pick a parent of the same content type as this item.":["L'élément que vous avez choisi comme parent contient un autre genre de contenu. Choisissez un parent du même type de contenu que cet élément."],"The item you picked as parent is in the trash. Restore it, or pick another parent.":["L'élément que vous avez choisi comme parent est dans la corbeille. Rétablissez-le, ou choisissez un autre parent."],"The item you picked as parent no longer exists. Reload the page and pick another parent.":["L'élément que vous avez choisi comme parent n'existe plus. Rechargez la page et choisissez un autre parent."],"The media library could not be loaded.":["La bibliothèque de médias n'a pas pu être chargée."],"The name changes. Nothing stored under this field moves.":["Le nom change. Rien de ce qui est stocké sous ce champ ne bouge."],"The name could not be updated.":["Le nom n'a pas pu être mis à jour."],"The new order has to name every field group exactly once. Reload the page and move the groups again.":["Le nouvel ordre doit nommer chaque groupe de champs exactement une fois. Rechargez la page et déplacez les groupes à nouveau."],"The new order has to name every field of this content type exactly once. Reload the page and move the fields again.":["Le nouvel ordre doit nommer chaque champ de ce type de contenu exactement une fois. Rechargez la page et déplacez les champs à nouveau."],"The number of revisions to keep has to be a whole number, and it cannot be negative. Enter a different number.":["Le nombre de révisions à conserver doit être un nombre entier, et il ne peut pas être négatif. Saisissez un autre nombre."],"The registry could not be reached.":["Le registre n'a pas pu être joint."],"The role could not be changed.":["Le rôle n'a pas pu être modifié."],"The rule on %(source)s names nothing to match. Pick a value, or remove the rule.":["La règle sur %(source)s ne nomme rien à faire correspondre. Choisissez une valeur, ou retirez la règle."],"The rules could not be loaded.":["Les règles n'ont pas pu être chargées."],"The rules on %(field)s lead back to %(field)s itself, so nothing can decide whether to show it. Point one of them at another field.":["Les règles de %(field)s reviennent à %(field)s lui-même, rien ne peut donc décider de l'afficher. Faites pointer l'une d'elles vers un autre champ."],"The same item was picked twice for %(field)s. Pick each item once.":["Le même élément a été choisi deux fois pour %(field)s. Choisissez chaque élément une seule fois."],"The server could not be reached, so nothing was changed.":["Le serveur n'a pas pu être joint, rien n'a donc été changé."],"The server could not be reached, so nothing was saved.":["Le serveur n'a pas pu être joint, rien n'a donc été enregistré."],"The server could not be reached, so nothing was uploaded.":["Le serveur n'a pas pu être joint, rien n'a donc été téléversé."],"The setting %(setting)s cannot hold the value it was given. Check what this setting takes and try again.":["Le réglage %(setting)s ne peut pas contenir la valeur donnée. Vérifiez ce que ce réglage accepte et réessayez."],"The setting %(setting)s falls outside the others. Keep min below max and the default inside the bounds.":["Le réglage %(setting)s sort des autres. Gardez min sous max et la valeur par défaut dans les limites."],"The settings could not be read, so nothing can be changed here yet.":["Les réglages n'ont pas pu être lus, donc rien ne peut encore être modifié ici."],"The site default":["La langue par défaut du site"],"The site may already hold part of this file. Import it again to see what is left.":["Le site contient peut-être déjà une partie de ce fichier. Importez-le à nouveau pour voir ce qu'il reste."],"The source %(source)s does not offer %(operator)s. Pick one of the comparisons it does offer.":["La source %(source)s n'offre pas %(operator)s. Choisissez une des comparaisons qu'elle offre."],"The theme %(name)s carries no %(file)s, so Gophenberg cannot tell what it is. Put that file at the top level of the zip and package the theme again.":["Le thème %(name)s ne contient aucun %(file)s, Gophenberg ne peut donc pas savoir ce que c'est. Placez ce fichier au premier niveau du zip et réempaquetez le thème."],"The theme %(name)s could not be read, so it cannot serve your site. Upload it again, or choose another theme.":["Le thème %(name)s n'a pas pu être lu, il ne peut donc pas servir votre site. Téléversez-le de nouveau, ou choisissez un autre thème."],"The theme %(name)s did not start, so your site is still served by the theme it had. Ask whoever looks after your site to check the server log for what the theme reported.":["Le thème %(name)s n'a pas démarré, votre site est donc toujours servi par le thème qu'il avait. Demandez à la personne qui s'occupe de votre site de regarder ce que le thème a signalé dans le journal du serveur."],"The theme %(name)s does not carry %(path)s as a file, so there is nothing to run. Package the built theme rather than its source.":["Le thème %(name)s ne contient pas %(path)s comme fichier, il n'y a donc rien à exécuter. Empaquetez le thème construit plutôt que sa source."],"The theme %(name)s does not carry %(path)s as a folder, so its styles and scripts are missing. Package the built theme rather than its source.":["Le thème %(name)s ne contient pas %(path)s comme dossier, ses styles et ses scripts manquent donc. Empaquetez le thème construit plutôt que sa source."],"The theme %(name)s holds a link to another file at %(path)s, and a theme may only carry real files. Replace it and package the theme again.":["Le thème %(name)s contient un lien vers un autre fichier à %(path)s, et un thème ne peut contenir que de vrais fichiers. Remplacez-le et réempaquetez le thème."],"The theme %(name)s is serving your site right now, so it cannot be replaced. Deactivate it first, or install this copy under another name.":["Le thème %(name)s sert votre site en ce moment, il ne peut donc pas être remplacé. Désactivez-le d'abord, ou installez cette copie sous un autre nom."],"The theme %(name)s is the one chosen, but it is not installed, so your site is served by the built-in renderer. Upload the theme again, or choose another one.":["Le thème %(name)s est celui choisi, mais il n'est pas installé, votre site est donc servi par le moteur de rendu intégré. Téléversez de nouveau le thème, ou choisissez-en un autre."],"The theme %(name)s was built on theme kit %(declared)s, and this site serves %(served)s. Build the theme again against a kit this site serves, then install it.":["Le thème %(name)s a été compilé avec le kit de thèmes %(declared)s, et ce site sert %(served)s. Compilez le thème à nouveau avec un kit que ce site sert, puis installez-le."],"The trash could not be emptied.":["La corbeille n'a pas pu être vidée."],"The user could not be created.":["L'utilisateur n'a pas pu être créé."],"The values stored under it do not follow.":["Les valeurs enregistrées dessous ne le suivent pas."],"Theme":["Thème"],"Themes":["Thèmes"],"Themes could not be loaded.":["Les thèmes n'ont pas pu être chargés."],"There is no content type called %(value)s. Pick a type your site holds, or register it first.":["Il n'existe aucun type de contenu appelé %(value)s. Choisissez un type que votre site possède, ou déclarez-le d'abord."],"There is no content type called %(value)s. Pick one of the types your site holds and try again.":["Il n'existe aucun type de contenu appelé %(value)s. Choisissez un des types que votre site possède et réessayez."],"There is no kind of field called %(value)s. Pick one of these instead: %(allowed)s.":["Il n'existe aucun genre de champ appelé %(value)s. Choisissez plutôt parmi ceux-ci : %(allowed)s."],"There is no page kind called %(value)s. Pick one of these instead: %(allowed)s.":["Il n'existe aucun genre de page appelé %(value)s. Choisissez plutôt parmi ceux-ci : %(allowed)s."],"There is no status called %(value)s. Pick one of these instead: %(allowed)s.":["Il n'existe aucun état appelé %(value)s. Choisissez plutôt parmi ceux-ci : %(allowed)s."],"There is nothing at this address. Check the link and try again.":["Il n'y a rien à cette adresse. Vérifiez le lien et réessayez."],"There is nothing to roll back to, because your site has not been through a theme change yet. Install a theme first, then a rollback has somewhere to go.":["Il n'y a rien vers quoi revenir, car votre site n'a pas encore changé de thème. Installez d'abord un thème, et le retour aura alors une destination."],"These files could not be read.":["Ces fichiers n'ont pas pu être lus."],"These were left alone, because nobody confirmed losing them.":["Ceux-ci ont été laissés tels quels, car personne n'a confirmé leur perte."],"This content type does not exist any more. Reload the page to see the types your site holds now.":["Ce type de contenu n'existe plus. Rechargez la page pour voir les types que votre site possède maintenant."],"This content type does not nest, so one of its items cannot sit inside another. Mark the type as Nests first.":["Ce type de contenu ne s'imbrique pas, un de ses éléments ne peut donc pas se trouver dans un autre. Marquez d'abord le type comme Imbriqué."],"This content type has no field called %(field)s. Check the name, or declare the field on the type first.":["Ce type de contenu n'a aucun champ appelé %(field)s. Vérifiez le nom, ou déclarez d'abord le champ sur le type."],"This content type is turned off, so its content is not served or edited. Activate it first.":["Ce type de contenu est désactivé, son contenu n'est donc ni servi ni modifié. Activez-le d'abord."],"This content type still holds content, so it cannot be deleted. Move or delete its items first.":["Ce type de contenu contient encore du contenu, il ne peut donc pas être supprimé. Déplacez ou supprimez d'abord ses éléments."],"This definitions file is larger than the %(max)s bytes Gophenberg reads in one request. Split it, or raise the limit your site runs with.":["Ce fichier de définitions dépasse les %(max)s octets que Gophenberg lit en une requête. Divisez-le, ou relevez la limite de votre site."],"This field holds no layouts yet.":["Ce champ ne contient pas encore de dispositions."],"This field would stand inside too many containers. Put it nearer the top and try again.":["Ce champ se trouverait dans trop de conteneurs. Placez-le plus près du niveau supérieur et réessayez."],"This file could not be opened as a zip. Package the theme again and upload the new file.":["Ce fichier n'a pas pu être ouvert comme zip. Réempaquetez le thème et téléversez le nouveau fichier."],"This file is larger than the upload limit. Upload a smaller file.":["Ce fichier dépasse la limite de téléversement. Téléversez un fichier plus petit."],"This file is named %(extension)s but it holds %(detected)s content. Upload it under a name that matches what is inside it.":["Ce fichier est nommé %(extension)s mais il contient du %(detected)s. Téléversez-le sous un nom qui correspond à ce qu'il contient."],"This file matches the site, so there is nothing to change.":["Ce fichier correspond au site, il n'y a donc rien à changer."],"This file says it was written in format %(declared)s, which is not a version Gophenberg can read. Export the definitions again from the site they came from.":["Ce fichier indique le format %(declared)s, qui n'est pas une version que Gophenberg sait lire. Exportez à nouveau les définitions depuis le site d'origine."],"This file was written in format %(declared)s, and this release reads %(served)s. Upgrade the site the file came from, or this one.":["Ce fichier est écrit au format %(declared)s, et cette version lit %(served)s. Mettez à jour le site d'origine du fichier, ou celui-ci."],"This group holds no fields yet.":["Ce groupe ne contient pas encore de champs."],"This install of Gophenberg has no install root, so it updates by hand.":["Cette installation de Gophenberg n'a pas de racine d'installation, elle se met donc à jour à la main."],"This is a custom build of Gophenberg, so it updates by hand.":["Il s'agit d'une version compilée sur mesure de Gophenberg, elle se met donc à jour à la main."],"This item cannot go straight to that status from the one it holds now. Save it as a draft first, then try again.":["Cet élément ne peut pas passer directement à cet état depuis celui qu'il a maintenant. Enregistrez-le d'abord comme brouillon, puis réessayez."],"This item does not exist, and it may have been deleted. Go back to the list to see what is there.":["Cet élément n'existe pas, et il a peut-être été supprimé. Revenez à la liste pour voir ce qui s'y trouve."],"This item is already in the trash. Restore it first to work on it again.":["Cet élément est déjà dans la corbeille. Rétablissez-le d'abord pour y retravailler."],"This item is in the trash. Restore it first to work on it again.":["Cet élément est dans la corbeille. Rétablissez-le d'abord pour y retravailler."],"This item is not in the trash, so there is nothing to restore. Open it from the list to work on it as it is.":["Cet élément n'est pas dans la corbeille, il n'y a donc rien à rétablir. Ouvrez-le depuis la liste pour travailler dessus tel quel."],"This item still holds items nested inside it. Move or delete those first.":["Cet élément contient encore des éléments imbriqués. Déplacez-les ou supprimez-les d'abord."],"This kind of field holds no fields inside it. Put the field in a section or a repeater instead.":["Ce type de champ ne contient aucun champ. Placez le champ dans une section ou dans un répéteur."],"This media item is not in the library, and someone may have deleted it. Reload the page to see what is there now.":["Ce média n'est pas dans la bibliothèque, et quelqu'un l'a peut-être supprimé. Rechargez la page pour voir ce qui s'y trouve maintenant."],"This picture could not be read, so nothing was stored. The file may be damaged, so open it on your computer and upload it again.":["Cette image n'a pas pu être lue, rien n'a donc été stocké. Le fichier est peut-être endommagé, ouvrez-le sur votre ordinateur et téléversez-le de nouveau."],"This picture is %(width)s by %(height)s pixels, over the limit of %(max)s pixels in all. Make it smaller and upload it again.":["Cette image fait %(width)s par %(height)s pixels, au-delà de la limite de %(max)s pixels au total. Réduisez-la et téléversez-la de nouveau."],"This post changed elsewhere. Reload before saving again.":["Cet article a changé ailleurs. Rechargez avant d'enregistrer de nouveau."],"This request came from a page on another site, so it was refused. Open the admin on this site and try again.":["Cette requête vient d'une page d'un autre site, elle a donc été refusée. Ouvrez l'administration sur ce site et réessayez."],"This request carried %(attribute)s, which fields do not take. Reload the page so the admin and the server agree again.":["Cette requête portait %(attribute)s, que les champs n'acceptent pas. Rechargez la page pour que l'administration et le serveur concordent à nouveau."],"This request left out %(field)s, which Gophenberg needs. Reload the page and try again.":["Cette requête a omis %(field)s, dont Gophenberg a besoin. Rechargez la page et réessayez."],"This rule reads a source called %(source)s, and nothing on your site declares one. A plugin that added it may have been removed.":["Cette règle lit une source nommée %(source)s, et rien sur votre site n'en déclare. Une extension qui l'ajoutait a pu être retirée."],"This site cannot write to its themes folder, so no theme can be installed. Ask whoever looks after your site to make the folder that %(setting)s points at writable. A read-only mount is the usual cause.":["Ce site ne peut pas écrire dans son dossier de thèmes, aucun thème ne peut donc être installé. Demandez à la personne qui s'occupe de votre site de rendre accessible en écriture le dossier vers lequel pointe %(setting)s. Un montage en lecture seule en est la cause habituelle."],"This site has nowhere to keep themes, so no theme can be installed. Ask whoever looks after your site to point %(setting)s at a folder the server can write to.":["Ce site n'a nulle part où garder les thèmes, aucun thème ne peut donc être installé. Demandez à la personne qui s'occupe de votre site de faire pointer %(setting)s vers un dossier où le serveur peut écrire."],"This site has nowhere to store uploads, so nothing can be uploaded. Ask whoever looks after your site to point %(setting)s at a folder the server can write to.":["Ce site n'a nulle part où stocker les téléversements, rien ne peut donc être téléversé. Demandez à la personne qui s'occupe de votre site de faire pointer %(setting)s vers un dossier où le serveur peut écrire."],"This theme is over the limit of %(max)s bytes, packed or unpacked. Leave out what the theme does not need and package it again.":["Ce thème dépasse la limite de %(max)s octets, compressé ou non. Retirez ce dont le thème n'a pas besoin et réempaquetez-le."],"This type will answer under /%(word)s.":["Ce type répondra sous /%(word)s."],"This zip holds %(entries)s files, more than the %(max)s a theme may carry. Package only the built theme.":["Ce zip contient %(entries)s fichiers, plus que les %(max)s qu'un thème peut contenir. Empaquetez seulement le thème construit."],"Through":["Via"],"Thumbnail":["Miniature"],"Title":["Titre"],"Two field groups in this file share the key %(key)s. Give one of them a different key and import again.":["Deux groupes de champs de ce fichier partagent la clé %(key)s. Donnez une clé différente à l'un d'eux et importez à nouveau."],"Two rule sources are registered under the name %(param)s. A plugin is declaring a source your site already holds.":["Deux sources de règles sont enregistrées sous le nom %(param)s. Une extension déclare une source que votre site possède déjà."],"Type":["Type"],"Type a whole number in both boxes before saving.":["Saisissez un nombre entier dans les deux cases avant d'enregistrer."],"Undo":["Annuler"],"Unsaved changes":["Modifications non enregistrées"],"Update":["Mettre à jour"],"Update failed.":["La mise à jour a échoué."],"Upload theme":["Téléverser un thème"],"Uploaded %s file.":["%s fichier téléversé.","%s fichiers téléversés.","%s fichiers téléversés."],"Users":["Utilisateurs"],"Users could not be loaded.":["Les utilisateurs n'ont pas pu être chargés."],"Value":["Valeur"],"Version":["Version"],"Videos":["Vidéos"],"Visit Site":["Aller sur le site"],"Web address":["Adresse web"],"What each Linked from field reads":["Ce que lit chaque champ Lié depuis"],"What it points at changed, so its stored values go with it.":["Ce qu'il vise a changé, donc ses valeurs enregistrées partent avec lui."],"Where %(group)s appears":["Où apparaît %(group)s"],"Without a rule this field always shows.":["Sans aucune règle ce champ s'affiche toujours."],"Without a rule this group appears nowhere.":["Sans une règle ce groupe n'apparaît nulle part."],"Yes":["Oui"],"Yes or no":["Oui ou non"],"You cannot change your own role.":["Vous ne pouvez pas changer votre propre rôle."],"Your language":["Votre langue"],"Your role does not allow %(capability)s.":["Votre rôle ne permet pas %(capability)s."],"Your server pins the site to the theme %(name)s, so themes cannot be changed here. Ask whoever looks after your site to remove the pin.":["Votre serveur fixe le site au thème %(name)s, les thèmes ne peuvent donc pas être changés ici. Demandez à la personne qui s'occupe de votre site de retirer cette fixation."],"Your site always needs one default content type, so this one cannot be turned off or deleted. Make another type the default first.":["Votre site a toujours besoin d'un type de contenu par défaut, celui-ci ne peut donc être ni désactivé ni supprimé. Rendez d'abord un autre type par défaut."],"a content type":["un type de contenu"],"account\u0004Role":["Rôle"],"account\u0004Status":["État"],"action label\u0004Duplicate":["Dupliquer"],"action label\u0004Duplicate…":["Dupliquer…"],"address":["adresse"],"admin section\u0004Content Types":["Types de contenu"],"admin section\u0004Field Groups":["Groupes de champs"],"admin section\u0004Language":["Langue"],"admin section\u0004Media":["Médias"],"admin section\u0004Settings":["Réglages"],"admin section\u0004Themes":["Thèmes"],"column\u0004Date":["Date"],"content type\u0004\"%s\" permanently deleted.":["Type de contenu « %s » supprimé définitivement."],"content type\u0004\"%s\" successfully created.":["Type de contenu « %s » créé avec succès."],"content type\u0004Status":["État"],"field\u0004Name":["Nom"],"field group\u0004Status":["Statut"],"field type\u0004Choice":["Choix"],"field type\u0004Color":["Couleur"],"field type\u0004Date":["Date"],"field type\u0004Flexible content":["Contenu flexible"],"field type\u0004Gallery":["Galerie"],"field type\u0004Kind":["Genre"],"field type\u0004Layout":["Disposition"],"field type\u0004Link":["Lien"],"field type\u0004Media":["Média"],"field type\u0004Range":["Plage"],"field type\u0004Repeater":["Répéteur"],"field type\u0004Section":["Section"],"field type\u0004Select":["Liste déroulante"],"file size\u0004%1$s %2$s":["%1$s %2$s"],"file type group\u0004Archives":["Archives"],"file type group\u0004Audio":["Sons"],"file type group\u0004Video":["Vidéos"],"holds":["contient"],"holds anything":["contient quelque chose"],"https://www.w3.org/WAI/tutorials/images/decision-tree/":["https://www.w3.org/WAI/tutorials/images/decision-tree/"],"image dimensions\u0004%1$s × %2$s":["%1$s par %2$s"],"is":["est"],"is above":["est supérieur à"],"is below":["est inférieur à"],"is empty":["est vide"],"is not":["n'est pas"],"panel button label\u0004Settings":["Réglages"],"person\u0004Name":["Nom"],"post\u0004%s (Copy)":["%s (copie)"],"post\u0004Status":["État"],"post status\u0004Draft":["Brouillon"],"post status\u0004Published":["Publié"],"post status\u0004Trash":["Corbeille"],"post type general name\u0004Pages":["Pages"],"post type general name\u0004Posts":["Articles"],"post type singular name\u0004Page":["Page"],"post type singular name\u0004Post":["Article"],"relation target\u0004None":["Aucun"],"role\u0004Administrator":["Administrateur"],"role\u0004Author":["Auteur"],"role\u0004Editor":["Éditeur"],"role\u0004Member":["Membre"],"role\u0004No role":["Sans rôle"],"status filter\u0004All":["Tout"],"taxonomy general name\u0004Categories":["Catégories"],"taxonomy singular name\u0004Category":["Catégorie"],"theme\u0004Status":["État"],"trash\u0004Restore":["Rétablir"],"unit symbol\u0004B":["o"],"unit symbol\u0004EB":["Eo"],"unit symbol\u0004GB":["Go"],"unit symbol\u0004KB":["Ko"],"unit symbol\u0004MB":["Mo"],"unit symbol\u0004PB":["Po"],"unit symbol\u0004TB":["To"],"unit symbol\u0004YB":["Yo"],"unit symbol\u0004ZB":["Zo"],"v%(version)s":["v%(version)s"],"verb\u0004Trash…":["Mettre à la corbeille…"],"verb\u0004View":["Voir"],"{day} {month} {year}":["{day} {month} {year}"]} +{"":{"lang":"fr","plural-forms":"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"}," and ":[" et "]," or ":[" ou "],"\"%s\" activated.":["Type de contenu « %s » activé."],"\"%s\" deactivated.":["Type de contenu « %s » désactivé."],"\"%s\" has been restored.":["« %s » a été rétabli."],"\"%s\" moved to the trash.":["« %s » déplacé dans la corbeille."],"\"%s\" permanently deleted.":["Suppression définitive de « %s »."],"\"%s\" successfully created.":["« %s » créé avec succès."],"\"%s\" uploaded.":["« %s » téléversé."],"%(field)s address":["Adresse de %(field)s"],"%(field)s cannot move inside itself. Pick a container that is not one of its own.":["%(field)s ne peut pas être déplacé à l'intérieur de lui-même. Choisissez un conteneur qui n'est pas l'un des siens."],"%(field)s declared.":["%(field)s déclaré."],"%(field)s deleted.":["%(field)s supprimé."],"%(field)s does not match the format its field asks for. Check it and save again.":["%(field)s ne respecte pas le format demandé par son champ. Vérifiez-le et enregistrez de nouveau."],"%(field)s goes no higher than %(limit)s. Lower the value and save again.":["%(field)s ne dépasse pas %(limit)s. Baissez la valeur et enregistrez de nouveau."],"%(field)s goes no lower than %(limit)s. Raise the value and save again.":["%(field)s ne descend pas sous %(limit)s. Augmentez la valeur et enregistrez de nouveau."],"%(field)s holds no value of its own, so it cannot be required. Make it optional.":["%(field)s ne contient aucune valeur propre, il ne peut donc pas être obligatoire. Rendez-le facultatif."],"%(field)s is optional again.":["%(field)s est de nouveau facultatif."],"%(field)s is required now.":["%(field)s est maintenant obligatoire."],"%(field)s moved.":["%(field)s déplacé."],"%(field)s names the same one twice. Remove the repeat and save again.":["%(field)s nomme le même deux fois. Retirez la répétition et enregistrez de nouveau."],"%(field)s needs at least %(limit)s files. Add one and save again.":["%(field)s demande au moins %(limit)s fichiers. Ajoutez-en un et enregistrez."],"%(field)s needs at least %(limit)s rows. Add one and save again.":["%(field)s demande au moins %(limit)s lignes. Ajoutez-en une et enregistrez."],"%(field)s only takes one of its listed choices. Pick one and save again.":["%(field)s accepte uniquement un des choix de sa liste. Choisissez-en un et enregistrez de nouveau."],"%(field)s reads a relation field that is not there. Pick a group and a relation field it holds.":["%(field)s lit un champ de relation qui n'existe pas. Choisissez un groupe et un champ de relation qu'il contient."],"%(field)s reads a relation pointing at %(type)s, so it would list nothing here. Pick a relation pointing at the items this group is shown on.":["%(field)s lit une relation qui pointe vers %(type)s, elle n'afficherait donc rien ici. Choisissez une relation qui pointe vers les éléments où ce groupe s'affiche."],"%(field)s renamed.":["%(field)s renommé."],"%(field)s settled.":["%(field)s réglé."],"%(field)s shows by its rules now.":["%(field)s s'affiche désormais selon ses règles."],"%(field)s stands in the list.":["%(field)s figure dans la liste."],"%(field)s stays out of the list.":["%(field)s reste hors de la liste."],"%(field)s takes at most %(limit)s files. Remove one and save again.":["%(field)s accepte au plus %(limit)s fichiers. Retirez-en un et enregistrez."],"%(field)s takes at most %(limit)s letters. Shorten what you wrote and save again.":["%(field)s accepte au plus %(limit)s lettres. Raccourcissez ce que vous avez écrit et enregistrez de nouveau."],"%(field)s takes at most %(limit)s rows. Remove one and save again.":["%(field)s accepte au plus %(limit)s lignes. Retirez-en une et enregistrez."],"%(field)s title":["Titre de %(field)s"],"%(file)s is larger than one upload may be.":["%(file)s dépasse la taille maximale d'un téléversement."],"%(file)s is not a file this block accepts.":["%(file)s n'est pas un fichier que ce bloc accepte."],"%(file)s: %(reason)s":["%(file)s : %(reason)s"],"%(group)s created.":["%(group)s créé."],"%(group)s now appears where you said.":["%(group)s apparaît maintenant là où vous avez dit."],"%(group)s removed.":["%(group)s supprimé."],"%(group)s updated.":["%(group)s mis à jour."],"%(key)s is served by %(winner)s, so %(loser)s does not show it on %(where)s.":["%(key)s est servi par %(winner)s, donc %(loser)s ne le montre pas sur %(where)s."],"%(name)s %(version)s is serving the public site.":["%(name)s %(version)s sert le site public."],"%(name)s belongs to the site now.":["%(name)s appartient désormais au site."],"%(name)s came from the %(plugin)s plugin, which no longer declares it.":["%(name)s venait de l'extension %(plugin)s, qui ne le déclare plus."],"%(name)s cannot be used as a theme name. Name the zip file after the theme, with no dot at the start and no slashes in it.":["%(name)s ne peut pas servir de nom de thème. Nommez le fichier zip comme le thème, sans point au début et sans barre oblique."],"%(name)s moves to /%(word)s. Every address of both types changes.":["Le type %(name)s passe à /%(word)s. Toutes les adresses des deux types changent."],"%(name)s would move to /%(word)s, which Gophenberg keeps for itself. Change its plural name and try again.":["Le type %(name)s passerait à /%(word)s, que Gophenberg garde pour lui. Modifiez son nom au pluriel et réessayez."],"%(source)s is %(value)s":["%(source)s est %(value)s"],"%(theme)s failed to start, so the built-in renderer is serving.":["%(theme)s n'a pas pu démarrer, le moteur de rendu intégré sert donc le site."],"%(theme)s is now serving the public site.":["%(theme)s sert désormais le site public."],"%(theme)s is serving the public site.":["%(theme)s sert le site public."],"%(theme)s is still starting, so the built-in renderer is serving.":["%(theme)s démarre encore, le moteur de rendu intégré sert donc le site."],"%(theme)s was installed.":["%(theme)s a été installé."],"%(theme)s will not load, so the built-in renderer is serving.":["%(theme)s ne se charge pas, le moteur de rendu intégré sert donc le site."],"%(type)s answers on a new address, and stored links move with it.":["%(type)s répond à une nouvelle adresse, et les liens enregistrés la suivent."],"%(type)s becomes the type the site opens on, and the old one takes an address.":["%(type)s devient le type sur lequel le site ouvre, et l'ancien prend une adresse."],"%(type)s keeps nesting while %(items)s of its items sit inside another. Move those to the top level first, the ones in the trash included.":["%(type)s continue de s'imbriquer tant que %(items)s de ses éléments se trouvent dans un autre. Déplacez-les d'abord au niveau supérieur, ceux de la corbeille compris."],"%(type)s keeps nesting, because some of its items sit inside another.":["%(type)s continue de s'imbriquer, car certains de ses éléments se trouvent dans un autre."],"%(type)s will answer at the root.":["Le type %(type)s répondra à la racine."],"%s content type activated.":["%s type de contenu activé.","%s types de contenu activés.","%s types de contenu activés."],"%s content type could not be activated.":["%s type de contenu n'a pas pu être activé.","%s types de contenu n'ont pas pu être activés.","%s types de contenu n'ont pas pu être activés."],"%s content type could not be deactivated.":["%s type de contenu n'a pas pu être désactivé.","%s types de contenu n'ont pas pu être désactivés.","%s types de contenu n'ont pas pu être désactivés."],"%s content type could not be permanently deleted.":["%s type de contenu n'a pas pu être supprimé définitivement.","%s types de contenu n'ont pas pu être supprimés définitivement.","%s types de contenu n'ont pas pu être supprimés définitivement."],"%s content type deactivated.":["%s type de contenu désactivé.","%s types de contenu désactivés.","%s types de contenu désactivés."],"%s content type permanently deleted.":["%s type de contenu supprimé définitivement.","%s types de contenu supprimés définitivement.","%s types de contenu supprimés définitivement."],"%s day":["%s jour","%s jours","%s jours"],"%s hour":["%s heure","%s heures","%s heures"],"%s item could not be moved to the trash.":["%s élément n'a pas pu être déplacé dans la corbeille.","%s éléments n'ont pas pu être déplacés dans la corbeille.","%s éléments n'ont pas pu être déplacés dans la corbeille."],"%s item could not be permanently deleted.":["%s élément n'a pas pu être supprimé définitivement.","%s éléments n'ont pas pu être supprimés définitivement.","%s éléments n'ont pas pu être supprimés définitivement."],"%s item could not be restored.":["%s élément n'a pas pu être rétabli.","%s éléments n'ont pas pu être rétablis.","%s éléments n'ont pas pu être rétablis."],"%s item moved to the trash.":["%s élément déplacé dans la corbeille.","%s éléments déplacés dans la corbeille.","%s éléments déplacés dans la corbeille."],"%s item permanently deleted.":["%s élément supprimé définitivement.","%s éléments supprimés définitivement.","%s éléments supprimés définitivement."],"%s item stays in the trash.":["%s élément reste dans la corbeille.","%s éléments restent dans la corbeille.","%s éléments restent dans la corbeille."],"%s minute":["%s minute","%s minutes","%s minutes"],"%s page has been restored.":["%s page a été rétablie.","%s pages ont été rétablies.","%s pages ont été rétablies."],"%s post has been restored.":["%s article a été rétabli.","%s articles ont été rétablis.","%s articles ont été rétablis."],"%s update available":["%s mise à jour disponible","%s mises à jour disponibles","%s mises à jour disponibles"],"(no title)":["(pas de titre)"],"Gophenberg %(version)s is available! Please update now.":["Gophenberg %(version)s est disponible ! Veuillez faire la mise à jour maintenant."],"Important: Before updating, please back up your database and files. For help with updates, visit the Updating Gophenberg documentation page.":["Important : avant de mettre à jour, veuillez sauvegarder votre base de données et vos fichiers. Pour obtenir de l'aide sur les mises à jour, consultez la page de documentation Mettre à jour Gophenberg."],"A %(kind)s field does not take a setting called %(setting)s. Remove it and try again.":["Un champ %(kind)s n'accepte pas de réglage nommé %(setting)s. Retirez-le et réessayez."],"A Linked from field stands on its own, not inside a section or a repeater. Declare %(field)s beside the container.":["Un champ Lié depuis se place seul, ni dans une section ni dans un répéteur. Déclarez %(field)s à côté du conteneur."],"A backup of the database is taken first, and Gophenberg goes back to %(running)s on its own if the new version does not start.":["Une sauvegarde de la base de données est faite d'abord, et Gophenberg revient de lui-même à %(running)s si la nouvelle version ne démarre pas."],"A backup of the database is taken first, and the site stays down until you restore it if the new version does not start.":["Une sauvegarde de la base de données est faite d'abord, et le site reste hors service jusqu'à ce que vous la restauriez si la nouvelle version ne démarre pas."],"A content type needs a singular and a plural name, like Guide and Guides. Fill both in and try again.":["Un type de contenu a besoin d'un nom au singulier et d'un nom au pluriel, comme Guide et Guides. Remplissez les deux et réessayez."],"A descriptive summary of the content type.":["Un résumé descriptif du type de contenu."],"A field group key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Rename the group in the file so its key comes out in that shape.":["La clé d'un groupe de champs doit commencer par une lettre minuscule puis ne contenir que des lettres minuscules, des chiffres et des tirets. Renommez le groupe dans le fichier pour que sa clé prenne cette forme."],"A field key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Rename the field so its key comes out in that shape.":["La clé d'un champ doit commencer par une lettre minuscule et ne contenir ensuite que des lettres minuscules, des chiffres et des tirets. Renommez le champ pour que sa clé prenne cette forme."],"A field needs a name. Type one and try again.":["Un champ a besoin d'un nom. Saisissez-en un et réessayez."],"A field with that name already exists on the items this group reaches. Pick another name.":["Un champ portant ce nom existe déjà sur les éléments que ce groupe atteint. Choisissez un autre nom."],"A flexible content field holds layouts, and %(field)s is not one. Add a layout first, then declare the field inside that layout.":["Un champ de contenu flexible contient des dispositions, et %(field)s n'en est pas une. Ajoutez d'abord une disposition, puis déclarez le champ dans cette disposition."],"A higher quality stores larger files, and it applies to pictures uploaded from now on.":["Une qualité plus élevée stocke des fichiers plus grands, et elle s'applique aux images téléversées à partir de maintenant."],"A layout stands inside a flexible content field only. Put %(field)s inside one of those instead.":["Une disposition ne se place que dans un champ de contenu flexible. Placez %(field)s dans l'un d'eux."],"A layout stands inside a flexible content field, never on its own. Declare a flexible content field first, then add %(field)s inside it.":["Une disposition se place dans un champ de contenu flexible, jamais seule. Déclarez d'abord un champ de contenu flexible, puis ajoutez %(field)s dedans."],"A listing carries between 1 and %(max)s items, so %(value)s is not a size Gophenberg takes. Pick a number inside that range.":["Une liste affiche entre 1 et %(max)s éléments, donc %(value)s n'est pas une taille que Gophenberg accepte. Choisissez un nombre dans cet intervalle."],"A relation field has to say which content type it points at. Pick that type and try again.":["Un champ de relation doit indiquer le type de contenu qu'il vise. Choisissez ce type et réessayez."],"A reload shows the admin in the language you chose.":["Un rechargement affiche l'administration dans la langue que vous avez choisie."],"A route word has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Change it and try again.":["Un mot de route doit commencer par une lettre minuscule et ne contenir ensuite que des lettres minuscules, des chiffres et des tirets. Modifiez-le et réessayez."],"A row of %(field)s has to name the layout it takes. Pick a layout for the row, or remove the row.":["Une ligne de %(field)s doit nommer la disposition qu'elle prend. Choisissez une disposition pour la ligne, ou retirez la ligne."],"A row of %(field)s takes one layout and no more. Reload the page and build the row again.":["Une ligne de %(field)s prend une seule disposition. Rechargez la page et reconstruisez la ligne."],"A rule matching any %(source)s cannot be turned into an exclusion. Leave it as is, or name the ones to leave out instead.":["Une règle valable pour n'importe quel %(source)s ne peut pas devenir une exclusion. Laissez-la telle quelle, ou nommez ceux à écarter."],"A theme naming its own page size uses that instead.":["Un thème qui indique sa propre taille de page utilise celle-ci à la place."],"A type key has to start with a lowercase letter and then hold only lowercase letters, numbers and hyphens. Change the key and try again.":["La clé d'un type doit commencer par une lettre minuscule et ne contenir ensuite que des lettres minuscules, des chiffres et des tirets. Modifiez la clé et réessayez."],"Actions":["Actions"],"Activate":["Activer"],"Activate %(theme)s":["Activer %(theme)s"],"Active":["Actif"],"Add":["Ajouter"],"Add %(layout)s":["Ajouter %(layout)s"],"Add %(name)s":["Ajouter %(name)s"],"Add %(type)s":["Ajouter %(type)s"],"Add Category":["Ajouter une catégorie"],"Add Content Type":["Ajouter un type de contenu"],"Add Field Group":["Ajouter un groupe de champs"],"Add Media File":["Ajouter un fichier média"],"Add Page":["Ajouter une page"],"Add Post":["Ajouter un article"],"Add User":["Ajouter un utilisateur"],"Add block":["Ajouter un bloc"],"Add choice":["Ajouter un choix"],"Add condition":["Ajouter une condition"],"Add field":["Ajouter un champ"],"Add field to %(field)s":["Ajouter un champ à %(field)s"],"Add layout":["Ajouter une disposition"],"Add layout to %(field)s":["Ajouter une disposition à %(field)s"],"Add one with %(button)s.":["Ajoutez un élément avec %(button)s."],"Add row":["Ajouter une ligne"],"Add rule set":["Ajouter un ensemble de règles"],"Add title":["Ajouter un titre"],"Add to %(field)s":["Ajouter à %(field)s"],"Address":["Adresse"],"Address updated.":["Adresse mise à jour."],"Adopt":["Adopter"],"Allow custom":["Autoriser les valeurs libres"],"Allow empty":["Autoriser le vide"],"Alt text":["Texte alternatif"],"An item cannot point at itself. Pick a different item for %(field)s.":["Un élément ne peut pas se viser lui-même. Choisissez un autre élément pour %(field)s."],"An item cannot sit inside itself, or inside one of the items nested under it. Pick a parent outside this branch.":["Un élément ne peut pas se trouver dans lui-même, ni dans un élément imbriqué sous lui. Choisissez un parent hors de cette branche."],"An updated version of Gophenberg is available.":["Une version mise à jour de Gophenberg est disponible."],"Another account wrote this, and only its author, an editor or an administrator may change it. You can still read it.":["Un autre compte a écrit ceci, et seuls son auteur, un éditeur ou un administrateur peuvent le modifier. Vous pouvez toujours le lire."],"Another account wrote this, so you are reading it rather than editing it.":["Un autre compte a écrit ceci, alors vous le lisez au lieu de le modifier."],"Another content type already answers under this route word. Pick a different word.":["Un autre type de contenu répond déjà sous ce mot de route. Choisissez un autre mot."],"Another content type already lives at the root of your site, and only one can. Give this type a route word, or hand the root over with Make default.":["Un autre type de contenu occupe déjà la racine de votre site, et un seul le peut. Donnez un mot de route à ce type, ou cédez la racine avec Rendre par défaut."],"Another content type already uses this key. Give this type a different name.":["Un autre type de contenu utilise déjà cette clé. Donnez un autre nom à ce type."],"Another item of this content type already uses that address. Pick a different slug and save again.":["Un autre élément de ce type de contenu utilise déjà cette adresse. Choisissez un autre slug et enregistrez de nouveau."],"Another update is currently in progress.":["Une autre mise à jour est actuellement en cours."],"Appears on":["Apparaît sur"],"Apply":["Appliquer"],"April":["avril"],"Are you sure you want to move \"%s\" to the trash?":["Voulez-vous vraiment déplacer « %s » dans la corbeille ?"],"Audio":["Audio"],"August":["août"],"Author":["Auteur/autrice"],"Back to %(type)s":["Retour aux %(type)s"],"Back to the latest posts":["Retour aux derniers articles"],"Backing up the database…":["Sauvegarde de la base de données…"],"Backups kept: %(kept)s of %(limit)s, taken on %(date)s at %(time)s.":["Sauvegardes conservées : %(kept)s sur %(limit)s, faite le %(date)s à %(time)s.","Sauvegardes conservées : %(kept)s sur %(limit)s, la plus récente le %(date)s à %(time)s.","Sauvegardes conservées : %(kept)s sur %(limit)s, la plus récente le %(date)s à %(time)s."],"Block":["Bloc"],"Broken":["Cassé"],"Bundles of fields, shown where their rules place them.":["Ensembles de champs, affichés là où leurs règles les placent."],"Button group":["Groupe de boutons"],"Cancel":["Annuler"],"Caption":["Légende"],"Change %(name)s":["Modifier %(name)s"],"Change address":["Changer l'adresse"],"Change address…":["Changer l'adresse…"],"Change role":["Changer le rôle"],"Change the role of %(name)s":["Changer le rôle de %(name)s"],"Check again.":["Vérifier à nouveau."],"Check now.":["Vérifier maintenant."],"Checkbox group":["Groupe de cases à cocher"],"Checking the new version…":["Vérification de la nouvelle version…"],"Choices":["Choix"],"Choose %(field)s":["Choisir %(field)s"],"Choose how the site serves its content.":["Choisissez comment le site sert son contenu."],"Choose the language the admin reads in.":["Choisissez la langue dans laquelle se lit l'administration."],"Choose the role of %(name)s.":["Choisissez le rôle de %(name)s."],"Choose the version to update to.":["Choisissez la version vers laquelle mettre à jour."],"Clear %(field)s":["Vider %(field)s"],"Close":["Fermer"],"Close Settings":["Fermer les réglages"],"Closed":["Fermé"],"Condition":["Condition"],"Content":["Contenu"],"Content Types":["Types de contenu"],"Content nests at most %(max)s levels deep, and this item would sit deeper. Pick a parent closer to the top.":["Le contenu s'imbrique sur au plus %(max)s niveaux, et cet élément irait plus profond. Choisissez un parent plus proche du sommet."],"Content type":["Type de contenu"],"Content type updated.":["Type de contenu mis à jour."],"Could not load that post.":["Impossible de charger cet article."],"Could not save image. %s":["Impossible d’enregistrer le média. %s"],"Could not save media. %s":["Impossible d’enregistrer le média. %s"],"Could not save that post.":["Impossible d'enregistrer cet article."],"Create":["Créer"],"Create a field group":["Créer un groupe de champs"],"Create user":["Créer l'utilisateur"],"Created":["Date de création"],"Current version: %(version)s":["Version actuelle : %(version)s"],"Date added":["Date d’ajout"],"Date modified":["Date de modification"],"Deactivate":["Désactiver"],"Deactivate %(theme)s":["Désactiver %(theme)s"],"December":["décembre"],"Default":["Par défaut"],"Default content type updated.":["Type de contenu par défaut mis à jour."],"Definitions file":["Fichier de définitions"],"Delete":["Supprimer"],"Delete \"%(title)s\" for good? This cannot be undone.":["Supprimer « %(title)s » définitivement ? Cette action est irréversible."],"Delete %(field)s":["Supprimer %(field)s"],"Delete %(group)s":["Supprimer %(group)s"],"Delete %s content type for good? This cannot be undone.":["Supprimer %s type de contenu définitivement ? Cette action est irréversible.","Supprimer %s types de contenu définitivement ? Cette action est irréversible.","Supprimer %s types de contenu définitivement ? Cette action est irréversible."],"Delete %s item for good? This cannot be undone.":["Supprimer %s élément définitivement ? Cette action est irréversible.","Supprimer %s éléments définitivement ? Cette action est irréversible.","Supprimer %s éléments définitivement ? Cette action est irréversible."],"Delete permanently":["Supprimer définitivement"],"Delete the field":["Supprimer le champ"],"Delete the group":["Supprimer le groupe"],"Delete…":["Supprimer…"],"Describe":["Décrire"],"Describe the purpose of the image.":["Décrivez la fonction de l’image."],"Describe…":["Décrire…"],"Description":["Description"],"Description updated.":["Description mise à jour."],"Desktop":["Ordinateur"],"Destination":["Destination"],"Dimensions":["Dimensions"],"Disable":["Désactiver"],"Disable %(name)s":["Désactiver %(name)s"],"Disabled":["Désactivé"],"Dismiss":["Ignorer"],"Document":["Document"],"Documents":["Documents"],"Done. The site now holds what the file describes.":["Terminé. Le site contient maintenant ce que décrit le fichier."],"Downloading Gophenberg %(version)s…":["Téléchargement de Gophenberg %(version)s…"],"Draft saved.":["Brouillon enregistré."],"Drop files to upload":["Déposez vos fichiers pour les téléverser"],"Edit media":["Modifier le média"],"Edit…":["Modifier…"],"Email":["E-mail"],"Empty Trash":["Vider la corbeille"],"Empty trash":["Vider la corbeille"],"Enable":["Activer"],"Enable %(name)s":["Activer %(name)s"],"Every address of this type moves. Links kept elsewhere to the old addresses stop working.":["Toutes les adresses de ce type changent. Les liens conservés ailleurs vers les anciennes adresses cessent de fonctionner."],"Every content type":["Tous les types de contenu"],"Every field group needs a title. Give it a name and save again.":["Chaque groupe de champs a besoin d'un titre. Donnez-lui un nom et enregistrez à nouveau."],"Every item needs an author who exists. Pick one from the list and save again.":["Chaque élément a besoin d'un auteur existant. Choisissez-en un dans la liste et enregistrez de nouveau."],"Every kind of content this site holds.":["Toutes les sortes de contenu que ce site contient."],"Every value stored under this field goes with it, in every item the group reaches and in the revisions behind them.":["Toutes les valeurs enregistrées dans ce champ partent avec lui, dans chaque élément que le groupe atteint et dans les révisions qui les suivent."],"Excerpt":["Extrait"],"Export definitions":["Exporter les définitions"],"February":["février"],"Fewest files":["Minimum de fichiers"],"Fewest rows":["Minimum de lignes"],"Field":["Champ"],"Field Groups":["Groupes de champs"],"Field group":["Groupe de champs"],"Fields":["Champs"],"Fields of %(group)s":["Champs de %(group)s"],"File name":["Nom de fichier"],"File size":["Taille du fichier"],"File type":["Type de fichier"],"Filter by status":["Filtrer par état"],"Follow the browser":["Suivre le navigateur"],"Follow the steps on the Updating Gophenberg documentation page to update by hand.":["Suivez les étapes de la page de documentation Mettre à jour Gophenberg pour mettre à jour à la main."],"From %(plugin)s":["De %(plugin)s"],"Full Size":["Taille originale"],"Gophenberg %(version)s failed its start check on this site. Fix what failed before you try it again.":["Gophenberg %(version)s a échoué à sa vérification de démarrage sur ce site. Corrigez ce qui a échoué avant de réessayer."],"Gophenberg Updates":["Mises à jour de Gophenberg"],"Gophenberg cannot start this update: %(reason)s":["Gophenberg ne peut pas lancer cette mise à jour : %(reason)s"],"Gophenberg checked for updates moments ago. Try again later.":["Gophenberg a cherché des mises à jour il y a un instant. Réessayez plus tard."],"Gophenberg could not read what your browser sent. Reload the page and try again, and tell whoever looks after your site if it keeps happening.":["Gophenberg n'a pas pu lire ce que votre navigateur a envoyé. Rechargez la page et réessayez, et prévenez la personne qui s'occupe de votre site si cela continue."],"Gophenberg could not read which item you picked as parent. Reload the page and pick it again.":["Gophenberg n'a pas pu lire quel élément vous avez choisi comme parent. Rechargez la page et choisissez-le de nouveau."],"Gophenberg does not accept %(extension)s files. Upload a picture, a video, an audio file, a PDF or a zip instead.":["Gophenberg n'accepte pas les fichiers %(extension)s. Téléversez plutôt une image, une vidéo, un fichier audio, un PDF ou un zip."],"Gophenberg does not answer in %(value)s. Pick one of the languages on the list.":["Gophenberg ne répond pas en %(value)s. Choisissez une des langues de la liste."],"Gophenberg has no autosave of yours for this item. Open the item to see the version that is stored.":["Gophenberg n'a aucun enregistrement automatique de vous pour cet élément. Ouvrez l'élément pour voir la version stockée."],"Gophenberg has not checked for updates yet.":["Gophenberg n'a pas encore recherché de mises à jour."],"Gophenberg has not come back yet.":["Gophenberg n'est pas encore revenu."],"Gophenberg holds no kind of definition called %(subject)s, so nothing was taken over. Reload the page so the admin and the server agree again.":["Gophenberg ne connaît aucune sorte de définition nommée %(subject)s, rien n'a donc été repris. Rechargez la page pour que l'admin et le serveur se rejoignent à nouveau."],"Gophenberg keeps /%(path)s for itself or for another content type, so your content cannot answer there. Give the item a different slug.":["Gophenberg garde l'adresse /%(path)s pour lui ou pour un autre type de contenu, votre contenu ne peut donc pas y répondre. Donnez un autre slug à l'élément."],"Gophenberg keeps this word for itself, so no content type can answer under it. Pick a different route word.":["Gophenberg garde ce mot pour lui, aucun type de contenu ne peut donc répondre sous ce mot. Choisissez un autre mot de route."],"Gophenberg stopped after the switch so that its service manager, such as systemd, starts the new version. Check that the service manager starts it again after exit code 75, and run update:status on the server to see where the update stands.":["Gophenberg s'est arrêté après le changement pour que son gestionnaire de services, comme systemd, démarre la nouvelle version. Vérifiez que le gestionnaire de services le redémarre après le code de sortie 75, et lancez update:status sur le serveur pour voir où en est la mise à jour."],"Gophenberg updated successfully.":["Gophenberg a été mis à jour avec succès."],"Gophenberg went back to %(from)s and is running normally.":["Gophenberg est revenu à %(from)s et fonctionne normalement."],"Group":["Groupe"],"Highest":["Maximum"],"Holds":["Contient"],"Images":["Images"],"Import definitions":["Importer les définitions"],"In list":["Dans la liste"],"Inactive":["Inactif"],"Installed":["Installé"],"Instructions":["Instructions"],"It moves here from another group and keeps its stored values.":["Il arrive ici depuis un autre groupe et garde ses valeurs enregistrées."],"It moves to another group and keeps its stored values.":["Il passe dans un autre groupe et garde ses valeurs enregistrées."],"It moves to another group, so its stored values do not follow.":["Il passe dans un autre groupe, donc ses valeurs enregistrées ne le suivent pas."],"It reads a relation inside a container, and only an import can point it elsewhere.":["Il lit une relation dans un conteneur, et seule une importation peut le faire pointer ailleurs."],"It starts on %(type)s, and the rules may be edited afterwards.":["Il commence sur %(type)s, et les règles peuvent être modifiées ensuite."],"Items could not be loaded.":["Les éléments n'ont pas pu être chargés."],"Its items sit inside one another, so it keeps nesting.":["Ses éléments se trouvent les uns dans les autres, donc il continue de s'imbriquer."],"Its kind changed, so its stored values go with it.":["Son type a changé, donc ses valeurs enregistrées partent avec lui."],"January":["janvier"],"July":["juillet"],"June":["juin"],"Keep %(field)s out of the list":["Garder %(field)s hors de la liste"],"Keep it":["Le conserver"],"Keep it here":["Le laisser ici"],"Key":["Clé"],"Label":["Libellé"],"Language":["Langue"],"Large":["Grande"],"Last checked on %(date)s at %(time)s.":["Dernière vérification le %(date)s à %(time)s."],"Leave empty if decorative.":["Laissez vide si l’image est décorative"],"Let items nest":["Autoriser l'imbrication"],"Linked from":["Lié depuis"],"List view":["Vue en liste"],"Loading field groups.":["Chargement des groupes de champs."],"Loading the post.":["Chargement de l'article."],"Loading the screen.":["Chargement de l'écran."],"Loading themes.":["Chargement des thèmes."],"Loading users.":["Chargement des utilisateurs."],"Loading…":["Chargement…"],"Longest":["Longueur maximale"],"Lowest":["Minimum"],"Make %(field)s optional":["Rendre %(field)s facultatif"],"Make default":["Rendre par défaut"],"Make default…":["Rendre par défaut…"],"Make optional":["Rendre facultatif"],"Manage the categories on this site.":["Gérez les catégories de ce site."],"Manage the images and files this site holds.":["Gérez les images et les fichiers que ce site contient."],"Manage the items of this content type.":["Gérez les éléments de ce type de contenu."],"Manage the pages on this site.":["Gérez les pages de ce site."],"Manage the posts on this site.":["Gérez les articles de ce site."],"Many targets":["Plusieurs cibles"],"Many values":["Plusieurs valeurs"],"March":["mars"],"May":["mai"],"Media %(id)s":["Média %(id)s"],"Media Library":["Médiathèque"],"Media file updated.":["Fichier média mis à jour."],"Medium":["Moyenne"],"Mobile":["Mobile"],"Modified: %s":["Modifié : %s"],"Most files":["Maximum de fichiers"],"Most rows":["Maximum de lignes"],"Move":["Déplacer"],"Move \"%(title)s\" to the trash?":["Déplacer « %(title)s » dans la corbeille ?"],"Move %(field)s down":["Descendre %(field)s"],"Move %(field)s elsewhere":["Déplacer %(field)s ailleurs"],"Move %(field)s up":["Monter %(field)s"],"Move %(group)s down":["Descendre %(group)s"],"Move %(group)s up":["Monter %(group)s"],"Move %(name)s down":["Descendre %(name)s"],"Move %(name)s up":["Monter %(name)s"],"Move %s item to the trash?":["Déplacer %s élément dans la corbeille ?","Déplacer %s éléments dans la corbeille ?","Déplacer %s éléments dans la corbeille ?"],"Move every address":["Déplacer toutes les adresses"],"Move row down":["Descendre la ligne"],"Move row up":["Monter la ligne"],"Move the field":["Déplacer le champ"],"Move to trash":["Déplacer dans la corbeille"],"Name":["Nom"],"Name updated.":["Nom mis à jour."],"Nests":["Imbriqué"],"Newer posts":["Articles plus récents"],"No":["Non"],"No content types found.":["Aucun type de contenu trouvé."],"No description":["Aucune description"],"No file arrived with this upload. Choose a file and try again.":["Aucun fichier n'est arrivé avec ce téléversement. Choisissez un fichier et réessayez."],"No items found.":["Aucun élément trouvé."],"No items yet.":["Aucun élément pour l'instant."],"No media chosen":["Aucun média choisi"],"No media has been uploaded yet.":["Aucun média n'a encore été téléversé."],"No media items found.":["Aucun média n’a été trouvé."],"No media items yet.":["Aucun fichier média pour l’instant."],"No new updates found.":["Aucune nouvelle mise à jour trouvée."],"No page lives at this address.":["Aucune page n'existe à cette adresse."],"No parent":["Pas de parent"],"No theme arrived with this upload. Choose a zip file and try again.":["Aucun thème n'est arrivé avec ce téléversement. Choisissez un fichier zip et réessayez."],"No themes are installed.":["Aucun thème n'est installé."],"No title":["Aucun titre"],"None":["Aucun"],"Not %(type)s":["Sauf %(type)s"],"Not found":["Introuvable"],"Not serving":["Hors service"],"Nothing declares that role.":["Rien ne déclare ce rôle."],"Nothing points here yet.":["Rien ne pointe encore ici."],"Nothing published here yet.":["Rien n'est encore publié ici."],"Nothing published yet.":["Rien n'est encore publié."],"November":["novembre"],"Nowhere":["Nulle part"],"Number":["Nombre"],"October":["octobre"],"Older posts":["Articles plus anciens"],"One frame of this animation holds more than %(max)s pixels, which is more than Gophenberg opens. Upload a smaller animation.":["Une image de cette animation dépasse %(max)s pixels, plus que ce que Gophenberg ouvre. Téléversez une animation plus petite."],"One of the filters on this list is not one Gophenberg understands. Clear the filters and try again.":["Un des filtres de cette liste n'est pas un filtre que Gophenberg comprend. Videz les filtres et réessayez."],"One of the items picked for %(field)s is not the kind of content that field points at. Reload the page and pick from the list the field offers.":["Un des éléments choisis pour %(field)s n'est pas le genre de contenu que vise ce champ. Rechargez la page et choisissez dans la liste que le champ propose."],"One of the items picked for %(field)s was not named in a way Gophenberg understands. Reload the page and pick the items again.":["Un des éléments choisis pour %(field)s n'était pas nommé d'une façon que Gophenberg comprend. Rechargez la page et choisissez de nouveau les éléments."],"One of the items picked no longer exists. Reload the page and pick again.":["Un des éléments choisis n'existe plus. Rechargez la page et choisissez de nouveau."],"One target":["Une cible"],"Only a relation field points at another content type or holds many items. Pick the Relation kind, or leave the target and the many option empty.":["Seul un champ de relation vise un autre type de contenu ou contient plusieurs éléments. Choisissez le genre Relation, ou laissez vides la cible et l'option plusieurs."],"Only one file may be placed here.":["Un seul fichier peut être placé ici."],"Only the content type at the root of your site may go without a route word. Give this type one and try again.":["Seul le type de contenu à la racine de votre site peut se passer de mot de route. Donnez-en un à ce type et réessayez."],"Open %(field)s in a new tab":["Ouvrir %(field)s dans un nouvel onglet"],"Order stored.":["Ordre enregistré."],"Other":["Autre"],"Out of list":["Hors de la liste"],"Parent":["Parent"],"Password":["Mot de passe"],"Pending":["En attente"],"Pending Review":["En attente de relecture"],"Permanently delete…":["Supprimer définitivement…"],"Picture quality":["Qualité d'image"],"Picture quality runs from 1 to %(max)s, so %(value)s is not a quality Gophenberg stores at. Pick a number inside that range.":["La qualité d'image va de 1 à %(max)s, donc %(value)s n'est pas une qualité avec laquelle Gophenberg enregistre. Choisissez un nombre dans cet intervalle."],"Placeholder":["Texte indicatif"],"Plural name":["Nom au pluriel"],"Points at":["Vise"],"Post published.":["Article publié."],"Posts per page":["Articles par page"],"Preview":["Prévisualiser"],"Private":["Privé"],"Publish":["Publier"],"Published: %s":["Publié : %s"],"Radio group":["Groupe de boutons radio"],"Re-install version %(version)s":["Réinstaller la version %(version)s"],"Reads from":["Lit depuis"],"Redo":["Rétablir"],"Relation":["Relation"],"Reload the admin":["Recharger l'administration"],"Remove":["Retirer"],"Remove %(name)s":["Retirer %(name)s"],"Remove %(title)s":["Retirer %(title)s"],"Remove row":["Retirer la ligne"],"Rename":["Renommer"],"Rename %(field)s":["Renommer %(field)s"],"Rename…":["Renommer…"],"Require":["Rendre obligatoire"],"Require %(field)s":["Rendre %(field)s obligatoire"],"Required":["Obligatoire"],"Restarting Gophenberg…":["Redémarrage de Gophenberg…"],"Restore":["Rétablir"],"Role changed.":["Rôle modifié."],"Roll back to %(theme)s":["Revenir à %(theme)s"],"Roll back to the built-in renderer":["Revenir au moteur de rendu intégré"],"Route word":["Mot de route"],"Rule %(number)s of set %(set)s":["Règle %(number)s de l'ensemble %(set)s"],"Rule set %(number)s":["Ensemble de règles %(number)s"],"Rules":["Règles"],"Rules showing %(field)s":["Règles affichant %(field)s"],"Run update:status on the server to see the backup taken before the update. Then restore that backup, or fix what failed and start Gophenberg again.":["Exécutez update:status sur le serveur pour voir la sauvegarde faite avant la mise à jour. Ensuite, restaurez cette sauvegarde, ou corrigez ce qui a échoué et redémarrez Gophenberg."],"Save":["Enregistrer"],"Save draft":["Enregistrer le brouillon"],"Save rules":["Enregistrer les règles"],"Save settings":["Enregistrer les réglages"],"Saved":["Enregistré"],"Saving":["Enregistrement"],"Scheduled":["Planifié"],"Scheduled: %s":["Planifié : %s"],"Search %(type)s…":["Rechercher des %(type)s…"],"Search audio":["Rechercher un audio"],"Search images":["Rechercher des images"],"Search media":["Rechercher des médias"],"Search videos":["Rechercher des vidéos"],"Select":["Sélectionner"],"September":["septembre"],"Serving":["En service"],"Settings":["Réglages"],"Settings of %(field)s":["Réglages de %(field)s"],"Shadowed":["Masqué"],"Show %(field)s in the list":["Afficher %(field)s dans la liste"],"Showing %(held)s of %(total)s.":["Affichage de %(held)s sur %(total)s."],"Singular name":["Nom au singulier"],"Slug":["Slug"],"Somebody must be able to manage users.":["Quelqu'un doit pouvoir gérer les utilisateurs."],"Someone else changed this media item while you were editing it. Reload the page and make your change again.":["Quelqu'un d'autre a modifié ce média pendant que vous le modifiiez. Rechargez la page et refaites votre modification."],"Someone else saved changes to this item while you were editing, so yours were not saved. Copy your text somewhere safe, then reload the item and put your changes back in.":["Quelqu'un d'autre a enregistré des modifications sur cet élément pendant que vous éditiez, les vôtres n'ont donc pas été enregistrées. Copiez votre texte en lieu sûr, puis rechargez l'élément et remettez vos modifications."],"Something went wrong inside Gophenberg. Try again in a moment, and tell whoever looks after your site if it keeps happening.":["Quelque chose a mal tourné dans Gophenberg. Réessayez dans un instant, et prévenez la personne qui s'occupe de votre site si cela continue."],"Something went wrong.":["Quelque chose a mal tourné."],"Something went wrong. Try again.":["Quelque chose a mal tourné. Réessayez."],"Sorry, you are not allowed to access this page.":["Désolé, vous n’avez pas l’autorisation d’accéder à cette page."],"Source":["Source"],"Steps of":["Pas de"],"Stop nesting":["Arrêter l'imbrication"],"Tablet":["Tablette"],"Text":["Texte"],"Text area":["Zone de texte"],"That email is already in use.":["Cet e-mail est déjà utilisé."],"That field group no longer exists. Reload the page to see the groups your site holds now.":["Ce groupe de champs n'existe plus. Rechargez la page pour voir les groupes que votre site contient maintenant."],"That field is not on this content type any more. Reload the page to see the fields it has now.":["Ce champ n'est plus sur ce type de contenu. Rechargez la page pour voir les champs qu'il possède maintenant."],"That revision does not exist, and older ones drop off once a type holds more than it keeps. Open the item to see which revisions are left.":["Cette révision n'existe pas, et les plus anciennes disparaissent quand un type en détient plus qu'il n'en conserve. Ouvrez l'élément pour voir les révisions restantes."],"That role holds more than your own.":["Ce rôle va au-delà du vôtre."],"That web address does not name a media item Gophenberg can look up. Open the media library and pick the item from there.":["Cette adresse web ne désigne aucun média que Gophenberg puisse trouver. Ouvrez la bibliothèque de médias et choisissez l'élément depuis là."],"That web address does not name a revision Gophenberg can look up. Open the item and pick a revision from its history.":["Cette adresse web ne désigne aucune révision que Gophenberg puisse trouver. Ouvrez l'élément et choisissez une révision dans son historique."],"That web address does not name an item Gophenberg can look up. Go back to the list and open the item from there.":["Cette adresse web ne désigne aucun élément que Gophenberg puisse trouver. Revenez à la liste et ouvrez l'élément depuis là."],"The %(count)s item in the trash is deleted for good. This cannot be undone.":["%(count)s élément de la corbeille est supprimé définitivement. Cette action est irréversible.","Les %(count)s éléments de la corbeille sont supprimés définitivement. Cette action est irréversible.","Les %(count)s éléments de la corbeille sont supprimés définitivement. Cette action est irréversible."],"The %(file)s calls this theme %(declared)s, but it is being installed as %(installed)s. Rename the zip file to match, or change the name inside %(file)s.":["Le fichier %(file)s appelle ce thème %(declared)s, mais il s'installe sous %(installed)s. Renommez le fichier zip pour qu'ils correspondent, ou changez le nom dans %(file)s."],"The %(file)s inside %(name)s is not valid JSON, so it could not be read. Fix that file and package the theme again.":["Le fichier %(file)s dans %(name)s n'est pas du JSON valide, il n'a donc pas pu être lu. Corrigez ce fichier et réempaquetez le thème."],"The %(file)s inside %(name)s names its theme kit as %(declared)s, which is not a version number. Build the theme again, and the build will fill that in.":["Le %(file)s dans %(name)s indique son kit de thèmes comme %(declared)s, ce qui n'est pas un numéro de version. Compilez le thème à nouveau et la compilation le renseignera."],"The %(origin)s plugin declared this, so it can only be changed in that plugin. Turning it off is still yours to do.":["L'extension %(origin)s l'a déclaré, donc il ne peut être modifié que dans cette extension. Le désactiver reste entre vos mains."],"The %(plugin)s plugin also declares %(name)s, and the site keeps the key.":["L'extension %(plugin)s déclare aussi %(name)s, et le site garde la clé."],"The %(plugin)s plugin declared these fields, so they change only in its code.":["L'extension %(plugin)s a déclaré ces champs, donc ils ne changent que dans son code."],"The %(plugin)s plugin declares %(name)s flat, and the site keeps it nesting while its items sit inside another.":["L'extension %(plugin)s déclare %(name)s sans imbrication, et le site continue de l'imbriquer tant que ses éléments se trouvent dans un autre."],"The browser kept an unsaved version of this post.":["Le navigateur a gardé une version non enregistrée de cet article."],"The built-in renderer is now serving the public site.":["Le moteur de rendu intégré sert désormais le site public."],"The built-in renderer is serving the public site.":["Le moteur de rendu intégré sert le site public."],"The check on %(date)s at %(time)s failed: %(error)s":["La vérification du %(date)s à %(time)s a échoué : %(error)s"],"The content type this field points at is not named in a shape Gophenberg accepts. Give it a key that starts with a lowercase letter and then holds only lowercase letters, numbers and hyphens.":["Le type de contenu que vise ce champ n'est pas nommé sous une forme que Gophenberg accepte. Donnez-lui une clé qui commence par une lettre minuscule et ne contient ensuite que des lettres minuscules, des chiffres et des tirets."],"The content types could not be loaded, so where these groups appear and which fields they shadow are not shown.":["Les types de contenu n'ont pas pu être chargés, donc où ces groupes apparaissent et quels champs ils masquent ne sont pas affichés."],"The content types could not be loaded.":["Les types de contenu n'ont pas pu être chargés."],"The content types could not be refreshed, so where these groups appear and what they shadow may be out of date.":["Les types de contenu n'ont pas pu être actualisés, donc où ces groupes apparaissent et ce qu'ils masquent peut être obsolète."],"The draft could not be created.":["Le brouillon n'a pas pu être créé."],"The entry %(entry)s in this zip would be written outside the theme folder, so nothing was installed. Package the theme again.":["L'entrée %(entry)s de ce zip s'écrirait hors du dossier du thème, rien n'a donc été installé. Réempaquetez le thème."],"The field %(field)s cannot go, because %(by)s reads it. Change %(by)s first.":["Le champ %(field)s ne peut pas être retiré, car %(by)s le lit. Modifiez d'abord %(by)s."],"The field %(field)s cannot hold the value it was given. Check what kind of field it is and enter a value that matches.":["Le champ %(field)s ne peut pas contenir la valeur qui lui a été donnée. Vérifiez de quel genre de champ il s'agit et saisissez une valeur qui convient."],"The field %(field)s has to hold a value before this item can be published. Fill it in, or leave the item as a draft.":["Le champ %(field)s doit contenir une valeur avant que cet élément puisse être publié. Remplissez-le, ou laissez l'élément en brouillon."],"The field %(field)s in %(group)s still points at this content type. Delete that field first, then delete this type.":["Le champ %(field)s dans %(group)s vise encore ce type de contenu. Supprimez d'abord ce champ, puis supprimez ce type."],"The field %(field)s is hidden by its own rules right now, so it cannot hold a value. Show it again before filling it in.":["Le champ %(field)s est masqué par ses propres règles pour le moment, il ne peut donc contenir aucune valeur. Affichez-le de nouveau avant de le remplir."],"The field %(field)s points at one item only. Remove the extra choices and keep one.":["Le champ %(field)s ne vise qu'un seul élément. Retirez les choix en trop et gardez-en un."],"The field %(field)s points at other items, so it does not take a plain value. Pick the items it points at instead.":["Le champ %(field)s vise d'autres éléments, il n'accepte donc pas une valeur simple. Choisissez plutôt les éléments qu'il vise."],"The field %(field)s takes a list of items, and what arrived was not a list. Reload the page and pick the items again.":["Le champ %(field)s attend une liste d'éléments, et ce qui est arrivé n'était pas une liste. Rechargez la page et choisissez de nouveau les éléments."],"The field %(source)s cannot hold the value %(value)s, so no rule can compare it. Write a value of the kind %(source)s stores.":["Le champ %(source)s ne peut pas contenir la valeur %(value)s, aucune règle ne peut donc la comparer. Écrivez une valeur du type que %(source)s enregistre."],"The field groups could not be loaded.":["Les groupes de champs n'ont pas pu être chargés."],"The field groups could not be reached.":["Les groupes de champs n'ont pas pu être joints."],"The field keeps its values on the content both groups reach.":["Le champ garde ses valeurs sur le contenu que les deux groupes atteignent."],"The fields this group holds go with it, and so do the values every item stored in them.":["Les champs que ce groupe contient partent avec lui, ainsi que les valeurs que chaque élément y a enregistrées."],"The groups were reordered.":["Les groupes ont été réordonnés."],"The item could not be duplicated.":["L'élément n'a pas pu être dupliqué."],"The item could not be moved to the trash.":["L'élément n'a pas pu être déplacé dans la corbeille."],"The item could not be permanently deleted.":["L'élément n'a pas pu être supprimé définitivement."],"The item could not be restored.":["L'élément n'a pas pu être rétabli."],"The item you picked as parent holds another kind of content. Pick a parent of the same content type as this item.":["L'élément que vous avez choisi comme parent contient un autre genre de contenu. Choisissez un parent du même type de contenu que cet élément."],"The item you picked as parent is in the trash. Restore it, or pick another parent.":["L'élément que vous avez choisi comme parent est dans la corbeille. Rétablissez-le, ou choisissez un autre parent."],"The item you picked as parent no longer exists. Reload the page and pick another parent.":["L'élément que vous avez choisi comme parent n'existe plus. Rechargez la page et choisissez un autre parent."],"The media library could not be loaded.":["La bibliothèque de médias n'a pas pu être chargée."],"The name changes. Nothing stored under this field moves.":["Le nom change. Rien de ce qui est stocké sous ce champ ne bouge."],"The name could not be updated.":["Le nom n'a pas pu être mis à jour."],"The new order has to name every field group exactly once. Reload the page and move the groups again.":["Le nouvel ordre doit nommer chaque groupe de champs exactement une fois. Rechargez la page et déplacez les groupes à nouveau."],"The new order has to name every field of this content type exactly once. Reload the page and move the fields again.":["Le nouvel ordre doit nommer chaque champ de ce type de contenu exactement une fois. Rechargez la page et déplacez les champs à nouveau."],"The next check runs in %(time)s.":["La prochaine vérification aura lieu dans %(time)s."],"The number of revisions to keep has to be a whole number, and it cannot be negative. Enter a different number.":["Le nombre de révisions à conserver doit être un nombre entier, et il ne peut pas être négatif. Saisissez un autre nombre."],"The registry could not be reached.":["Le registre n'a pas pu être joint."],"The role could not be changed.":["Le rôle n'a pas pu être modifié."],"The rule on %(source)s names nothing to match. Pick a value, or remove the rule.":["La règle sur %(source)s ne nomme rien à faire correspondre. Choisissez une valeur, ou retirez la règle."],"The rules could not be loaded.":["Les règles n'ont pas pu être chargées."],"The rules on %(field)s lead back to %(field)s itself, so nothing can decide whether to show it. Point one of them at another field.":["Les règles de %(field)s reviennent à %(field)s lui-même, rien ne peut donc décider de l'afficher. Faites pointer l'une d'elles vers un autre champ."],"The same item was picked twice for %(field)s. Pick each item once.":["Le même élément a été choisi deux fois pour %(field)s. Choisissez chaque élément une seule fois."],"The server could not be reached, so nothing was changed.":["Le serveur n'a pas pu être joint, rien n'a donc été changé."],"The server could not be reached, so nothing was saved.":["Le serveur n'a pas pu être joint, rien n'a donc été enregistré."],"The server could not be reached, so nothing was uploaded.":["Le serveur n'a pas pu être joint, rien n'a donc été téléversé."],"The setting %(setting)s cannot hold the value it was given. Check what this setting takes and try again.":["Le réglage %(setting)s ne peut pas contenir la valeur donnée. Vérifiez ce que ce réglage accepte et réessayez."],"The setting %(setting)s falls outside the others. Keep min below max and the default inside the bounds.":["Le réglage %(setting)s sort des autres. Gardez min sous max et la valeur par défaut dans les limites."],"The settings could not be read, so nothing can be changed here yet.":["Les réglages n'ont pas pu être lus, donc rien ne peut encore être modifié ici."],"The site default":["La langue par défaut du site"],"The site may already hold part of this file. Import it again to see what is left.":["Le site contient peut-être déjà une partie de ce fichier. Importez-le à nouveau pour voir ce qu'il reste."],"The source %(source)s does not offer %(operator)s. Pick one of the comparisons it does offer.":["La source %(source)s n'offre pas %(operator)s. Choisissez une des comparaisons qu'elle offre."],"The theme %(name)s carries no %(file)s, so Gophenberg cannot tell what it is. Put that file at the top level of the zip and package the theme again.":["Le thème %(name)s ne contient aucun %(file)s, Gophenberg ne peut donc pas savoir ce que c'est. Placez ce fichier au premier niveau du zip et réempaquetez le thème."],"The theme %(name)s could not be read, so it cannot serve your site. Upload it again, or choose another theme.":["Le thème %(name)s n'a pas pu être lu, il ne peut donc pas servir votre site. Téléversez-le de nouveau, ou choisissez un autre thème."],"The theme %(name)s did not start, so your site is still served by the theme it had. Ask whoever looks after your site to check the server log for what the theme reported.":["Le thème %(name)s n'a pas démarré, votre site est donc toujours servi par le thème qu'il avait. Demandez à la personne qui s'occupe de votre site de regarder ce que le thème a signalé dans le journal du serveur."],"The theme %(name)s does not carry %(path)s as a file, so there is nothing to run. Package the built theme rather than its source.":["Le thème %(name)s ne contient pas %(path)s comme fichier, il n'y a donc rien à exécuter. Empaquetez le thème construit plutôt que sa source."],"The theme %(name)s does not carry %(path)s as a folder, so its styles and scripts are missing. Package the built theme rather than its source.":["Le thème %(name)s ne contient pas %(path)s comme dossier, ses styles et ses scripts manquent donc. Empaquetez le thème construit plutôt que sa source."],"The theme %(name)s holds a link to another file at %(path)s, and a theme may only carry real files. Replace it and package the theme again.":["Le thème %(name)s contient un lien vers un autre fichier à %(path)s, et un thème ne peut contenir que de vrais fichiers. Remplacez-le et réempaquetez le thème."],"The theme %(name)s is serving your site right now, so it cannot be replaced. Deactivate it first, or install this copy under another name.":["Le thème %(name)s sert votre site en ce moment, il ne peut donc pas être remplacé. Désactivez-le d'abord, ou installez cette copie sous un autre nom."],"The theme %(name)s is the one chosen, but it is not installed, so your site is served by the built-in renderer. Upload the theme again, or choose another one.":["Le thème %(name)s est celui choisi, mais il n'est pas installé, votre site est donc servi par le moteur de rendu intégré. Téléversez de nouveau le thème, ou choisissez-en un autre."],"The theme %(name)s was built on theme kit %(declared)s, and this site serves %(served)s. Build the theme again against a kit this site serves, then install it.":["Le thème %(name)s a été compilé avec le kit de thèmes %(declared)s, et ce site sert %(served)s. Compilez le thème à nouveau avec un kit que ce site sert, puis installez-le."],"The trash could not be emptied.":["La corbeille n'a pas pu être vidée."],"The update failed before anything changed.":["La mise à jour a échoué avant que quoi que ce soit ne change."],"The update to %(to)s failed its start check, and Gophenberg cannot go back to %(from)s on its own.":["La mise à jour vers %(to)s a échoué à sa vérification de démarrage, et Gophenberg ne peut pas revenir à %(from)s de lui-même."],"The update to %(to)s failed.":["La mise à jour vers %(to)s a échoué."],"The update to Gophenberg %(version)s failed to complete. Please attempt the update again now.":["La mise à jour vers Gophenberg %(version)s n'a pas pu aboutir. Veuillez relancer la mise à jour maintenant."],"The updates could not be read, so nothing can be updated here yet.":["Les mises à jour n'ont pas pu être lues, donc rien ne peut encore être mis à jour ici."],"The user could not be created.":["L'utilisateur n'a pas pu être créé."],"The values stored under it do not follow.":["Les valeurs enregistrées dessous ne le suivent pas."],"Theme":["Thème"],"Themes":["Thèmes"],"Themes could not be loaded.":["Les thèmes n'ont pas pu être chargés."],"There is no content type called %(value)s. Pick a type your site holds, or register it first.":["Il n'existe aucun type de contenu appelé %(value)s. Choisissez un type que votre site possède, ou déclarez-le d'abord."],"There is no content type called %(value)s. Pick one of the types your site holds and try again.":["Il n'existe aucun type de contenu appelé %(value)s. Choisissez un des types que votre site possède et réessayez."],"There is no kind of field called %(value)s. Pick one of these instead: %(allowed)s.":["Il n'existe aucun genre de champ appelé %(value)s. Choisissez plutôt parmi ceux-ci : %(allowed)s."],"There is no page kind called %(value)s. Pick one of these instead: %(allowed)s.":["Il n'existe aucun genre de page appelé %(value)s. Choisissez plutôt parmi ceux-ci : %(allowed)s."],"There is no status called %(value)s. Pick one of these instead: %(allowed)s.":["Il n'existe aucun état appelé %(value)s. Choisissez plutôt parmi ceux-ci : %(allowed)s."],"There is nothing at this address. Check the link and try again.":["Il n'y a rien à cette adresse. Vérifiez le lien et réessayez."],"There is nothing to roll back to, because your site has not been through a theme change yet. Install a theme first, then a rollback has somewhere to go.":["Il n'y a rien vers quoi revenir, car votre site n'a pas encore changé de thème. Installez d'abord un thème, et le retour aura alors une destination."],"These files could not be read.":["Ces fichiers n'ont pas pu être lus."],"These were left alone, because nobody confirmed losing them.":["Ceux-ci ont été laissés tels quels, car personne n'a confirmé leur perte."],"This content type does not exist any more. Reload the page to see the types your site holds now.":["Ce type de contenu n'existe plus. Rechargez la page pour voir les types que votre site possède maintenant."],"This content type does not nest, so one of its items cannot sit inside another. Mark the type as Nests first.":["Ce type de contenu ne s'imbrique pas, un de ses éléments ne peut donc pas se trouver dans un autre. Marquez d'abord le type comme Imbriqué."],"This content type has no field called %(field)s. Check the name, or declare the field on the type first.":["Ce type de contenu n'a aucun champ appelé %(field)s. Vérifiez le nom, ou déclarez d'abord le champ sur le type."],"This content type is turned off, so its content is not served or edited. Activate it first.":["Ce type de contenu est désactivé, son contenu n'est donc ni servi ni modifié. Activez-le d'abord."],"This content type still holds content, so it cannot be deleted. Move or delete its items first.":["Ce type de contenu contient encore du contenu, il ne peut donc pas être supprimé. Déplacez ou supprimez d'abord ses éléments."],"This definitions file is larger than the %(max)s bytes Gophenberg reads in one request. Split it, or raise the limit your site runs with.":["Ce fichier de définitions dépasse les %(max)s octets que Gophenberg lit en une requête. Divisez-le, ou relevez la limite de votre site."],"This field holds no layouts yet.":["Ce champ ne contient pas encore de dispositions."],"This field would stand inside too many containers. Put it nearer the top and try again.":["Ce champ se trouverait dans trop de conteneurs. Placez-le plus près du niveau supérieur et réessayez."],"This file could not be opened as a zip. Package the theme again and upload the new file.":["Ce fichier n'a pas pu être ouvert comme zip. Réempaquetez le thème et téléversez le nouveau fichier."],"This file is larger than the upload limit. Upload a smaller file.":["Ce fichier dépasse la limite de téléversement. Téléversez un fichier plus petit."],"This file is named %(extension)s but it holds %(detected)s content. Upload it under a name that matches what is inside it.":["Ce fichier est nommé %(extension)s mais il contient du %(detected)s. Téléversez-le sous un nom qui correspond à ce qu'il contient."],"This file matches the site, so there is nothing to change.":["Ce fichier correspond au site, il n'y a donc rien à changer."],"This file says it was written in format %(declared)s, which is not a version Gophenberg can read. Export the definitions again from the site they came from.":["Ce fichier indique le format %(declared)s, qui n'est pas une version que Gophenberg sait lire. Exportez à nouveau les définitions depuis le site d'origine."],"This file was written in format %(declared)s, and this release reads %(served)s. Upgrade the site the file came from, or this one.":["Ce fichier est écrit au format %(declared)s, et cette version lit %(served)s. Mettez à jour le site d'origine du fichier, ou celui-ci."],"This group holds no fields yet.":["Ce groupe ne contient pas encore de champs."],"This install of Gophenberg has no install root, so it updates by hand.":["Cette installation de Gophenberg n'a pas de racine d'installation, elle se met donc à jour à la main."],"This install of Gophenberg updates by hand.":["Cette installation de Gophenberg se met à jour à la main."],"This is a custom build of Gophenberg, so it updates by hand.":["Il s'agit d'une version compilée sur mesure de Gophenberg, elle se met donc à jour à la main."],"This item cannot go straight to that status from the one it holds now. Save it as a draft first, then try again.":["Cet élément ne peut pas passer directement à cet état depuis celui qu'il a maintenant. Enregistrez-le d'abord comme brouillon, puis réessayez."],"This item does not exist, and it may have been deleted. Go back to the list to see what is there.":["Cet élément n'existe pas, et il a peut-être été supprimé. Revenez à la liste pour voir ce qui s'y trouve."],"This item is already in the trash. Restore it first to work on it again.":["Cet élément est déjà dans la corbeille. Rétablissez-le d'abord pour y retravailler."],"This item is in the trash. Restore it first to work on it again.":["Cet élément est dans la corbeille. Rétablissez-le d'abord pour y retravailler."],"This item is not in the trash, so there is nothing to restore. Open it from the list to work on it as it is.":["Cet élément n'est pas dans la corbeille, il n'y a donc rien à rétablir. Ouvrez-le depuis la liste pour travailler dessus tel quel."],"This item still holds items nested inside it. Move or delete those first.":["Cet élément contient encore des éléments imbriqués. Déplacez-les ou supprimez-les d'abord."],"This kind of field holds no fields inside it. Put the field in a section or a repeater instead.":["Ce type de champ ne contient aucun champ. Placez le champ dans une section ou dans un répéteur."],"This media item is not in the library, and someone may have deleted it. Reload the page to see what is there now.":["Ce média n'est pas dans la bibliothèque, et quelqu'un l'a peut-être supprimé. Rechargez la page pour voir ce qui s'y trouve maintenant."],"This picture could not be read, so nothing was stored. The file may be damaged, so open it on your computer and upload it again.":["Cette image n'a pas pu être lue, rien n'a donc été stocké. Le fichier est peut-être endommagé, ouvrez-le sur votre ordinateur et téléversez-le de nouveau."],"This picture is %(width)s by %(height)s pixels, over the limit of %(max)s pixels in all. Make it smaller and upload it again.":["Cette image fait %(width)s par %(height)s pixels, au-delà de la limite de %(max)s pixels au total. Réduisez-la et téléversez-la de nouveau."],"This post changed elsewhere. Reload before saving again.":["Cet article a changé ailleurs. Rechargez avant d'enregistrer de nouveau."],"This request came from a page on another site, so it was refused. Open the admin on this site and try again.":["Cette requête vient d'une page d'un autre site, elle a donc été refusée. Ouvrez l'administration sur ce site et réessayez."],"This request carried %(attribute)s, which fields do not take. Reload the page so the admin and the server agree again.":["Cette requête portait %(attribute)s, que les champs n'acceptent pas. Rechargez la page pour que l'administration et le serveur concordent à nouveau."],"This request left out %(field)s, which Gophenberg needs. Reload the page and try again.":["Cette requête a omis %(field)s, dont Gophenberg a besoin. Rechargez la page et réessayez."],"This rule reads a source called %(source)s, and nothing on your site declares one. A plugin that added it may have been removed.":["Cette règle lit une source nommée %(source)s, et rien sur votre site n'en déclare. Une extension qui l'ajoutait a pu être retirée."],"This site cannot write to its themes folder, so no theme can be installed. Ask whoever looks after your site to make the folder that %(setting)s points at writable. A read-only mount is the usual cause.":["Ce site ne peut pas écrire dans son dossier de thèmes, aucun thème ne peut donc être installé. Demandez à la personne qui s'occupe de votre site de rendre accessible en écriture le dossier vers lequel pointe %(setting)s. Un montage en lecture seule en est la cause habituelle."],"This site does not check for updates on its own.":["Ce site ne recherche pas de mises à jour de lui-même."],"This site has nowhere to keep themes, so no theme can be installed. Ask whoever looks after your site to point %(setting)s at a folder the server can write to.":["Ce site n'a nulle part où garder les thèmes, aucun thème ne peut donc être installé. Demandez à la personne qui s'occupe de votre site de faire pointer %(setting)s vers un dossier où le serveur peut écrire."],"This site has nowhere to store uploads, so nothing can be uploaded. Ask whoever looks after your site to point %(setting)s at a folder the server can write to.":["Ce site n'a nulle part où stocker les téléversements, rien ne peut donc être téléversé. Demandez à la personne qui s'occupe de votre site de faire pointer %(setting)s vers un dossier où le serveur peut écrire."],"This site will not receive automatic updates for new versions of Gophenberg.":["Ce site ne recevra pas de mises à jour automatiques pour les nouvelles versions de Gophenberg."],"This theme is over the limit of %(max)s bytes, packed or unpacked. Leave out what the theme does not need and package it again.":["Ce thème dépasse la limite de %(max)s octets, compressé ou non. Retirez ce dont le thème n'a pas besoin et réempaquetez-le."],"This type will answer under /%(word)s.":["Ce type répondra sous /%(word)s."],"This update needs a backup of the database, and the site stays down if the new version does not start.":["Cette mise à jour nécessite une sauvegarde de la base de données, et le site reste hors service si la nouvelle version ne démarre pas."],"This zip holds %(entries)s files, more than the %(max)s a theme may carry. Package only the built theme.":["Ce zip contient %(entries)s fichiers, plus que les %(max)s qu'un thème peut contenir. Empaquetez seulement le thème construit."],"Through":["Via"],"Thumbnail":["Miniature"],"Title":["Titre"],"Two field groups in this file share the key %(key)s. Give one of them a different key and import again.":["Deux groupes de champs de ce fichier partagent la clé %(key)s. Donnez une clé différente à l'un d'eux et importez à nouveau."],"Two rule sources are registered under the name %(param)s. A plugin is declaring a source your site already holds.":["Deux sources de règles sont enregistrées sous le nom %(param)s. Une extension déclare une source que votre site possède déjà."],"Type":["Type"],"Type a whole number in both boxes before saving.":["Saisissez un nombre entier dans les deux cases avant d'enregistrer."],"Undo":["Annuler"],"Unpacking the update…":["Décompression de la mise à jour…"],"Unsaved changes":["Modifications non enregistrées"],"Update":["Mettre à jour"],"Update failed.":["La mise à jour a échoué."],"Update to Gophenberg %(version)s?":["Mettre à jour vers Gophenberg %(version)s ?"],"Update to version %(version)s":["Mettre à jour vers la version %(version)s"],"Updates":["Mises à jour"],"Upload theme":["Téléverser un thème"],"Uploaded %s file.":["%s fichier téléversé.","%s fichiers téléversés.","%s fichiers téléversés."],"Users":["Utilisateurs"],"Users could not be loaded.":["Les utilisateurs n'ont pas pu être chargés."],"Value":["Valeur"],"Verifying the unpacked files…":["Vérification des fichiers décompressés…"],"Version":["Version"],"Videos":["Vidéos"],"Visit Site":["Aller sur le site"],"Web address":["Adresse web"],"What each Linked from field reads":["Ce que lit chaque champ Lié depuis"],"What it points at changed, so its stored values go with it.":["Ce qu'il vise a changé, donc ses valeurs enregistrées partent avec lui."],"Where %(group)s appears":["Où apparaît %(group)s"],"While your site is being updated, it keeps serving until Gophenberg restarts on the new version.":["Pendant la mise à jour, votre site reste en ligne jusqu'au redémarrage de Gophenberg sur la nouvelle version."],"Without a rule this field always shows.":["Sans aucune règle ce champ s'affiche toujours."],"Without a rule this group appears nowhere.":["Sans une règle ce groupe n'apparaît nulle part."],"Yes":["Oui"],"Yes or no":["Oui ou non"],"You can update from Gophenberg %(running)s to Gophenberg %(version)s manually:":["Vous pouvez mettre à jour de Gophenberg %(running)s vers Gophenberg %(version)s manuellement :"],"You cannot change your own role.":["Vous ne pouvez pas changer votre propre rôle."],"You cannot update because Gophenberg %(version)s requires PostgreSQL version %(postgresql)s or higher.":["Vous ne pouvez pas mettre à jour car Gophenberg %(version)s nécessite la version %(postgresql)s de PostgreSQL ou une version ultérieure."],"You have the latest version of Gophenberg.":["Vous avez la dernière version de Gophenberg."],"Your language":["Votre langue"],"Your role does not allow %(capability)s.":["Votre rôle ne permet pas %(capability)s."],"Your server pins the site to the theme %(name)s, so themes cannot be changed here. Ask whoever looks after your site to remove the pin.":["Votre serveur fixe le site au thème %(name)s, les thèmes ne peuvent donc pas être changés ici. Demandez à la personne qui s'occupe de votre site de retirer cette fixation."],"Your site always needs one default content type, so this one cannot be turned off or deleted. Make another type the default first.":["Votre site a toujours besoin d'un type de contenu par défaut, celui-ci ne peut donc être ni désactivé ni supprimé. Rendez d'abord un autre type par défaut."],"a content type":["un type de contenu"],"account\u0004Role":["Rôle"],"account\u0004Status":["État"],"action label\u0004Duplicate":["Dupliquer"],"action label\u0004Duplicate…":["Dupliquer…"],"address":["adresse"],"admin section\u0004Content Types":["Types de contenu"],"admin section\u0004Field Groups":["Groupes de champs"],"admin section\u0004Language":["Langue"],"admin section\u0004Media":["Médias"],"admin section\u0004Settings":["Réglages"],"admin section\u0004Themes":["Thèmes"],"column\u0004Date":["Date"],"content type\u0004\"%s\" permanently deleted.":["Type de contenu « %s » supprimé définitivement."],"content type\u0004\"%s\" successfully created.":["Type de contenu « %s » créé avec succès."],"content type\u0004Status":["État"],"field\u0004Name":["Nom"],"field group\u0004Status":["Statut"],"field type\u0004Choice":["Choix"],"field type\u0004Color":["Couleur"],"field type\u0004Date":["Date"],"field type\u0004Flexible content":["Contenu flexible"],"field type\u0004Gallery":["Galerie"],"field type\u0004Kind":["Genre"],"field type\u0004Layout":["Disposition"],"field type\u0004Link":["Lien"],"field type\u0004Media":["Média"],"field type\u0004Range":["Plage"],"field type\u0004Repeater":["Répéteur"],"field type\u0004Section":["Section"],"field type\u0004Select":["Liste déroulante"],"file size\u0004%1$s %2$s":["%1$s %2$s"],"file type group\u0004Archives":["Archives"],"file type group\u0004Audio":["Sons"],"file type group\u0004Video":["Vidéos"],"holds":["contient"],"holds anything":["contient quelque chose"],"https://www.w3.org/WAI/tutorials/images/decision-tree/":["https://www.w3.org/WAI/tutorials/images/decision-tree/"],"image dimensions\u0004%1$s × %2$s":["%1$s par %2$s"],"is":["est"],"is above":["est supérieur à"],"is below":["est inférieur à"],"is empty":["est vide"],"is not":["n'est pas"],"panel button label\u0004Settings":["Réglages"],"person\u0004Name":["Nom"],"post\u0004%s (Copy)":["%s (copie)"],"post\u0004Status":["État"],"post status\u0004Draft":["Brouillon"],"post status\u0004Published":["Publié"],"post status\u0004Trash":["Corbeille"],"post type general name\u0004Pages":["Pages"],"post type general name\u0004Posts":["Articles"],"post type singular name\u0004Page":["Page"],"post type singular name\u0004Post":["Article"],"relation target\u0004None":["Aucun"],"role\u0004Administrator":["Administrateur"],"role\u0004Author":["Auteur"],"role\u0004Editor":["Éditeur"],"role\u0004Member":["Membre"],"role\u0004No role":["Sans rôle"],"status filter\u0004All":["Tout"],"taxonomy general name\u0004Categories":["Catégories"],"taxonomy singular name\u0004Category":["Catégorie"],"theme\u0004Status":["État"],"trash\u0004Restore":["Rétablir"],"unit symbol\u0004B":["o"],"unit symbol\u0004EB":["Eo"],"unit symbol\u0004GB":["Go"],"unit symbol\u0004KB":["Ko"],"unit symbol\u0004MB":["Mo"],"unit symbol\u0004PB":["Po"],"unit symbol\u0004TB":["To"],"unit symbol\u0004YB":["Yo"],"unit symbol\u0004ZB":["Zo"],"v%(version)s":["v%(version)s"],"verb\u0004Trash…":["Mettre à la corbeille…"],"verb\u0004View":["Voir"],"{day} {month} {year}":["{day} {month} {year}"]} diff --git a/languages/es-ES.po b/languages/es-ES.po index 14f6bc2f..d895ff8b 100644 --- a/languages/es-ES.po +++ b/languages/es-ES.po @@ -2086,6 +2086,221 @@ msgstr "Esta instalación de Gophenberg no tiene raíz de instalación, así que msgid "This is a custom build of Gophenberg, so it updates by hand." msgstr "Esta es una compilación propia de Gophenberg, así que se actualiza a mano." +#, fuzzy +msgid "Updates" +msgstr "Actualizaciones" + +#, fuzzy +msgid "%s update available" +msgid_plural "%s updates available" +msgstr[0] "%s actualización disponible" +msgstr[1] "%s de actualizaciones disponibles" +msgstr[2] "%s actualizaciones disponibles" + +#, fuzzy +msgid "Gophenberg %(version)s is available! Please update now." +msgstr "¡Ya está disponible Gophenberg %(version)s! Por favor, actualiza ahora." + +#, fuzzy +msgid "The update to Gophenberg %(version)s failed to complete. Please attempt the update again now." +msgstr "No se ha podido completar la actualización a Gophenberg %(version)s. Por favor, vuelve a intentarlo." + +#, fuzzy +msgid "Gophenberg Updates" +msgstr "Actualizaciones de Gophenberg" + +#, fuzzy +msgid "Current version: %(version)s" +msgstr "Versión actual: %(version)s" + +#, fuzzy +msgid "Last checked on %(date)s at %(time)s." +msgstr "Última comprobación el %(date)s a las %(time)s." + +#, fuzzy +msgid "Check again." +msgstr "Comprobar de nuevo." + +#, fuzzy +msgid "Gophenberg has not checked for updates yet." +msgstr "Gophenberg todavía no ha buscado actualizaciones." + +#, fuzzy +msgid "Check now." +msgstr "Comprobar ahora." + +#, fuzzy +msgid "The next check runs in %(time)s." +msgstr "La próxima comprobación será dentro de %(time)s." + +#, fuzzy +msgid "%s minute" +msgid_plural "%s minutes" +msgstr[0] "%s minuto" +msgstr[1] "%s de minutos" +msgstr[2] "%s minutos" + +#, fuzzy +msgid "%s hour" +msgid_plural "%s hours" +msgstr[0] "%s hora" +msgstr[1] "%s de horas" +msgstr[2] "%s horas" + +#, fuzzy +msgid "%s day" +msgid_plural "%s days" +msgstr[0] "%s día" +msgstr[1] "%s de días" +msgstr[2] "%s días" + +#, fuzzy +msgid "This site does not check for updates on its own." +msgstr "Este sitio no busca actualizaciones por su cuenta." + +#, fuzzy +msgid "The check on %(date)s at %(time)s failed: %(error)s" +msgstr "La comprobación del %(date)s a las %(time)s ha fallado: %(error)s" + +#, fuzzy +msgid "No new updates found." +msgstr "No se han encontrado actualizaciones nuevas." + +#, fuzzy +msgid "This site will not receive automatic updates for new versions of Gophenberg." +msgstr "Este sitio no recibirá actualizaciones automáticas de nuevas versiones de Gophenberg." + +#, fuzzy +msgid "An updated version of Gophenberg is available." +msgstr "Hay disponible una versión actualizada de Gophenberg." + +#, fuzzy +msgid "You have the latest version of Gophenberg." +msgstr "Tienes la última versión de Gophenberg." + +#, fuzzy +msgid "Important: Before updating, please back up your database and files. For help with updates, visit the Updating Gophenberg documentation page." +msgstr "Importante: Antes de actualizar, por favor, haz una copia de seguridad de tu base de datos y de los archivos. Para obtener ayuda con las actualizaciones, visita la página de documentación Actualización de Gophenberg." + +#, fuzzy +msgid "You can update from Gophenberg %(running)s to Gophenberg %(version)s manually:" +msgstr "Puedes actualizar desde Gophenberg %(running)s a Gophenberg %(version)s manualmente:" + +#, fuzzy +msgid "You cannot update because Gophenberg %(version)s requires PostgreSQL version %(postgresql)s or higher." +msgstr "No puedes actualizar porque Gophenberg %(version)s necesita la versión %(postgresql)s o superior de PostgreSQL." + +#, fuzzy +msgid "Gophenberg %(version)s failed its start check on this site. Fix what failed before you try it again." +msgstr "Gophenberg %(version)s no ha superado su comprobación de arranque en este sitio. Corrige lo que ha fallado antes de volver a intentarlo." + +#, fuzzy +msgid "This update needs a backup of the database, and the site stays down if the new version does not start." +msgstr "Esta actualización necesita una copia de seguridad de la base de datos, y el sitio deja de funcionar si la nueva versión no arranca." + +#, fuzzy +msgid "Update to version %(version)s" +msgstr "Actualizar a la versión %(version)s" + +#, fuzzy +msgid "Re-install version %(version)s" +msgstr "Reinstalar la versión %(version)s" + +#, fuzzy +msgid "While your site is being updated, it keeps serving until Gophenberg restarts on the new version." +msgstr "Mientras tu sitio está siendo actualizado, sigue funcionando hasta que Gophenberg se reinicia con la nueva versión." + +#, fuzzy +msgid "This install of Gophenberg updates by hand." +msgstr "Esta instalación de Gophenberg se actualiza a mano." + +#, fuzzy +msgid "Follow the steps on the Updating Gophenberg documentation page to update by hand." +msgstr "Sigue los pasos de la página de documentación Actualización de Gophenberg para actualizar a mano." + +#, fuzzy +msgid "Backups kept: %(kept)s of %(limit)s, taken on %(date)s at %(time)s." +msgid_plural "Backups kept: %(kept)s of %(limit)s, the newest on %(date)s at %(time)s." +msgstr[0] "Copias de seguridad guardadas: %(kept)s de %(limit)s, hecha el %(date)s a las %(time)s." +msgstr[1] "Copias de seguridad guardadas: %(kept)s de %(limit)s, la más reciente del %(date)s a las %(time)s." +msgstr[2] "Copias de seguridad guardadas: %(kept)s de %(limit)s, la más reciente del %(date)s a las %(time)s." + +#, fuzzy +msgid "Update to Gophenberg %(version)s?" +msgstr "¿Actualizar a Gophenberg %(version)s?" + +#, fuzzy +msgid "A backup of the database is taken first, and Gophenberg goes back to %(running)s on its own if the new version does not start." +msgstr "Primero se hace una copia de seguridad de la base de datos, y Gophenberg vuelve a %(running)s por su cuenta si la nueva versión no arranca." + +#, fuzzy +msgid "A backup of the database is taken first, and the site stays down until you restore it if the new version does not start." +msgstr "Primero se hace una copia de seguridad de la base de datos, y el sitio deja de funcionar hasta que la restaures si la nueva versión no arranca." + +#, fuzzy +msgid "Downloading Gophenberg %(version)s…" +msgstr "Descargando Gophenberg %(version)s…" + +#, fuzzy +msgid "Unpacking the update…" +msgstr "Descomprimiendo la actualización…" + +#, fuzzy +msgid "Verifying the unpacked files…" +msgstr "Verificando los archivos descomprimidos…" + +#, fuzzy +msgid "Backing up the database…" +msgstr "Haciendo copia de seguridad de la base de datos…" + +#, fuzzy +msgid "Restarting Gophenberg…" +msgstr "Reiniciando Gophenberg…" + +#, fuzzy +msgid "Checking the new version…" +msgstr "Comprobando la nueva versión…" + +#, fuzzy +msgid "Gophenberg updated successfully." +msgstr "Gophenberg se ha actualizado correctamente." + +#, fuzzy +msgid "Reload the admin" +msgstr "Recargar la administración" + +#, fuzzy +msgid "The update to %(to)s failed." +msgstr "La actualización a %(to)s ha fallado." + +#, fuzzy +msgid "Gophenberg went back to %(from)s and is running normally." +msgstr "Gophenberg ha vuelto a %(from)s y funciona con normalidad." + +#, fuzzy +msgid "The update failed before anything changed." +msgstr "La actualización ha fallado antes de cambiar nada." + +#, fuzzy +msgid "Gophenberg has not come back yet." +msgstr "Gophenberg todavía no ha vuelto." + +#, fuzzy +msgid "Gophenberg stopped after the switch so that its service manager, such as systemd, starts the new version. Check that the service manager starts it again after exit code 75, and run update:status on the server to see where the update stands." +msgstr "Gophenberg se ha detenido tras el cambio para que su gestor de servicios, como systemd, arranque la nueva versión. Comprueba que el gestor de servicios lo vuelve a arrancar tras el código de salida 75, y ejecuta update:status en el servidor para ver en qué punto está la actualización." + +#, fuzzy +msgid "The updates could not be read, so nothing can be updated here yet." +msgstr "No se han podido leer las actualizaciones, así que todavía no se puede actualizar nada aquí." + +#, fuzzy +msgid "The update to %(to)s failed its start check, and Gophenberg cannot go back to %(from)s on its own." +msgstr "La actualización a %(to)s no ha superado su comprobación de arranque, y Gophenberg no puede volver a %(from)s por su cuenta." + +#, fuzzy +msgid "Run update:status on the server to see the backup taken before the update. Then restore that backup, or fix what failed and start Gophenberg again." +msgstr "Ejecuta update:status en el servidor para ver la copia de seguridad hecha antes de la actualización. Después, restaura esa copia de seguridad, o corrige lo que ha fallado y vuelve a arrancar Gophenberg." + #, fuzzy msgid "Are you sure you want to move \"%s\" to the trash?" msgstr "¿Seguro que quieres mover «%s» a la papelera?" diff --git a/languages/fr-FR.po b/languages/fr-FR.po index 55547f68..8d21c220 100644 --- a/languages/fr-FR.po +++ b/languages/fr-FR.po @@ -554,6 +554,221 @@ msgstr "Cette installation de Gophenberg n'a pas de racine d'installation, elle msgid "This is a custom build of Gophenberg, so it updates by hand." msgstr "Il s'agit d'une version compilée sur mesure de Gophenberg, elle se met donc à jour à la main." +#, fuzzy +msgid "Updates" +msgstr "Mises à jour" + +#, fuzzy +msgid "%s update available" +msgid_plural "%s updates available" +msgstr[0] "%s mise à jour disponible" +msgstr[1] "%s mises à jour disponibles" +msgstr[2] "%s mises à jour disponibles" + +#, fuzzy +msgid "Gophenberg %(version)s is available! Please update now." +msgstr "Gophenberg %(version)s est disponible ! Veuillez faire la mise à jour maintenant." + +#, fuzzy +msgid "The update to Gophenberg %(version)s failed to complete. Please attempt the update again now." +msgstr "La mise à jour vers Gophenberg %(version)s n'a pas pu aboutir. Veuillez relancer la mise à jour maintenant." + +#, fuzzy +msgid "Gophenberg Updates" +msgstr "Mises à jour de Gophenberg" + +#, fuzzy +msgid "Current version: %(version)s" +msgstr "Version actuelle : %(version)s" + +#, fuzzy +msgid "Last checked on %(date)s at %(time)s." +msgstr "Dernière vérification le %(date)s à %(time)s." + +#, fuzzy +msgid "Check again." +msgstr "Vérifier à nouveau." + +#, fuzzy +msgid "Gophenberg has not checked for updates yet." +msgstr "Gophenberg n'a pas encore recherché de mises à jour." + +#, fuzzy +msgid "Check now." +msgstr "Vérifier maintenant." + +#, fuzzy +msgid "The next check runs in %(time)s." +msgstr "La prochaine vérification aura lieu dans %(time)s." + +#, fuzzy +msgid "%s minute" +msgid_plural "%s minutes" +msgstr[0] "%s minute" +msgstr[1] "%s minutes" +msgstr[2] "%s minutes" + +#, fuzzy +msgid "%s hour" +msgid_plural "%s hours" +msgstr[0] "%s heure" +msgstr[1] "%s heures" +msgstr[2] "%s heures" + +#, fuzzy +msgid "%s day" +msgid_plural "%s days" +msgstr[0] "%s jour" +msgstr[1] "%s jours" +msgstr[2] "%s jours" + +#, fuzzy +msgid "This site does not check for updates on its own." +msgstr "Ce site ne recherche pas de mises à jour de lui-même." + +#, fuzzy +msgid "The check on %(date)s at %(time)s failed: %(error)s" +msgstr "La vérification du %(date)s à %(time)s a échoué : %(error)s" + +#, fuzzy +msgid "No new updates found." +msgstr "Aucune nouvelle mise à jour trouvée." + +#, fuzzy +msgid "This site will not receive automatic updates for new versions of Gophenberg." +msgstr "Ce site ne recevra pas de mises à jour automatiques pour les nouvelles versions de Gophenberg." + +#, fuzzy +msgid "An updated version of Gophenberg is available." +msgstr "Une version mise à jour de Gophenberg est disponible." + +#, fuzzy +msgid "You have the latest version of Gophenberg." +msgstr "Vous avez la dernière version de Gophenberg." + +#, fuzzy +msgid "Important: Before updating, please back up your database and files. For help with updates, visit the Updating Gophenberg documentation page." +msgstr "Important : avant de mettre à jour, veuillez sauvegarder votre base de données et vos fichiers. Pour obtenir de l'aide sur les mises à jour, consultez la page de documentation Mettre à jour Gophenberg." + +#, fuzzy +msgid "You can update from Gophenberg %(running)s to Gophenberg %(version)s manually:" +msgstr "Vous pouvez mettre à jour de Gophenberg %(running)s vers Gophenberg %(version)s manuellement :" + +#, fuzzy +msgid "You cannot update because Gophenberg %(version)s requires PostgreSQL version %(postgresql)s or higher." +msgstr "Vous ne pouvez pas mettre à jour car Gophenberg %(version)s nécessite la version %(postgresql)s de PostgreSQL ou une version ultérieure." + +#, fuzzy +msgid "Gophenberg %(version)s failed its start check on this site. Fix what failed before you try it again." +msgstr "Gophenberg %(version)s a échoué à sa vérification de démarrage sur ce site. Corrigez ce qui a échoué avant de réessayer." + +#, fuzzy +msgid "This update needs a backup of the database, and the site stays down if the new version does not start." +msgstr "Cette mise à jour nécessite une sauvegarde de la base de données, et le site reste hors service si la nouvelle version ne démarre pas." + +#, fuzzy +msgid "Update to version %(version)s" +msgstr "Mettre à jour vers la version %(version)s" + +#, fuzzy +msgid "Re-install version %(version)s" +msgstr "Réinstaller la version %(version)s" + +#, fuzzy +msgid "While your site is being updated, it keeps serving until Gophenberg restarts on the new version." +msgstr "Pendant la mise à jour, votre site reste en ligne jusqu'au redémarrage de Gophenberg sur la nouvelle version." + +#, fuzzy +msgid "This install of Gophenberg updates by hand." +msgstr "Cette installation de Gophenberg se met à jour à la main." + +#, fuzzy +msgid "Follow the steps on the Updating Gophenberg documentation page to update by hand." +msgstr "Suivez les étapes de la page de documentation Mettre à jour Gophenberg pour mettre à jour à la main." + +#, fuzzy +msgid "Backups kept: %(kept)s of %(limit)s, taken on %(date)s at %(time)s." +msgid_plural "Backups kept: %(kept)s of %(limit)s, the newest on %(date)s at %(time)s." +msgstr[0] "Sauvegardes conservées : %(kept)s sur %(limit)s, faite le %(date)s à %(time)s." +msgstr[1] "Sauvegardes conservées : %(kept)s sur %(limit)s, la plus récente le %(date)s à %(time)s." +msgstr[2] "Sauvegardes conservées : %(kept)s sur %(limit)s, la plus récente le %(date)s à %(time)s." + +#, fuzzy +msgid "Update to Gophenberg %(version)s?" +msgstr "Mettre à jour vers Gophenberg %(version)s ?" + +#, fuzzy +msgid "A backup of the database is taken first, and Gophenberg goes back to %(running)s on its own if the new version does not start." +msgstr "Une sauvegarde de la base de données est faite d'abord, et Gophenberg revient de lui-même à %(running)s si la nouvelle version ne démarre pas." + +#, fuzzy +msgid "A backup of the database is taken first, and the site stays down until you restore it if the new version does not start." +msgstr "Une sauvegarde de la base de données est faite d'abord, et le site reste hors service jusqu'à ce que vous la restauriez si la nouvelle version ne démarre pas." + +#, fuzzy +msgid "Downloading Gophenberg %(version)s…" +msgstr "Téléchargement de Gophenberg %(version)s…" + +#, fuzzy +msgid "Unpacking the update…" +msgstr "Décompression de la mise à jour…" + +#, fuzzy +msgid "Verifying the unpacked files…" +msgstr "Vérification des fichiers décompressés…" + +#, fuzzy +msgid "Backing up the database…" +msgstr "Sauvegarde de la base de données…" + +#, fuzzy +msgid "Restarting Gophenberg…" +msgstr "Redémarrage de Gophenberg…" + +#, fuzzy +msgid "Checking the new version…" +msgstr "Vérification de la nouvelle version…" + +#, fuzzy +msgid "Gophenberg updated successfully." +msgstr "Gophenberg a été mis à jour avec succès." + +#, fuzzy +msgid "Reload the admin" +msgstr "Recharger l'administration" + +#, fuzzy +msgid "The update to %(to)s failed." +msgstr "La mise à jour vers %(to)s a échoué." + +#, fuzzy +msgid "Gophenberg went back to %(from)s and is running normally." +msgstr "Gophenberg est revenu à %(from)s et fonctionne normalement." + +#, fuzzy +msgid "The update failed before anything changed." +msgstr "La mise à jour a échoué avant que quoi que ce soit ne change." + +#, fuzzy +msgid "Gophenberg has not come back yet." +msgstr "Gophenberg n'est pas encore revenu." + +#, fuzzy +msgid "Gophenberg stopped after the switch so that its service manager, such as systemd, starts the new version. Check that the service manager starts it again after exit code 75, and run update:status on the server to see where the update stands." +msgstr "Gophenberg s'est arrêté après le changement pour que son gestionnaire de services, comme systemd, démarre la nouvelle version. Vérifiez que le gestionnaire de services le redémarre après le code de sortie 75, et lancez update:status sur le serveur pour voir où en est la mise à jour." + +#, fuzzy +msgid "The updates could not be read, so nothing can be updated here yet." +msgstr "Les mises à jour n'ont pas pu être lues, donc rien ne peut encore être mis à jour ici." + +#, fuzzy +msgid "The update to %(to)s failed its start check, and Gophenberg cannot go back to %(from)s on its own." +msgstr "La mise à jour vers %(to)s a échoué à sa vérification de démarrage, et Gophenberg ne peut pas revenir à %(from)s de lui-même." + +#, fuzzy +msgid "Run update:status on the server to see the backup taken before the update. Then restore that backup, or fix what failed and start Gophenberg again." +msgstr "Exécutez update:status sur le serveur pour voir la sauvegarde faite avant la mise à jour. Ensuite, restaurez cette sauvegarde, ou corrigez ce qui a échoué et redémarrez Gophenberg." + #, fuzzy msgid "Gophenberg could not read what your browser sent. Reload the page and try again, and tell whoever looks after your site if it keeps happening." msgstr "Gophenberg n'a pas pu lire ce que votre navigateur a envoyé. Rechargez la page et réessayez, et prévenez la personne qui s'occupe de votre site si cela continue." diff --git a/languages/gophenberg.pot b/languages/gophenberg.pot index 8354cbba..854a504c 100644 --- a/languages/gophenberg.pot +++ b/languages/gophenberg.pot @@ -220,6 +220,16 @@ msgid_plural "%s content types permanently deleted." msgstr[0] "" msgstr[1] "" +msgid "%s day" +msgid_plural "%s days" +msgstr[0] "" +msgstr[1] "" + +msgid "%s hour" +msgid_plural "%s hours" +msgstr[0] "" +msgstr[1] "" + msgid "%s item could not be moved to the trash." msgid_plural "%s items could not be moved to the trash." msgstr[0] "" @@ -250,6 +260,11 @@ msgid_plural "%s items stay in the trash." msgstr[0] "" msgstr[1] "" +msgid "%s minute" +msgid_plural "%s minutes" +msgstr[0] "" +msgstr[1] "" + msgid "%s page has been restored." msgid_plural "%s pages have been restored." msgstr[0] "" @@ -260,15 +275,32 @@ msgid_plural "%s posts have been restored." msgstr[0] "" msgstr[1] "" +msgid "%s update available" +msgid_plural "%s updates available" +msgstr[0] "" +msgstr[1] "" + msgid "(no title)" msgstr "" +msgid "Gophenberg %(version)s is available! Please update now." +msgstr "" + +msgid "Important: Before updating, please back up your database and files. For help with updates, visit the Updating Gophenberg documentation page." +msgstr "" + msgid "A %(kind)s field does not take a setting called %(setting)s. Remove it and try again." msgstr "" msgid "A Linked from field stands on its own, not inside a section or a repeater. Declare %(field)s beside the container." msgstr "" +msgid "A backup of the database is taken first, and Gophenberg goes back to %(running)s on its own if the new version does not start." +msgstr "" + +msgid "A backup of the database is taken first, and the site stays down until you restore it if the new version does not start." +msgstr "" + msgid "A content type needs a singular and a plural name, like Guide and Guides. Fill both in and try again." msgstr "" @@ -431,6 +463,9 @@ msgstr "" msgid "An item cannot sit inside itself, or inside one of the items nested under it. Pick a parent outside this branch." msgstr "" +msgid "An updated version of Gophenberg is available." +msgstr "" + msgid "Another account wrote this, and only its author, an editor or an administrator may change it. You can still read it." msgstr "" @@ -479,6 +514,14 @@ msgstr "" msgid "Back to the latest posts" msgstr "" +msgid "Backing up the database…" +msgstr "" + +msgid "Backups kept: %(kept)s of %(limit)s, taken on %(date)s at %(time)s." +msgid_plural "Backups kept: %(kept)s of %(limit)s, the newest on %(date)s at %(time)s." +msgstr[0] "" +msgstr[1] "" + msgid "Block" msgstr "" @@ -512,9 +555,18 @@ msgstr "" msgid "Change the role of %(name)s" msgstr "" +msgid "Check again." +msgstr "" + +msgid "Check now." +msgstr "" + msgid "Checkbox group" msgstr "" +msgid "Checking the new version…" +msgstr "" + msgid "Choices" msgstr "" @@ -587,6 +639,9 @@ msgstr "" msgid "Created" msgstr "" +msgid "Current version: %(version)s" +msgstr "" + msgid "Date added" msgstr "" @@ -690,6 +745,9 @@ msgstr "" msgid "Done. The site now holds what the file describes." msgstr "" +msgid "Downloading Gophenberg %(version)s…" +msgstr "" + msgid "Draft saved." msgstr "" @@ -780,12 +838,21 @@ msgstr "" msgid "Follow the browser" msgstr "" +msgid "Follow the steps on the Updating Gophenberg documentation page to update by hand." +msgstr "" + msgid "From %(plugin)s" msgstr "" msgid "Full Size" msgstr "" +msgid "Gophenberg %(version)s failed its start check on this site. Fix what failed before you try it again." +msgstr "" + +msgid "Gophenberg Updates" +msgstr "" + msgid "Gophenberg cannot start this update: %(reason)s" msgstr "" @@ -807,6 +874,12 @@ msgstr "" msgid "Gophenberg has no autosave of yours for this item. Open the item to see the version that is stored." msgstr "" +msgid "Gophenberg has not checked for updates yet." +msgstr "" + +msgid "Gophenberg has not come back yet." +msgstr "" + msgid "Gophenberg holds no kind of definition called %(subject)s, so nothing was taken over. Reload the page so the admin and the server agree again." msgstr "" @@ -816,6 +889,15 @@ msgstr "" msgid "Gophenberg keeps this word for itself, so no content type can answer under it. Pick a different route word." msgstr "" +msgid "Gophenberg stopped after the switch so that its service manager, such as systemd, starts the new version. Check that the service manager starts it again after exit code 75, and run update:status on the server to see where the update stands." +msgstr "" + +msgid "Gophenberg updated successfully." +msgstr "" + +msgid "Gophenberg went back to %(from)s and is running normally." +msgstr "" + msgid "Group" msgstr "" @@ -897,6 +979,9 @@ msgstr "" msgid "Large" msgstr "" +msgid "Last checked on %(date)s at %(time)s." +msgstr "" + msgid "Leave empty if decorative." msgstr "" @@ -1085,6 +1170,9 @@ msgstr "" msgid "No media items yet." msgstr "" +msgid "No new updates found." +msgstr "" + msgid "No page lives at this address." msgstr "" @@ -1229,6 +1317,9 @@ msgstr "" msgid "Radio group" msgstr "" +msgid "Re-install version %(version)s" +msgstr "" + msgid "Reads from" msgstr "" @@ -1238,6 +1329,9 @@ msgstr "" msgid "Relation" msgstr "" +msgid "Reload the admin" +msgstr "" + msgid "Remove" msgstr "" @@ -1268,6 +1362,9 @@ msgstr "" msgid "Required" msgstr "" +msgid "Restarting Gophenberg…" +msgstr "" + msgid "Restore" msgstr "" @@ -1295,6 +1392,9 @@ msgstr "" msgid "Rules showing %(field)s" msgstr "" +msgid "Run update:status on the server to see the backup taken before the update. Then restore that backup, or fix what failed and start Gophenberg again." +msgstr "" + msgid "Save" msgstr "" @@ -1462,6 +1562,9 @@ msgstr "" msgid "The built-in renderer is serving the public site." msgstr "" +msgid "The check on %(date)s at %(time)s failed: %(error)s" +msgstr "" + msgid "The content type this field points at is not named in a shape Gophenberg accepts. Give it a key that starts with a lowercase letter and then holds only lowercase letters, numbers and hyphens." msgstr "" @@ -1558,6 +1661,9 @@ msgstr "" msgid "The new order has to name every field of this content type exactly once. Reload the page and move the fields again." msgstr "" +msgid "The next check runs in %(time)s." +msgstr "" + msgid "The number of revisions to keep has to be a whole number, and it cannot be negative. Enter a different number." msgstr "" @@ -1636,6 +1742,21 @@ msgstr "" msgid "The trash could not be emptied." msgstr "" +msgid "The update failed before anything changed." +msgstr "" + +msgid "The update to %(to)s failed its start check, and Gophenberg cannot go back to %(from)s on its own." +msgstr "" + +msgid "The update to %(to)s failed." +msgstr "" + +msgid "The update to Gophenberg %(version)s failed to complete. Please attempt the update again now." +msgstr "" + +msgid "The updates could not be read, so nothing can be updated here yet." +msgstr "" + msgid "The user could not be created." msgstr "" @@ -1726,6 +1847,9 @@ msgstr "" msgid "This install of Gophenberg has no install root, so it updates by hand." msgstr "" +msgid "This install of Gophenberg updates by hand." +msgstr "" + msgid "This is a custom build of Gophenberg, so it updates by hand." msgstr "" @@ -1777,18 +1901,27 @@ msgstr "" msgid "This site cannot write to its themes folder, so no theme can be installed. Ask whoever looks after your site to make the folder that %(setting)s points at writable. A read-only mount is the usual cause." msgstr "" +msgid "This site does not check for updates on its own." +msgstr "" + msgid "This site has nowhere to keep themes, so no theme can be installed. Ask whoever looks after your site to point %(setting)s at a folder the server can write to." msgstr "" msgid "This site has nowhere to store uploads, so nothing can be uploaded. Ask whoever looks after your site to point %(setting)s at a folder the server can write to." msgstr "" +msgid "This site will not receive automatic updates for new versions of Gophenberg." +msgstr "" + msgid "This theme is over the limit of %(max)s bytes, packed or unpacked. Leave out what the theme does not need and package it again." msgstr "" msgid "This type will answer under /%(word)s." msgstr "" +msgid "This update needs a backup of the database, and the site stays down if the new version does not start." +msgstr "" + msgid "This zip holds %(entries)s files, more than the %(max)s a theme may carry. Package only the built theme." msgstr "" @@ -1816,6 +1949,9 @@ msgstr "" msgid "Undo" msgstr "" +msgid "Unpacking the update…" +msgstr "" + msgid "Unsaved changes" msgstr "" @@ -1825,6 +1961,15 @@ msgstr "" msgid "Update failed." msgstr "" +msgid "Update to Gophenberg %(version)s?" +msgstr "" + +msgid "Update to version %(version)s" +msgstr "" + +msgid "Updates" +msgstr "" + msgid "Upload theme" msgstr "" @@ -1842,6 +1987,9 @@ msgstr "" msgid "Value" msgstr "" +msgid "Verifying the unpacked files…" +msgstr "" + msgid "Version" msgstr "" @@ -1863,6 +2011,9 @@ msgstr "" msgid "Where %(group)s appears" msgstr "" +msgid "While your site is being updated, it keeps serving until Gophenberg restarts on the new version." +msgstr "" + msgid "Without a rule this field always shows." msgstr "" @@ -1875,9 +2026,18 @@ msgstr "" msgid "Yes or no" msgstr "" +msgid "You can update from Gophenberg %(running)s to Gophenberg %(version)s manually:" +msgstr "" + msgid "You cannot change your own role." msgstr "" +msgid "You cannot update because Gophenberg %(version)s requires PostgreSQL version %(postgresql)s or higher." +msgstr "" + +msgid "You have the latest version of Gophenberg." +msgstr "" + msgid "Your language" msgstr "" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 25df412b..700b9605 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -141,8 +141,8 @@ importers: specifier: workspace:* version: link:../sdk/frontend '@gopherium/godmin': - specifier: 0.25.0 - version: 0.25.0(95cb8e83355dc3cd0ae6db4441fc2ea1) + specifier: 0.26.0 + version: 0.26.0(95cb8e83355dc3cd0ae6db4441fc2ea1) '@gopherium/gottext': specifier: 0.7.0 version: 0.7.0(@wordpress/i18n@6.30.0)(gettext-extractor@4.0.6)(react@19.3.1) @@ -158,6 +158,9 @@ importers: '@wordpress/date': specifier: 5.57.0 version: 5.57.0 + '@wordpress/element': + specifier: 9.0.0 + version: 9.0.0(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) '@wordpress/i18n': specifier: 6.30.0 version: 6.30.0 @@ -266,8 +269,8 @@ importers: sdk/frontend: dependencies: '@gopherium/godmin': - specifier: 0.25.0 - version: 0.25.0(95cb8e83355dc3cd0ae6db4441fc2ea1) + specifier: 0.26.0 + version: 0.26.0(95cb8e83355dc3cd0ae6db4441fc2ea1) '@gopherium/react-auth': specifier: 0.15.0 version: 0.15.0(2d3f16a3b2e3dd70991c065c2099a2ee) @@ -1285,8 +1288,8 @@ packages: '@floating-ui/utils@0.2.12': resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==} - '@gopherium/godmin@0.25.0': - resolution: {integrity: sha512-X1stZFI7Hg1voaruRqjj59HmfLdPblw+9FaioyJZ6fc1nNwYz6m2DwxSJeDPRwdNbVp4RLcMo/fB4l6Us3UUsA==} + '@gopherium/godmin@0.26.0': + resolution: {integrity: sha512-xRqCoi1nEmP/Nr6f1kOGY0U30OgZ3YRPb3wCFDfa4qxusNQSjIfNUrWP6X+7rj519cclIFl47LdCcBW9mWMVTA==} peerDependencies: '@tanstack/react-router': ^1.170.44 '@testing-library/react': ^16.3.2 @@ -7005,7 +7008,7 @@ snapshots: '@floating-ui/utils@0.2.12': {} - '@gopherium/godmin@0.25.0(95cb8e83355dc3cd0ae6db4441fc2ea1)': + '@gopherium/godmin@0.26.0(95cb8e83355dc3cd0ae6db4441fc2ea1)': dependencies: '@wordpress/a11y': 4.57.0 '@wordpress/i18n': 6.30.0 diff --git a/sdk/frontend/capabilities.ts b/sdk/frontend/capabilities.ts index 7e6b9168..59b48374 100644 --- a/sdk/frontend/capabilities.ts +++ b/sdk/frontend/capabilities.ts @@ -33,6 +33,9 @@ export const MANAGE_SETTINGS: Capability = 'manage_settings' /** The capability changing content and media another account wrote. */ export const CHANGE_OTHERS_WORK: Capability = 'change_others_work' +/** The capability checking for and installing a new version of Gophenberg. */ +export const UPDATE_CORE: Capability = 'update_core' + /** * Reports whether an account carrying the given capabilities may change work the author owns. * @param capabilities - The capabilities the session carries, missing counting as none. diff --git a/sdk/frontend/index.ts b/sdk/frontend/index.ts index 015e067f..20607473 100644 --- a/sdk/frontend/index.ts +++ b/sdk/frontend/index.ts @@ -48,6 +48,7 @@ export { Notice, SelectControl, Skeleton, + Spinner, Stack, Tabs, Text, @@ -80,6 +81,7 @@ export { trash as trashIcon, undo as undoIcon, chevronUp as upIcon, + update as updateIcon, upload as uploadIcon, video as videoIcon, } from '@wordpress/icons' @@ -104,6 +106,7 @@ export { MANAGE_TYPES, MANAGE_USERS, MEMBER, + UPDATE_CORE, sessionMayChange, } from './capabilities' export { can, useSession } from '@gopherium/react-auth' diff --git a/sdk/frontend/package.json b/sdk/frontend/package.json index 6437f31d..e94035cd 100644 --- a/sdk/frontend/package.json +++ b/sdk/frontend/package.json @@ -11,7 +11,7 @@ "./testing": "./testing.tsx" }, "dependencies": { - "@gopherium/godmin": "0.25.0", + "@gopherium/godmin": "0.26.0", "@gopherium/react-auth": "0.15.0", "@tanstack/react-query": "^5.102.8", "@wordpress/a11y": "4.57.0", diff --git a/sdk/frontend/test/capabilities.test.ts b/sdk/frontend/test/capabilities.test.ts index 519f87bc..85389fdd 100644 --- a/sdk/frontend/test/capabilities.test.ts +++ b/sdk/frontend/test/capabilities.test.ts @@ -12,6 +12,7 @@ import { MANAGE_TYPES, MANAGE_USERS, MEMBER, + UPDATE_CORE, can, sessionMayChange, } from '../index' @@ -21,11 +22,17 @@ test('a session holds exactly the capabilities it lists, a plugin capability inc expect(can(session, MANAGE_THEMES)).toBe(true) expect(can(session, 'events.manage')).toBe(true) - for (const capability of [MANAGE_USERS, MANAGE_TYPES, MANAGE_SETTINGS, CHANGE_OTHERS_WORK]) { + for (const capability of [MANAGE_USERS, MANAGE_TYPES, MANAGE_SETTINGS, CHANGE_OTHERS_WORK, UPDATE_CORE]) { expect(can(session, capability)).toBe(false) } }) +test('names the capability updating Gophenberg, which a session holds only when it lists it', () => { + expect(UPDATE_CORE).toBe('update_core') + expect(can({ ...defaultUser, role: 'admin', capabilities: [UPDATE_CORE] }, UPDATE_CORE)).toBe(true) + expect(can({ ...defaultUser, role: 'editor', capabilities: [CHANGE_OTHERS_WORK] }, UPDATE_CORE)).toBe(false) +}) + test('names the capability entering the admin, which a member never holds', () => { const member = { ...defaultUser, role: MEMBER, capabilities: [] } diff --git a/sdk/frontend/test/menu-icons.test.ts b/sdk/frontend/test/menu-icons.test.ts index 52d421e1..b8e9be8c 100644 --- a/sdk/frontend/test/menu-icons.test.ts +++ b/sdk/frontend/test/menu-icons.test.ts @@ -13,6 +13,7 @@ import { page, post, settings, + update, video, } from '@wordpress/icons' import { Tooltip as UiTooltip } from '@wordpress/ui' @@ -32,6 +33,7 @@ import { postIcon, settingsIcon, Tooltip, + updateIcon, videoIcon, } from '../index' @@ -45,6 +47,7 @@ test('hands the sidebar rows the glyphs WordPress draws them with', () => { expect(languageIcon).toBe(language) expect(customPostTypeIcon).toBe(customPostType) expect(listIcon).toBe(list) + expect(updateIcon).toBe(update) }) test('hands a media card the glyph WordPress draws for each kind of file', () => { diff --git a/sdk/frontend/test/spinner.test.ts b/sdk/frontend/test/spinner.test.ts new file mode 100644 index 00000000..d1cee6aa --- /dev/null +++ b/sdk/frontend/test/spinner.test.ts @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: Apache-2.0 + +import * as wpds from '@wordpress/ui' +import { expect, test } from 'vitest' + +import { Spinner } from '../index' + +test('hands plugins the spinner WPDS marks a step under way with', () => { + expect(Spinner).toBe(wpds.Spinner) +}) diff --git a/test/e2e/tests/roles.spec.ts b/test/e2e/tests/roles.spec.ts index 5d80b69a..0aa7ad3d 100644 --- a/test/e2e/tests/roles.spec.ts +++ b/test/e2e/tests/roles.spec.ts @@ -48,6 +48,7 @@ test.describe('an author', () => { await expect(menu.getByRole('link', { name: 'Users' })).toHaveCount(0) await expect(menu.getByRole('link', { name: 'Themes' })).toHaveCount(0) await expect(menu.getByRole('link', { name: 'Content Types' })).toHaveCount(0) + await expect(menu.getByRole('link', { name: /^Updates/ })).toHaveCount(0) }) test('is returned to the default list from a pasted admin link', async ({ page }) => { @@ -100,6 +101,7 @@ test.describe('an editor', () => { await expect(menu.getByRole('link', { name: 'Media' })).toBeVisible() await expect(menu.getByRole('link', { name: 'Users' })).toHaveCount(0) await expect(menu.getByRole('link', { name: 'Themes' })).toHaveCount(0) + await expect(menu.getByRole('link', { name: /^Updates/ })).toHaveCount(0) }) test('is refused the theme list by the API', async ({ request }) => { diff --git a/test/e2e/tests/updates.spec.ts b/test/e2e/tests/updates.spec.ts new file mode 100644 index 00000000..a3dbee3b --- /dev/null +++ b/test/e2e/tests/updates.spec.ts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { expect, test } from '@playwright/test' + +test('an administrator reaches the Updates screen from the sidebar and sees the version that runs', async ({ page }) => { + const answered = await page.request.get('/api/version') + expect(answered.ok()).toBe(true) + const { version } = (await answered.json()) as { version: string } + + await page.goto('/admin/') + await page.getByRole('region', { name: 'Navigation' }).getByRole('link', { name: /^Updates/ }).click() + + await expect(page).toHaveURL(/\/admin\/update-core$/) + await expect(page.getByRole('heading', { level: 2, name: 'Gophenberg Updates' })).toBeVisible() + await expect(page.getByText(`Current version: ${version}`)).toBeVisible() + await expect(page.getByText('Gophenberg has not checked for updates yet.')).toBeVisible() + await expect(page.getByText('This site does not check for updates on its own.')).toBeVisible() +}) diff --git a/test/features/features/core-updates.feature b/test/features/features/core-updates.feature index 03089249..22c7c45e 100644 --- a/test/features/features/core-updates.feature +++ b/test/features/features/core-updates.feature @@ -15,7 +15,9 @@ Feature: Operators and administrators update the core and see where it stands A step that fails leaves which update failed, when, at which step and why. An administrator asks the site for the same: the version that runs, whether this install updates itself, the refused versions, the - last update, the backups kept and when the next check runs. + last update, the backups kept and when the next check runs. Once the + site runs the version a check offered, or the version an update + failed to reach, it names neither. An administrator also starts an update from the admin. The site runs the checks that need no download first and answers at once when one refuses. It runs the rest on its own, one update at a time, and once @@ -203,6 +205,18 @@ Feature: Operators and administrators update the core and see where it stands Then the site names "99.0.0" as refused And the site names the update from this version to "99.0.0" at the step "rolled-back" + Scenario: The site names no update once it runs the version the last check offered + Given an install root running this version as an official build + And the last check ran on the build "0.18.0" and found this version + When an administrator asks the site for its updates + Then the site names no update on offer + + Scenario: The site names no failure once it runs the version the failed update went to + Given an install root running this version as an official build + And an earlier update from "0.18.0" to this version failed at the step "download" + When an administrator asks the site for its updates + Then the site names no failure + Scenario: The site names when, where and why the last update failed Given an install root running this version as an official build And an update site offering version "99.0.0" that keeps the minimum version of this binary