lockedit: Support specifying which users (and IP addresses) a page is locked for...
authorJoey Hess <joey@kodama.kitenet.net>
Wed, 8 Oct 2008 21:47:38 +0000 (17:47 -0400)
committerJoey Hess <joey@kodama.kitenet.net>
Wed, 8 Oct 2008 21:47:38 +0000 (17:47 -0400)
IkiWiki.pm
IkiWiki/Plugin/attachment.pm
IkiWiki/Plugin/lockedit.pm
debian/changelog
doc/ikiwiki/pagespec.mdwn
doc/ikiwiki/pagespec/attachment.mdwn
doc/plugins/lockedit.mdwn
doc/todo/ACL.mdwn
po/es.po
po/ikiwiki.pot

index 82370f430ddd257544d47509ed4ffc0f14c5250f..633c5138180a9f87f4a974bef3322492c1d08ada 100644 (file)
@@ -1919,4 +1919,61 @@ sub match_creation_year ($$;@) { #{{{
        }
 } #}}}
 
+sub match_user ($$;@) { #{{{
+       shift;
+       my $user=shift;
+       my %params=@_;
+       
+       if (! exists $params{user}) {
+               return IkiWiki::FailReason->new("no user specified");
+       }
+
+       if (defined $params{user} && lc $params{user} eq lc $user) {
+               return IkiWiki::SuccessReason->new("user is $user");
+       }
+       elsif (! defined $params{user}) {
+               return IkiWiki::FailReason->new("not logged in");
+       }
+       else {
+               return IkiWiki::FailReason->new("user is $params{user}, not $user");
+       }
+} #}}}
+
+sub match_admin ($$;@) { #{{{
+       shift;
+       shift;
+       my %params=@_;
+       
+       if (! exists $params{user}) {
+               return IkiWiki::FailReason->new("no user specified");
+       }
+
+       if (defined $params{user} && IkiWiki::is_admin($params{user})) {
+               return IkiWiki::SuccessReason->new("user is an admin");
+       }
+       elsif (! defined $params{user}) {
+               return IkiWiki::FailReason->new("not logged in");
+       }
+       else {
+               return IkiWiki::FailReason->new("user is not an admin");
+       }
+} #}}}
+
+sub match_ip ($$;@) { #{{{
+       shift;
+       my $ip=shift;
+       my %params=@_;
+       
+       if (! exists $params{ip}) {
+               return IkiWiki::FailReason->new("no IP specified");
+       }
+
+       if (defined $params{ip} && lc $params{ip} eq lc $ip) {
+               return IkiWiki::SuccessReason->new("IP is $ip");
+       }
+       else {
+               return IkiWiki::FailReason->new("IP is $params{ip}, not $ip");
+       }
+} #}}}
+
 1
index 2d1fe51cf090b0f70595104217bd8d01b34ab0f9..dcac3e82006bf9679732727d4ed683b5b31bf8a9 100644 (file)
@@ -289,63 +289,4 @@ sub attachment_list ($) { #{{{
        return sort { $b->{mtime_raw} <=> $a->{mtime_raw} || $a->{link} cmp $b->{link} } @ret;
 } #}}}
 
-package IkiWiki::PageSpec;
-
-sub match_user ($$;@) { #{{{
-       shift;
-       my $user=shift;
-       my %params=@_;
-       
-       if (! exists $params{user}) {
-               return IkiWiki::FailReason->new("no user specified");
-       }
-
-       if (defined $params{user} && lc $params{user} eq lc $user) {
-               return IkiWiki::SuccessReason->new("user is $user");
-       }
-       elsif (! defined $params{user}) {
-               return IkiWiki::FailReason->new("not logged in");
-       }
-       else {
-               return IkiWiki::FailReason->new("user is $params{user}, not $user");
-       }
-} #}}}
-
-sub match_admin ($$;@) { #{{{
-       shift;
-       shift;
-       my %params=@_;
-       
-       if (! exists $params{user}) {
-               return IkiWiki::FailReason->new("no user specified");
-       }
-
-       if (defined $params{user} && IkiWiki::is_admin($params{user})) {
-               return IkiWiki::SuccessReason->new("user is an admin");
-       }
-       elsif (! defined $params{user}) {
-               return IkiWiki::FailReason->new("not logged in");
-       }
-       else {
-               return IkiWiki::FailReason->new("user is not an admin");
-       }
-} #}}}
-
-sub match_ip ($$;@) { #{{{
-       shift;
-       my $ip=shift;
-       my %params=@_;
-       
-       if (! exists $params{ip}) {
-               return IkiWiki::FailReason->new("no IP specified");
-       }
-
-       if (defined $params{ip} && lc $params{ip} eq lc $ip) {
-               return IkiWiki::SuccessReason->new("IP is $ip");
-       }
-       else {
-               return IkiWiki::FailReason->new("IP is $params{ip}, not $ip");
-       }
-} #}}}
-
 1
