# SOME DESCRIPTIVE TITLE. # Copyright (C) 2009-2020, Marcel Hellkamp # This file is distributed under the same license as the Bottle package. # # Translators: msgid "" msgstr "" "Project-Id-Version: bottle\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-12-31 18:35+0100\n" "PO-Revision-Date: 2020-12-31 17:35+0000\n" "Last-Translator: defnull \n" "Language-Team: Chinese (China) (http://www.transifex.com/bottle/bottle/language/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: zh_CN\n" "Plural-Forms: nplurals=1; plural=0;\n" #: ../../plugindev.rst:6 msgid "Plugin Development Guide" msgstr "插件开发指南" #: ../../plugindev.rst:8 msgid "" "This guide explains the plugin API and how to write custom plugins. I " "suggest reading :ref:`plugins` first if you have not done that already. You " "might also want to have a look at the :doc:`/plugins/index` for some " "practical examples." msgstr "这份指南介绍了插件的API,以及如何编写自己的插件。我建议先阅读 :ref:`plugins` 这一部分,再看这份指南。 :doc:`/plugins/index` 这里也有一些实际的例子。" #: ../../plugindev.rst:12 msgid "" "This is a draft. If you see any errors or find that a specific part is not " "explained clear enough, please tell the `mailing-list " "`_ or file a `bug report " "`_." msgstr "这是一份初稿。如果你发现了任何错误,或某些部分解释的不够清楚,请通过 `邮件列表 `_ 或 `bug report `_ 告知。" #: ../../plugindev.rst:16 msgid "How Plugins Work: The Basics" msgstr "插件工作方式:基础知识" #: ../../plugindev.rst:18 msgid "" "The plugin API builds on the concept of `decorators " "`_. To put it briefly, " "a plugin is a decorator applied to every single route callback of an " "application." msgstr "插件的API是通过Python的 `修饰器 `_ 来实现的。简单来说,一个插件就是应用在route回调函数上的修饰器。" #: ../../plugindev.rst:20 msgid "" "This is just a simplification. Plugins can do a lot more than just " "decorating route callbacks, but it is a good starting point. Lets have a " "look at some code::" msgstr "" #: ../../plugindev.rst:36 msgid "" "This plugin measures the execution time for each request and adds an " "appropriate ``X-Exec-Time`` header to the response. As you can see, the " "plugin returns a wrapper and the wrapper calls the original callback " "recursively. This is how decorators usually work." msgstr "这个插件计算每次请求的响应时间,并在响应头中添加了 ``X-Exec-Time`` 字段。如你所见,插件返回了一个wrapper函数,由它来调用原先的回调函数。这就是修饰器的常见工作方式了。" #: ../../plugindev.rst:38 msgid "" "The last line tells Bottle to install the plugin to the default application." " This causes the plugin to be automatically applied to all routes of that " "application. In other words, ``stopwatch()`` is called once for each route " "callback and the return value is used as a replacement for the original " "callback." msgstr "最后一行,将该插件安装到Bottle的默认应用里面。这样,应用中的所有route都会应用这个插件了。就是说,每次请求都会调用 ``stopwatch()`` ,更改了route的默认行为。" #: ../../plugindev.rst:40 msgid "" "Plugins are applied on demand, that is, as soon as a route is requested for " "the first time. For this to work properly in multi-threaded environments, " "the plugin should be thread-safe. This is not a problem most of the time, " "but keep it in mind." msgstr "插件是按需加载的,就是在route第一次被访问的时候加载。为了在多线程环境下工作,插件应该是线程安全的。在大多数情况下,这都不是一个问题,但务必提高警惕。" #: ../../plugindev.rst:42 msgid "" "Once all plugins are applied to a route, the wrapped callback is cached and " "subsequent requests are handled by the cached version directly. This means " "that a plugin is usually applied only once to a specific route. That cache, " "however, is cleared every time the list of installed plugins changes. Your " "plugin should be able to decorate the same route more than once." msgstr "一旦route中使用了插件后,插件中的回调函数会被缓存起来,接下来都是直接使用缓存中的版本来响应请求。意味着每个route只会请求一次插件。在应用的插件列表变化的时候,这个缓存会被清空。你的插件应当可以多次修饰同一个route。" #: ../../plugindev.rst:44 msgid "" "The decorator API is quite limited, though. You don't know anything about " "the route being decorated or the associated application object and have no " "way to efficiently store data that is shared among all routes. But fear not!" " Plugins are not limited to just decorator functions. Bottle accepts " "anything as a plugin as long as it is callable or implements an extended " "API. This API is described below and gives you a lot of control over the " "whole process." msgstr "这种修饰器般的API受到种种限制。你不知道route或相应的应用对象是如何被修饰的,也不知道如何有效地存储那些在route之间共享的数据。但别怕!插件不仅仅是修饰器函数。只要一个插件是callable的或实现了一个扩展的API(后面会讲到),Bottle都可接受。扩展的API给你更多的控制权。" #: ../../plugindev.rst:48 msgid "Plugin API" msgstr "插件API" #: ../../plugindev.rst:50 msgid "" ":class:`Plugin` is not a real class (you cannot import it from " ":mod:`bottle`) but an interface that plugins are expected to implement. " "Bottle accepts any object of any type as a plugin, as long as it conforms to" " the following API." msgstr "``Plugin`` 类不是一个真正的类(你不能从bottle中导入它),它只是一个插件需要实现的接口。只要一个对象实现了以下接口,Bottle就认可它作为一个插件。" #: ../../plugindev.rst:54 msgid "" "Plugins must be callable or implement :meth:`apply`. If :meth:`apply` is " "defined, it is always preferred over calling the plugin directly. All other " "methods and attributes are optional." msgstr "插件应该是callable的,或实现了 :meth:`apply` 方法。如果定义了 :meth:`apply` 方法,那么会优先调用,而不是直接调用插件。其它的方法和属性都是可选的。" #: ../../plugindev.rst:58 msgid "" "Both :meth:`Bottle.uninstall` and the `skip` parameter of " ":meth:`Bottle.route()` accept a name string to refer to a plugin or plugin " "type. This works only for plugins that have a name attribute." msgstr ":meth:`Bottle.uninstall` 方法和 :meth:`Bottle.route()` 中的 `skip` 参数都接受一个与名字有关的字符串,对应插件或其类型。只有插件中有一个name属性的时候,这才会起作用。" #: ../../plugindev.rst:62 msgid "" "The Plugin API is still evolving. This integer attribute tells bottle which " "version to use. If it is missing, bottle defaults to the first version. The " "current version is ``2``. See :ref:`plugin-changelog` for details." msgstr "插件的API还在逐步改进。这个整形数告诉Bottle使用哪个版本的插件。如果没有这个属性,Bottle默认使用第一个版本。当前版本是 ``2`` 。详见 :ref:`plugin-changelog` 。" #: ../../plugindev.rst:66 msgid "" "Called as soon as the plugin is installed to an application (see " ":meth:`Bottle.install`). The only parameter is the associated application " "object." msgstr "插件被安装的时候调用(见 :meth:`Bottle.install` )。唯一的参数是相应的应用对象。" #: ../../plugindev.rst:70 msgid "" "As long as :meth:`apply` is not defined, the plugin itself is used as a " "decorator and applied directly to each route callback. The only parameter is" " the callback to decorate. Whatever is returned by this method replaces the " "original callback. If there is no need to wrap or replace a given callback, " "just return the unmodified callback parameter." msgstr "如果没有定义 :meth:`apply` 方法,插件本身会被直接当成一个修饰器使用(译者注:Python的Magic Method,调用一个类即是调用类的__call__函数),应用到各个route。唯一的参数就是其所修饰的函数。这个方法返回的东西会直接替换掉原先的回调函数。如果无需如此,则直接返回未修改过的回调函数即可。" #: ../../plugindev.rst:74 msgid "" "If defined, this method is used in favor of :meth:`__call__` to decorate " "route callbacks. The additional `route` parameter is an instance of " ":class:`Route` and provides a lot of meta-information and context for that " "route. See :ref:`route-context` for details." msgstr "如果存在,会优先调用,而不调用 :meth:`__call__` 。额外的 `route` 参数是 :class:`Route` 类的一个实例,提供很多该route信息和上下文。详见 :ref:`route-context` 。" #: ../../plugindev.rst:78 msgid "" "Called immediately before the plugin is uninstalled or the application is " "closed (see :meth:`Bottle.uninstall` or :meth:`Bottle.close`)." msgstr "插件被卸载或应用关闭的时候被调用,详见 :meth:`Bottle.uninstall` 或 :meth:`Bottle.close` 。" #: ../../plugindev.rst:81 msgid "" "Both :meth:`Plugin.setup` and :meth:`Plugin.close` are *not* called for " "plugins that are applied directly to a route via the :meth:`Bottle.route()` " "decorator, but only for plugins installed to an application." msgstr ":meth:`Plugin.setup` 方法和 :meth:`Plugin.close` 方法 *不* 会被调用,如果插件是通过 :meth:`Bottle.route` 方法来应用到route上面的,但会在安装插件的时候被调用。" #: ../../plugindev.rst:87 msgid "Plugin API changes" msgstr "插件API的改动" #: ../../plugindev.rst:89 msgid "" "The Plugin API is still evolving and changed with Bottle 0.10 to address " "certain issues with the route context dictionary. To ensure backwards " "compatibility with 0.9 Plugins, we added an optional :attr:`Plugin.api` " "attribute to tell bottle which API to use. The API differences are " "summarized here." msgstr "插件的API还在不断改进中。在Bottle 0.10版本中的改动,定位了route上下文字典中已确定的问题。为了保持对0.9版本插件的兼容,我们添加了一个可选的 :attr:`Plugin.api` 属性,告诉Bottle使用哪个版本的API。API之间的不同点总结如下。" #: ../../plugindev.rst:91 msgid "**Bottle 0.9 API 1** (:attr:`Plugin.api` not present)" msgstr "**Bottle 0.9 API 1** (无 :attr:`Plugin.api` 属性)" #: ../../plugindev.rst:93 msgid "Original Plugin API as described in the 0.9 docs." msgstr "" #: ../../plugindev.rst:95 msgid "**Bottle 0.10 API 2** (:attr:`Plugin.api` equals 2)" msgstr "**Bottle 0.10 API 2** ( :attr:`Plugin.api` 属性为2)" #: ../../plugindev.rst:97 msgid "" "The `context` parameter of the :meth:`Plugin.apply` method is now an " "instance of :class:`Route` instead of a context dictionary." msgstr " :meth:`Plugin.apply` 方法中的 `context` 参数,现在是 :class:`Route` 类的一个实例,不再是一个上下文字典。" #: ../../plugindev.rst:103 msgid "The Route Context" msgstr "Route上下文" #: ../../plugindev.rst:105 msgid "" "The :class:`Route` instance passed to :meth:`Plugin.apply` provides detailed" " informations about the associated route. The most important attributes are " "summarized here:" msgstr ":class:`Route` 的实例被传递给 :meth:`Plugin.apply` 函数,以提供更多该route的相关信息。最重要的属性总结如下。" #: ../../plugindev.rst:108 msgid "Attribute" msgstr "属性" #: ../../plugindev.rst:108 msgid "Description" msgstr "描述" #: ../../plugindev.rst:110 msgid "app" msgstr "" #: ../../plugindev.rst:110 msgid "The application object this route is installed to." msgstr "安装该route的应用对象" #: ../../plugindev.rst:111 msgid "rule" msgstr "" #: ../../plugindev.rst:111 msgid "The rule string (e.g. ``/wiki/``)." msgstr "" #: ../../plugindev.rst:112 msgid "method" msgstr "" #: ../../plugindev.rst:112 msgid "The HTTP method as a string (e.g. ``GET``)." msgstr "HTTP方法的字符串(例如: ``GET``)" #: ../../plugindev.rst:113 msgid "callback" msgstr "" #: ../../plugindev.rst:113 msgid "" "The original callback with no plugins applied. Useful for introspection." msgstr "未应用任何插件的原始回调函数,用于内省。" #: ../../plugindev.rst:115 msgid "name" msgstr "" #: ../../plugindev.rst:115 msgid "The name of the route (if specified) or ``None``." msgstr "route的名字,如未指定则为 ``None``" #: ../../plugindev.rst:116 msgid "plugins" msgstr "" #: ../../plugindev.rst:116 msgid "" "A list of route-specific plugins. These are applied in addition to " "application-wide plugins. (see :meth:`Bottle.route`)." msgstr "route安装的插件列表,除了整个应用范围内的插件,额外添加的(见 :meth:`Bottle.route` )" #: ../../plugindev.rst:118 msgid "skiplist" msgstr "" #: ../../plugindev.rst:118 msgid "" "A list of plugins to not apply to this route (again, see " ":meth:`Bottle.route`)." msgstr "应用安装了,但该route没安装的插件列表(见 meth:`Bottle.route` )" #: ../../plugindev.rst:120 msgid "config" msgstr "" #: ../../plugindev.rst:120 msgid "" "Additional keyword arguments passed to the :meth:`Bottle.route` decorator " "are stored in this dictionary. Used for route-specific configuration and " "meta-data." msgstr "传递给 :meth:`Bottle.route` 修饰器的额外参数,存在一个字典中,用于特定的设置和元数据" #: ../../plugindev.rst:125 msgid "" "For your plugin, :attr:`Route.config` is probably the most important " "attribute. Keep in mind that this dictionary is local to the route, but " "shared between all plugins. It is always a good idea to add a unique prefix " "or, if your plugin needs a lot of configuration, store it in a separate " "namespace within the `config` dictionary. This helps to avoid naming " "collisions between plugins." msgstr "对你的应用而言, :attr:`Route.config` 也许是最重要的属性了。记住,这个字典会在所有插件中共享,建议添加一个独一无二的前缀。如果你的插件需要很多设置,将其保存在 `config` 字典的一个独立的命名空间吧。防止插件之间的命名冲突。" #: ../../plugindev.rst:129 msgid "Changing the :class:`Route` object" msgstr "改变 :class:`Route` 对象" #: ../../plugindev.rst:131 msgid "" "While some :class:`Route` attributes are mutable, changes may have unwanted " "effects on other plugins. It is most likely a bad idea to monkey-patch a " "broken route instead of providing a helpful error message and let the user " "fix the problem." msgstr ":class:`Route` 的一些属性是不可变的,改动也许会影响到其它插件。坏主意就是,monkey-patch一个损坏的route,而不是提供有效的帮助信息来让用户修复问题。" #: ../../plugindev.rst:133 msgid "" "In some rare cases, however, it might be justifiable to break this rule. " "After you made your changes to the :class:`Route` instance, raise " ":exc:`RouteReset` as an exception. This removes the current route from the " "cache and causes all plugins to be re-applied. The router is not updated, " "however. Changes to `rule` or `method` values have no effect on the router, " "but only on plugins. This may change in the future, though." msgstr "在极少情况下,破坏规则也许是恰当的。在你更改了 :class:`Route` 实例后,抛一个 :exc:`RouteReset` 异常。这会从缓存中删除当前的route,并重新应用所有插件。无论如何,router没有被更新。改变 `rule` 或 `method` 的值并不会影响到router,只会影响到插件。这个情况在将来也许会改变。" #: ../../plugindev.rst:137 msgid "Runtime optimizations" msgstr "运行时优化" #: ../../plugindev.rst:139 msgid "" "Once all plugins are applied to a route, the wrapped route callback is " "cached to speed up subsequent requests. If the behavior of your plugin " "depends on configuration, and you want to be able to change that " "configuration at runtime, you need to read the configuration on each " "request. Easy enough." msgstr "插件应用到route以后,被插件封装起来的回调函数会被缓存,以加速后续的访问。如果你的插件的行为依赖一些设置,你需要在运行时更改这些设置,你需要在每次请求的时候读取设置信息。够简单了吧。" #: ../../plugindev.rst:141 msgid "" "For performance reasons, however, it might be worthwhile to choose a " "different wrapper based on current needs, work with closures, or enable or " "disable a plugin at runtime. Let's take the built-in HooksPlugin as an " "example: If no hooks are installed, the plugin removes itself from all " "affected routes and has virtually no overhead. As soon as you install the " "first hook, the plugin activates itself and takes effect again." msgstr "" #: ../../plugindev.rst:143 msgid "" "To achieve this, you need control over the callback cache: " ":meth:`Route.reset` clears the cache for a single route and " ":meth:`Bottle.reset` clears all caches for all routes of an application at " "once. On the next request, all plugins are re-applied to the route as if it " "were requested for the first time." msgstr "为了达到这个目的,你需要控制回调函数的缓存: :meth:`Route.reset` 函数清空单一route的缓存, :meth:`Bottle.reset` 函数清空所有route的缓存。在下一次请求的时候,所有插件被重新应用到route上面,就像第一次请求时那样。" #: ../../plugindev.rst:145 msgid "" "Both methods won't affect the current request if called from within a route " "callback, of cause. To force a restart of the current request, raise " ":exc:`RouteReset` as an exception." msgstr "如果在route的回调函数里面调用,两种方法都不会影响当前的请求。当然,可以抛出一个 :exc:`RouteReset` 异常,来改变当前的请求。" #: ../../plugindev.rst:149 msgid "Plugin Example: SQLitePlugin" msgstr "插件例子: SQLitePlugin" #: ../../plugindev.rst:151 msgid "" "This plugin provides an sqlite3 database connection handle as an additional " "keyword argument to wrapped callbacks, but only if the callback expects it. " "If not, the route is ignored and no overhead is added. The wrapper does not " "affect the return value, but handles plugin-related exceptions properly. " ":meth:`Plugin.setup` is used to inspect the application and search for " "conflicting plugins." msgstr "这个插件提供对sqlite3数据库的访问,如果route的回调函数提供了关键字参数(默认是\"db\"),则\"db\"可做为数据库连接,如果route的回调函数没有提供该参数,则忽略该route。wrapper不会影响返回值,但是会处理插件相关的异常。 :meth:`Plugin.setup` 方法用于检查应用,查找冲突的插件。" #: ../../plugindev.rst:218 msgid "" "This plugin is actually useful and very similar to the version bundled with " "Bottle. Not bad for less than 60 lines of code, don't you think? Here is a " "usage example::" msgstr "这个插件十分有用,已经和Bottle提供的那个版本很类似了(译者注:=。= 一模一样)。只要60行代码,还不赖嘛!下面是一个使用例子。" #: ../../plugindev.rst:239 msgid "" "The first route needs a database connection and tells the plugin to create a" " handle by requesting a ``db`` keyword argument. The second route does not " "need a database and is therefore ignored by the plugin. The third route does" " expect a 'db' keyword argument, but explicitly skips the sqlite plugin. " "This way the argument is not overruled by the plugin and still contains the " "value of the same-named url argument." msgstr "第一个route提供了一个\"db\"参数,告诉插件它需要一个数据库连接。第二个route不需要一个数据库连接,所以会被插件忽略。第三个route确实有一个\"db\"参数,但显式的禁用了sqlite插件,这样,\"db\"参数不会被插件修改,还是包含URL传过来的那个值。"