index 7462de41c73851346403e408eb9d53cbf861fe01..f6cac6cdd8c69b520824c2557d14d9a9ea3d5fdc 100644 (file)
@@ -37,7 +37,10 @@ sub canedit ($$) { #{{{
        return undef if defined $user && IkiWiki::is_admin($user);
 
        if (defined $config{locked_pages} && length $config{locked_pages} &&
-           pagespec_match($page, $config{locked_pages})) {
+           pagespec_match($page, $config{locked_pages},
+                   user => $session->param("name"),
+                   ip => $ENV{REMOTE_ADDR},
+           )) {
                if (! defined $user ||
                    ! IkiWiki::userinfo_get($session->param("name"), "regdate")) {
                        return sub { IkiWiki::needsignin($cgi, $session) };
@@ -51,7 +54,10 @@ sub canedit ($$) { #{{{
 
        # XXX deprecated, should be removed eventually
        foreach my $admin (@{$config{adminuser}}) {
-               if (pagespec_match($page, IkiWiki::userinfo_get($admin, "locked_pages"))) {
+               if (pagespec_match($page, IkiWiki::userinfo_get($admin, "locked_pages"),
+                   user => $session->param("name"),
+                   ip => $ENV{REMOTE_ADDR},
+               )) {
                        if (! defined $user ||
                            ! IkiWiki::userinfo_get($session->param("name"), "regdate")) {
                                return sub { IkiWiki::needsignin($cgi, $session) };
index a7b4cbb00f153edc8c8a5a0f958a1051ecf7fdfe..9947c8a5817b7da49eeed173aa3a644a9fa5fb74 100644 (file)
@@ -2,6 +2,10 @@ ikiwiki (2.67) UNRELEASED; urgency=low
 
   * remove: Avoid $_ breakage. (Stupid, stupid perl.)
   * Updated Spanish translation from Victor Moral.
+  * lockedit: Support specifying which users (and IP addresses) a page
+    is locked for. This supports most of the ACL type things users have been
+    wanting to be done. Closes: #443346 (It does not control who can read a
+    page, but that's out of scope for ikiwiki.)
 
  -- Joey Hess <joeyh@debian.org>  Mon, 06 Oct 2008 16:07:50 -0400
 
index 156e3f6ca84a40eeb1c0b2009200d48f28675996..c78666c4057238035798b9c10b26a01e7f332409 100644 (file)
@@ -22,8 +22,7 @@ match all pages except for Discussion pages and the SandBox:
 
        * and !SandBox and !*/Discussion
 
-Some more elaborate limits can be added to what matches using any of these
-functions:
+Some more elaborate limits can be added to what matches using these functions:
 
 * "`link(page)`" - match only pages that link to a given page (or glob)
 * "`backlink(page)`" - match only pages that a given page links to
@@ -41,6 +40,13 @@ functions:
 * "`title(glob)`", "`author(glob)`", "`authorurl(glob)`",
   "`license(glob)`", "`copyright(glob)`" - match pages that have the given
   metadata, matching the specified glob.
+* "`user(username)`" - tests whether a modification is being made by a
+  user with the specified username. If openid is enabled, an openid can also
+  be put here.
+* "`admin()`" - tests whether a modification is being made by one of the
+  wiki admins.
+* "`ip(address)`" - tests whether a modification is being made from the
+  specified IP address.
 
 For example, to match all pages in a blog that link to the page about music
 and were written in 2005:
index 1287fc0a4bad61f1caab111aa678f978ee0db654..2d33db748ad2a5f9a35378194e0c0b497285eb08 100644 (file)
@@ -16,45 +16,22 @@ check all attachments for virii, something like this could be used:
 The regular [[ikiwiki/PageSpec]] syntax is expanded with the following
 additional tests:
 
-* maxsize(size)
-
-  Tests whether the attachment is no larger than the specified size.
-  The size defaults to being in bytes, but "kb", "mb", "gb" etc can be
-  used to specify the units.
+* "`maxsize(size)`" - Tests whether the attachment is no larger than the
+  specified size. The size defaults to being in bytes, but "kb", "mb", "gb"
+  etc can be used to specify the units.
   
-* minsize(size)
-
-  Tests whether the attachment is no smaller than the specified size.
-
-* ispage()
+* "`minsize(size)`" - Tests whether the attachment is no smaller than the
+  specified size.
 
-  Tests whether the attachment will be treated by ikiwiki as a wiki page.
-  (Ie, if it has an extension of ".mdwn", or of any other enabled page
-  format).
+* "`ispage()`" - Tests whether the attachment will be treated by ikiwiki as a
+  wiki page. (Ie, if it has an extension of ".mdwn", or of any other enabled
+  page format).
 
   So, if you don't want to allow wiki pages to be uploaded as attachments,
   use `!ispage()` ; if you only want to allow wiki pages to be uploaded
   as attachments, use `ispage()`.
 
-* user(username)
-
-  Tests whether the attachment is being uploaded by a user with the
-  specified username. If openid is enabled, an openid can also be put here.
-
-* admin()
-
-  Tests whether the attachment is being uploded by one of the wiki admins.
-
-* ip(address)
-
-  Tests whether the attacment is being uploaded from the specified IP
-  address.
-
-* mimetype(foo/bar)
-
-  This checks the MIME type of the attachment. You can include a glob
-  in the type, for example `mimetype(image/*)`.
-
-* virusfree()
+* "`mimetype(foo/bar)`" - This checks the MIME type of the attachment. You can
+  include a glob in the type, for example `mimetype(image/*)`.
 
-  Checks the attachment with an antiviral program.
+* "`virusfree()`" - Checks the attachment with an antiviral program.
index 07abce1affaef19efa22bada914a52e8c7501584..71bf232abdae7a14e48944a33cb891a0d5f3b557 100644 (file)
@@ -17,4 +17,8 @@ One handy thing to do if you're using ikiwiki for your blog is to lock
 posts in your blog, while still letting them comment via the Discussion
 pages.
 
-Wiki administrators can always edit locked pages.
+Wiki administrators can always edit locked pages. The [[ikiwiki/PageSpec]]
+can specify that some pages are not locked for some users. For example,
+"important_page and !user(joey)" locks `important_page` while still
+allowing joey to edit it, while "!*/Discussion and user(bob)" prevents bob
+from editing pages except for Discussion pages.
index 373f89364d0bc51299d926170c05cb1f6107610a..e9fb2717f10d4f6edd18fd1175d8eac763effcdf 100644 (file)
@@ -44,7 +44,8 @@ Also see [[!debbug 443346]].
 >> Yes, writing per-user commit ACLs has become somewhat easier with recent
 >> features. Breaking `match_user` out of attachment, and making the
 >> lockedit plugin pass`user` and `ip` params when it calls `pagespec_match`
->> would be sufficient. --[[Joey]]
+>> would be sufficient. And [[done]], configurable via
+>> [[plugin/lockedit]]'s `locked_pages`. --[[Joey]]
 
 I am considering giving this a try, implementing it as a module.
 Here is how I see it:
index 34a4d3669279973919ebba2c49f6510940cd07f5..ff02ea86a31b8f123469e056e1d6164a660c8fd1 100644 (file)
--- a/po/es.po
+++ b/po/es.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: es\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-09-29 17:12-0400\n"
+"POT-Creation-Date: 2008-10-08 17:34-0400\n"
 "PO-Revision-Date: 2008-10-07 12:44+0200\n"
 "Last-Translator: Víctor Moral <victor@taquiones.net>\n"
 "Language-Team: Spanish <es@li.org>\n"
@@ -48,7 +48,7 @@ msgstr "Las preferencias se han guardado."
 msgid "You are banned."
 msgstr "Ha sido expulsado."
 
-#: ../IkiWiki/CGI.pm:385 ../IkiWiki/CGI.pm:386 ../IkiWiki.pm:1153
+#: ../IkiWiki/CGI.pm:385 ../IkiWiki/CGI.pm:386 ../IkiWiki.pm:1166
 msgid "Error"
 msgstr "Error"
 
@@ -58,7 +58,8 @@ msgstr "Contenido añadido activado vía web."
 
 #: ../IkiWiki/Plugin/aggregate.pm:89
 msgid "Nothing to do right now, all feeds are up-to-date!"
-msgstr "¡ No hay nada que hacer, todas las fuentes de noticias están actualizadas !"
+msgstr ""
+"¡ No hay nada que hacer, todas las fuentes de noticias están actualizadas !"
 
 #: ../IkiWiki/Plugin/aggregate.pm:216
 #, perl-format
@@ -159,20 +160,20 @@ msgstr "ya existe una página de nombre %s"
 msgid "prohibited by allowed_attachments"
 msgstr "prohibido por la claúsula allowed_attachments"
 
-#: ../IkiWiki/Plugin/attachment.pm:188
+#: ../IkiWiki/Plugin/attachment.pm:189
 msgid "bad attachment filename"
 msgstr "nombre de archivo adjunto erróneo"
 
-#: ../IkiWiki/Plugin/attachment.pm:230
+#: ../IkiWiki/Plugin/attachment.pm:231
 msgid "attachment upload"
 msgstr "enviado el adjunto"
 
-#: ../IkiWiki/Plugin/autoindex.pm:103
+#: ../IkiWiki/Plugin/autoindex.pm:105
 msgid "automatic index generation"
 msgstr "creación de índice automática"
 
 #: ../IkiWiki/Plugin/brokenlinks.pm:33 ../IkiWiki/Plugin/editpage.pm:261
-#: ../IkiWiki/Plugin/inline.pm:323 ../IkiWiki/Plugin/opendiscussion.pm:26
+#: ../IkiWiki/Plugin/inline.pm:326 ../IkiWiki/Plugin/opendiscussion.pm:26
 #: ../IkiWiki/Plugin/orphans.pm:37 ../IkiWiki/Render.pm:79
 #: ../IkiWiki/Render.pm:149
 msgid "discussion"
@@ -303,20 +304,20 @@ msgstr "falta el parámetro pages"
 msgid "unknown sort type %s"
 msgstr "no conozco este tipo de ordenación %s"
 
-#: ../IkiWiki/Plugin/inline.pm:282
+#: ../IkiWiki/Plugin/inline.pm:285
 msgid "Add a new post titled:"
 msgstr "Añadir una entrada nueva titulada:"
 
-#: ../IkiWiki/Plugin/inline.pm:298
+#: ../IkiWiki/Plugin/inline.pm:301
 #, perl-format
 msgid "nonexistant template %s"
 msgstr "la plantilla %s no existe "
 
-#: ../IkiWiki/Plugin/inline.pm:331 ../IkiWiki/Render.pm:83
+#: ../IkiWiki/Plugin/inline.pm:334 ../IkiWiki/Render.pm:83
 msgid "Discussion"
 msgstr "Comentarios"
 
-#: ../IkiWiki/Plugin/inline.pm:568
+#: ../IkiWiki/Plugin/inline.pm:571
 msgid "RPC::XML::Client not found, not pinging"
 msgstr "No he encontrado el componente RPC::XML::Client, no envío señal alguna"
 
@@ -324,13 +325,15 @@ msgstr "No he encontrado el componente RPC::XML::Client, no envío señal alguna
 msgid "failed to run dot"
 msgstr "no he podido ejecutar el programa dot"
 
-#: ../IkiWiki/Plugin/lockedit.pm:46 ../IkiWiki/Plugin/lockedit.pm:60
+#: ../IkiWiki/Plugin/lockedit.pm:49 ../IkiWiki/Plugin/lockedit.pm:66
+#, perl-format
 msgid "%s is locked and cannot be edited"
 msgstr "La página %s está bloqueada y no puede modificarse"
 
 #: ../IkiWiki/Plugin/mdwn.pm:44
 msgid "multimarkdown is enabled, but Text::MultiMarkdown is not installed"
-msgstr "el modo multimarkdown está activo, pero no está instalado Text::MultiMarkdown"
+msgstr ""
+"el modo multimarkdown está activo, pero no está instalado Text::MultiMarkdown"
 
 #: ../IkiWiki/Plugin/mdwn.pm:67
 #, perl-format
@@ -393,7 +396,9 @@ msgstr "Error creando la cuenta de usuario."
 
 #: ../IkiWiki/Plugin/passwordauth.pm:257
 msgid "No email address, so cannot email password reset instructions."
-msgstr "No tengo dirección de correo electrónica, así que no puedo enviar instrucciones para reiniciar la contraseña"
+msgstr ""
+"No tengo dirección de correo electrónica, así que no puedo enviar "
+"instrucciones para reiniciar la contraseña"
 
 #: ../IkiWiki/Plugin/passwordauth.pm:291
 msgid "Failed to send mail"
@@ -401,7 +406,9 @@ msgstr "No he podido enviar el mensaje de correo electrónico"
 
 #: ../IkiWiki/Plugin/passwordauth.pm:293
 msgid "You have been mailed password reset instructions."
-msgstr "Las instrucciones para reinicar la contraseña se le han enviado por correo electrónico"
+msgstr ""
+"Las instrucciones para reinicar la contraseña se le han enviado por correo "
+"electrónico"
 
 #: ../IkiWiki/Plugin/passwordauth.pm:328
 msgid "incorrect password reset url"
@@ -558,16 +565,16 @@ msgstr "%s no está en el directorio fuente por lo que no puede ser borrada"
 msgid "%s is not a file"
 msgstr "%s no es un archivo"
 
-#: ../IkiWiki/Plugin/remove.pm:112
+#: ../IkiWiki/Plugin/remove.pm:115
 #, perl-format
 msgid "confirm removal of %s"
 msgstr "confirme el borrado de %s"
 
-#: ../IkiWiki/Plugin/remove.pm:148
+#: ../IkiWiki/Plugin/remove.pm:152
 msgid "Please select the attachments to remove."
 msgstr "Por favor seleccione los adjuntos que serán borrados."
 
-#: ../IkiWiki/Plugin/remove.pm:188
+#: ../IkiWiki/Plugin/remove.pm:192
 msgid "removed"
 msgstr "borrado"
 
@@ -604,20 +611,20 @@ msgstr "cambiando de nombre %s"
 msgid "Also rename SubPages and attachments"
 msgstr "También cambia de nombre las subpáginas y los adjuntos"
 
-#: ../IkiWiki/Plugin/rename.pm:223
+#: ../IkiWiki/Plugin/rename.pm:224
 msgid "Only one attachment can be renamed at a time."
 msgstr "Únicamente un adjunto puede ser renombrado a la vez."
 
-#: ../IkiWiki/Plugin/rename.pm:226
+#: ../IkiWiki/Plugin/rename.pm:227
 msgid "Please select the attachment to rename."
 msgstr "Por favor, seleccione el adjunto al que cambiar el nombre."
 
-#: ../IkiWiki/Plugin/rename.pm:332
+#: ../IkiWiki/Plugin/rename.pm:338
 #, perl-format
 msgid "rename %s to %s"
 msgstr "%s cambia de nombre a %s"
 
-#: ../IkiWiki/Plugin/rename.pm:484
+#: ../IkiWiki/Plugin/rename.pm:490
 #, perl-format
 msgid "update for rename of %s to %s"
 msgstr "actualizado el cambio de nombre de %s a %s"
@@ -762,13 +769,17 @@ msgstr "complementos"
 #: ../IkiWiki/Plugin/websetup.pm:395
 msgid ""
 "The configuration changes shown below require a wiki rebuild to take effect."
-msgstr "Los cambios en la configuración que se muestran más abajo precisan una reconstrucción del wiki para tener efecto."
+msgstr ""
+"Los cambios en la configuración que se muestran más abajo precisan una "
+"reconstrucción del wiki para tener efecto."
 
 #: ../IkiWiki/Plugin/websetup.pm:399
 msgid ""
 "For the configuration changes shown below to fully take effect, you may need "
 "to rebuild the wiki."
-msgstr "Para que los cambios en la configuración mostrados más abajo tengan efecto, es posible que necesite reconstruir el wiki."
+msgstr ""
+"Para que los cambios en la configuración mostrados más abajo tengan efecto, "
+"es posible que necesite reconstruir el wiki."
 
 #: ../IkiWiki/Plugin/websetup.pm:433
 #, perl-format
@@ -780,7 +791,9 @@ msgstr "<p class=\"error\">Error: %s finaliza con código distinto de cero (%s)"
 msgid ""
 "symlink found in srcdir path (%s) -- set allow_symlinks_before_srcdir to "
 "allow this"
-msgstr "encontrado un enlace simbólico en la ruta del directorio fuente (%s) -- use la directiva allow_symlinks_before_srcdir para permitir la acción"
+msgstr ""
+"encontrado un enlace simbólico en la ruta del directorio fuente (%s) -- use "
+"la directiva allow_symlinks_before_srcdir para permitir la acción"
 
 #: ../IkiWiki/Render.pm:277 ../IkiWiki/Render.pm:302
 #, perl-format
@@ -926,12 +939,14 @@ msgstr "no puedo emplear varios complementos rcs"
 msgid "failed to load external plugin needed for %s plugin: %s"
 msgstr "no he podido cargar el complemento externo %s necesario para %s"
 
-#: ../IkiWiki.pm:1136
+#: ../IkiWiki.pm:1149
 #, perl-format
 msgid "preprocessing loop detected on %s at depth %i"
-msgstr "se ha detectado en la página %s un bucle de preprocesado en la iteración número %i"
+msgstr ""
+"se ha detectado en la página %s un bucle de preprocesado en la iteración "
+"número %i"
 
-#: ../IkiWiki.pm:1645
+#: ../IkiWiki.pm:1658
 msgid "yes"
 msgstr "si"
 
@@ -949,7 +964,9 @@ msgstr "¿ Qué sistema de control de versiones empleará ?"
 
 #: ../auto.setup:20
 msgid "What wiki user (or openid) will be wiki admin?"
-msgstr "¿ Qué usuario del wiki (ó identificador openid) será el administrador del wiki ? "
+msgstr ""
+"¿ Qué usuario del wiki (ó identificador openid) será el administrador del "
+"wiki ? "
 
 #: ../auto.setup:23
 msgid "What is the domain name of the web server?"
index dbbf986d53416a96239c3bd6531c0b06b1c2bbf6..f07f2bf6236fbd263d24d937d9de7a5e11d30189 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-10-05 19:11-0400\n"
+"POT-Creation-Date: 2008-10-08 17:34-0400\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -167,7 +167,7 @@ msgstr ""
 msgid "attachment upload"
 msgstr ""
 
-#: ../IkiWiki/Plugin/autoindex.pm:103
+#: ../IkiWiki/Plugin/autoindex.pm:105
 msgid "automatic index generation"
 msgstr ""
 
@@ -321,7 +321,7 @@ msgstr ""
 msgid "failed to run dot"
 msgstr ""
 
-#: ../IkiWiki/Plugin/lockedit.pm:46 ../IkiWiki/Plugin/lockedit.pm:60
+#: ../IkiWiki/Plugin/lockedit.pm:49 ../IkiWiki/Plugin/lockedit.pm:66
 #, perl-format
 msgid "%s is locked and cannot be edited"
 msgstr ""
@@ -554,16 +554,16 @@ msgstr ""
 msgid "%s is not a file"
 msgstr ""
 
-#: ../IkiWiki/Plugin/remove.pm:113
+#: ../IkiWiki/Plugin/remove.pm:115
 #, perl-format
 msgid "confirm removal of %s"
 msgstr ""
 
-#: ../IkiWiki/Plugin/remove.pm:150
+#: ../IkiWiki/Plugin/remove.pm:152
 msgid "Please select the attachments to remove."
 msgstr ""
 
-#: ../IkiWiki/Plugin/remove.pm:190
+#: ../IkiWiki/Plugin/remove.pm:192
 msgid "removed"
 msgstr ""