Browse Source

doc: reformat translated doc

wangweimin 4 years ago
parent
commit
8967e76dd3

+ 4 - 4
demos/bmi.py

@@ -1,10 +1,10 @@
 """
-BMI指数计算
-^^^^^^^^^^^
+BMI calculation
+^^^^^^^^^^^^^^^
 
-计算 `BMI指数 <https://en.wikipedia.org/wiki/Body_mass_index>`_ 的简单应用
+Simple application for calculating `Body Mass Index <https://en.wikipedia.org/wiki/Body_mass_index>`_
 
-:demo_host:`Demo地址 </?pywebio_api=bmi>`  `源码 <https://github.com/wang0618/PyWebIO/blob/dev/demos/bmi.py>`_
+:demo_host:`Demo </?pywebio_api=bmi>`  `Source code <https://github.com/wang0618/PyWebIO/blob/dev/demos/bmi.py>`_
 """
 from pywebio import start_server
 from pywebio.input import *

+ 6 - 6
demos/chat_room.py

@@ -1,12 +1,12 @@
 """
-聊天室
-^^^^^^^^^^^
-和当前所有在线的人聊天
+Online chat room
+^^^^^^^^^^^^^^^^^^^
+Chat with everyone currently online
 
-:demo_host:`Demo地址 </?pywebio_api=chat_room>`  `源码 <https://github.com/wang0618/PyWebIO/blob/dev/demos/chat_room.py>`_
+:demo_host:`Demo </?pywebio_api=chat_room>`  `Source code <https://github.com/wang0618/PyWebIO/blob/dev/demos/chat_room.py>`_
 
-* 使用基于协程的会话
-* 使用 `run_async() <pywebio.session.run_async>` 启动后台协程
+* Use coroutine-based sessions
+* Use `run_async() <pywebio.session.run_async>` to start background coroutine
 """
 import asyncio
 

+ 2 - 2
demos/config.py

@@ -1,5 +1,5 @@
-# demos 模块的部署地址
+# The deployment address of the demos module
 demo_host = 'http://pywebio-demos.demo.wangweimin.site'
 
-# https://github.com/wang0618/pywebio-chart-gallery 的部署地址
+# The deployment address of https://github.com/wang0618/pywebio-chart-gallery repo
 charts_demo_host = 'http://pywebio-charts.demo.wangweimin.site'

+ 3 - 3
demos/doc_demo.py

@@ -1,6 +1,6 @@
 """
 文档中示例代码在线运行
-^^^^^^^^^^^^^^^^
+Run the example code in the documentation online
 """
 from pywebio import start_server
 from pywebio.input import *
@@ -27,7 +27,7 @@ def run_code(code, scope, locals):
         try:
             exec(code, globals(), locals)
         except Exception as e:
-            toast('代码产生异常:"%s:%s"' % (type(e).__name__, e), color='error')
+            toast('Exception occurred: "%s:%s"' % (type(e).__name__, e), color='error')
 
 
 IMPORT_CODE = """from pywebio.input import *
@@ -42,7 +42,7 @@ def copytoclipboard(code):
     if 'put_buttons(' in code or 'put_file(' in code:
         code += '\n\nhold()  # keep session alive'
     run_js("writeText(text)", text=code)
-    toast('已复制')
+    toast('The code has been copied to the clipboard')
 
 
 def handle_code(code, title):

+ 4 - 4
demos/input_usage.py

@@ -1,9 +1,9 @@
 """
-输入演示
-^^^^^^^^^^^
-演示PyWebIO支持的各种输入形式
+Demo of input
+^^^^^^^^^^^^^^^
+To demonstrate various input forms supported by PyWebIO
 
-:demo_host:`Demo地址 </?pywebio_api=input_usage>`  `源码 <https://github.com/wang0618/PyWebIO/blob/dev/demos/input_usage.py>`_
+:demo_host:`Demo </?pywebio_api=input_usage>`  `Source code <https://github.com/wang0618/PyWebIO/blob/dev/demos/input_usage.py>`_
 """
 from pywebio import start_server
 from pywebio.input import *

+ 4 - 4
demos/output_usage.py

@@ -1,9 +1,9 @@
 """
-输出演示
-^^^^^^^^^^^
-演示PyWebIO支持的各种输出形式
+Demo of output
+^^^^^^^^^^^^^^
+To demonstrate various output forms supported by PyWebIO
 
-:demo_host:`Demo地址 </?pywebio_api=output_usage>`  `源码 <https://github.com/wang0618/PyWebIO/blob/dev/demos/output_usage.py>`_
+:demo_host:`Demo </?pywebio_api=output_usage>`  `Source code <https://github.com/wang0618/PyWebIO/blob/dev/demos/output_usage.py>`_
 """
 from pywebio import start_server
 from pywebio.output import *

+ 1 - 14
docs/FAQ.rst

@@ -6,38 +6,25 @@ FAQ
 
 How to make the input form not disappear after submission, and can continue to receive input?
 ----------------------------------------------------------------------------------------------
-如何让输入框在提交后不消失,并可以持续性地输入
-
-PyWebIO 的设计就是输入表单在成功提交后就销毁,因为 PyWebIO 的输入是阻塞式的,一旦提交表单,输入函数就返回了,此时表单还留在界面上是没有意义的。如果想实现持续性的输入,可以将接收输入以及后续操作放到一个 ``while`` 循环中。
 
 The design of PyWebIO is that the input form is destroyed after successful submission. The input function of PyWebIO is blocking. Once the form is submitted, the input function returns. So it is meaningless to leave the form on the page after submission of form. If you want to make continuous input, you can put input and subsequent operations into a ``while`` loop.
 
 
 How to output an input widget such as a search bar?
 ----------------------------------------------------------
-如何输出一个诸如搜索栏的输入框
-
-很遗憾,PyWebIO并不支持将输入框作为一般性的内容输出到页面。因为这样就相当于又回到了基于回调获取输入的方式了,会导致应用开发的复杂性提高,PyWebIO不太推荐过多依赖回调机制,所以对此仅提供了非常少的支持。
-不过也可以使用另一种方式实现近似的效果:只需要在需要显示输入框的地方放置一个button( `put_buttons() <pywebio.output.put_buttons>` ),然后在button的回调函数中调用输入函数来获取输入并进行后续操作。
 
 Unfortunately, PyWebIO does not support outputting input widget to the page as general output widget.
-Because this will make the input asynchronous, which is exactly what PyWebIO strives to avoid. Callbacks will increase the complexity of application development. PyWebIO does not recommend relying too much on the callback mechanism, so it only provides very little support.
+Because this will make the input asynchronous, which is exactly what PyWebIO strives to avoid. Callbacks will increase the complexity of application development. PyWebIO does not recommend relying too much on the callback mechanism, so it only provides a little support.
 However, there is a compromise way to achieve similar behavior: just put a button (`put_buttons() <pywebio.output.put_buttons>`) where the input widget needs to be displayed, and in the button's callback function, you can call the input function to get input and perform subsequent operations.
 
 
 Why the callback of ``put_buttons()`` does not work?
 ----------------------------------------------------------
-为什么 ``put_buttons()`` 的回调不起作用
-
-一般情况下,在Server模式下,任务函数一旦返回(或在Script模式下,脚本运行结束),会话就结束了,此时事件回调也将不起作用,可以在任务函数(或脚本)末尾处使用 `pywebio.session.hold()` 函数来将会话保持,这样在用户关闭浏览器页面前,事件回调将一直可用。 参见 :ref:`Server模式与Script模式 <server_and_script_mode>`
 
 In general, in Server mode, once the task function returns (or in Script mode, the script exits), the session closes. After this, the event callback will not work. You can call the `pywebio.session.hold()` function at the end of the task function (or script) to hold the session, so that the event callback will always be available before the browser page is closed by user.
 
 
 Why I cannot download the file using ``put_file()``?
 ----------------------------------------------------------
-为什么 ``put_file()`` 无法下载文件
-
-原因同上。 ``put_file()`` 的文件链接被点击后,也是需要和服务端通信获取文件数据的,所以会话关闭后下载链接会不可用。可以在任务函数末尾处使用 `pywebio.session.hold()` 函数来将会话保持。
 
 The reason is the same as above. The page needs to request server for data when the download button is clicked, so the download link will be unavailable after the session is closed. You can use the `pywebio.session.hold()` function at the end of the task function to hold the session.

+ 0 - 1
docs/demos.rst

@@ -9,6 +9,5 @@ Sample application written with PyWebIO
 
 Data visualization demos
 --------------------------
-PyWebIO支持使用第三方库进行数据可视化,详情见 :ref:`使用PyWebIO进行数据可视化 <visualization>`
 
 PyWebIO supports data visualization by using of third-party libraries. For details, see :ref:`Use PyWebIO for data visualization <visualization>`

+ 80 - 309
docs/guide.rst

@@ -1,32 +1,19 @@
 User's guide
 ============
 
-如果你接触过Web开发,你可能对接下来描述的PyWebIO的用法感到不太习惯,不同于传统Web开发的后端实现接口、前端进行展示交互的模式,在PyWebIO中,所有的逻辑都通过编写Python代码实现。
-
-事实上,PyWebIO应用的编写逻辑更像控制台程序,只不过这里的终端变成了浏览器。通过PyWebIO提供的命令式API,
-你可以简单地调用 ``put_text`` 、 ``put_image`` 、 ``put_table`` 等函数输出文本、图片、表格等内容到浏览器,也可以调用 ``input`` 、 ``select`` 、
-``file_upload`` 等函数在浏览器上显示不同表单来接收用户的输入。此外PyWebIO中还提供了点击事件、布局等支持,让你可以使用最少的代码完成与用户的交互,
-并尽可能提供良好的用户体验。
-
-本篇使用指南从几个方面对PyWebIO的使用进行介绍,覆盖了PyWebIO的绝大部分特性。本文档中大部分示例代码的右上方都有一个Demo链接,点击后可以在线预览代码的运行效果。
-
-If you are familiar with web development, you may not be accustomed to the usage of PyWebIO described next, which is different from the traditional web development mode that backend implement api and frontend display content. In PyWebIO, you only need write code in Python.
+If you are familiar with web development, you may not be accustomed to the usage of PyWebIO described below, which is different from the traditional web development patton that backend implement api and frontend display content. In PyWebIO, you only need write code in Python.
 
 In fact, the way of writing PyWebIO applications is more like writing a console program, except that the terminal here becomes a browser. Using the imperative API provided by PyWebIO,
-you can simply call ``put_text``, ``put_image``, ``put_table`` and other functions to output text, pictures, tables and other content to the browser, or you can call some functions such as ``input``, ``select``, ``file_upload`` to display different forms on the browser to get user input. In addition, PyWebIO also provides support for click events, layout, etc. PyWebIO aims to allow you to use the least code to complete the interaction with the user and provide a good user experience as much as possible.
+you can simply call ``put_text``, ``put_image``, ``put_table`` and other functions to output text, pictures, tables and other content to the browser, or you can call some functions such as ``input``, ``select``, ``file_upload`` to display different forms on the browser to get user input. In addition, PyWebIO also provides support for click events, layout, etc. PyWebIO aims to allow you to use the least code to interact with the user and provide a good user experience as much as possible.
 
 This user guide introduces you the most of the features of PyWebIO. There is a demo link at the top right of the most of the example codes in this document, where you can preview the running effect of the code online.
 
 Input
 ------------
 
-输入函数都定义在 :doc:`pywebio.input </input>` 模块中,可以使用 ``from pywebio.input import *`` 引入。
-
-调用输入函数会在浏览器上弹出一个输入表单来获取输入。PyWebIO的输入函数是阻塞式的(和Python内置的 `input` 一样),在表单被成功提交之前,输入函数不会返回。
-
 The input functions are defined in the :doc:`pywebio.input </input>` module and can be imported using ``from pywebio.input import *``.
 
-Calling the input function will pop up an input form on the browser. PyWebIO's input functions is blocking (same as Python's built-in ``input()`` function) and will not return until the form is successfully submitted.
+When calling the input function, an input form  will be popped up on the browser. PyWebIO's input functions is blocking (same as Python's built-in ``input()`` function) and will not return until the form is successfully submitted.
 
 Basic input
 ^^^^^^^^^^^^^
@@ -42,7 +29,7 @@ Text input:
     age = input("How old are you?", type=NUMBER)
     put_text('age = %r' % age)  # ..demo-only
 
-After running the above code, the browser will pop up a text input box to get the input. After the user completes the input and submits the form, the function returns the value entered by the user.
+After running the above code, the browser will pop up a text input field to get the input. After the user completes the input and submits the form, the function returns the value entered by the user.
 
 Here are some other types of input functions:
 
@@ -84,8 +71,6 @@ Here are some other types of input functions:
 Parameter of input functions
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-输入函数可指定的参数非常丰富(全部参数及含义请见 :doc:`函数文档 </input>` ):
-
 There are many parameters that can be passed to the input function(for complete parameters, please refer to the :doc:`function document </input>`):
 
 .. exportable-codeblock::
@@ -95,21 +80,17 @@ There are many parameters that can be passed to the input function(for complete
     input('This is label', type=TEXT, placeholder='This is placeholder',
             help_text='This is help text', required=True)
 
-以上代码将在浏览器上显示如下:
-
 The results of the above example are as follows:
 
 .. image:: /assets/input_1.png
 
-我们可以为输入指定校验函数,校验函数应在校验通过时返回None,否则返回错误消息:
-
 You can specify a validation function for the input by using ``validate`` parameter. The validation function should return ``None`` when the check passes, otherwise an error message will be returned:
 
 .. exportable-codeblock::
     :name: input-valid-func
     :summary: Input validate function for
 
-    def check_age(p):  # return None when the check passes, otherwise an error message will be returned
+    def check_age(p):  # return None when the check passes, otherwise return the error message
         if p < 10:
             return 'Too young!!'
         if p > 60:
@@ -118,18 +99,11 @@ You can specify a validation function for the input by using ``validate`` parame
     age = input("How old are you?", type=NUMBER, validate=check_age)
     put_text('age = %r' % age)  # ..demo-only
 
-当用户输入了不合法的值时,页面上的显示如下:
-
-When the user input an illegal value, the display on the page is as follows:
+When the user input an illegal value, the input field is displayed as follows:
 
 .. image:: /assets/input_2.png
 
-
-:func:`pywebio.input.textarea` 还支持使用 `Codemirror <https://codemirror.net/>`_ 实现代码风格的编辑区,只需使用 ``code`` 参数传入Codemirror支持的选项即可(最简单的情况是直接传入 ``code={}`` 或 ``code=True``):
-
-:func:`pywebio.input.textarea` supports for code editing by using `Codemirror <https://codemirror.net/>`_ , just use the ``code`` parameter to pass in the options supported by Codemirror (the simplest case is to pass in ``code={}`` or ``code=True`` directly):
-
-You can use ``code`` parameter in :func:`pywebio.input.textarea` to make a code editing textarea. This feature uses `Codemirror <https://codemirror.net/>`_ as underlying implementation. The ``code`` parameter accept the Codemirror options as a dict.
+You can use ``code`` parameter in :func:`pywebio.input.textarea()` to make a code editing textarea. This feature uses `Codemirror <https://codemirror.net/>`_ as underlying implementation. The ``code`` parameter accept the Codemirror options as a dict.
 
 .. exportable-codeblock::
     :name: codemirror
@@ -141,22 +115,16 @@ You can use ``code`` parameter in :func:`pywebio.input.textarea` to make a code
     }, value='import something\n# Write your python code')
     put_code(code, language='python')  # ..demo-only
 
-文本框的显示效果为:
-
 The results of the above example are as follows:
 
 .. image:: /assets/codemirror_textarea.png
 
-:ref:`这里 <codemirror_options>` 列举了一些常用的Codemirror选项,完整的Codemirror选项请见:https://codemirror.net/doc/manual.html#config
-
 :ref:`Here <codemirror_options>` are some commonly used Codemirror options. For complete Codemirror options, please visit: https://codemirror.net/doc/manual.html#config
 
 Input Group
 ^^^^^^^^^^^^^
 
-PyWebIO支持输入组, 返回结果为一个字典。`pywebio.input.input_group()` 接受单项输入组成的列表作为参数, 返回以单项输入函数中的 ``name`` 作为键、以输入数据为值的字典:
-
-PyWebIO uses input group to get multiple inputs in single form. `pywebio.input.input_group()` accepts a list of single input function call as parameter, and returns a dictionary with the ``name`` from the single input function as the key and the input data as the value:
+PyWebIO uses input group to get multiple inputs in a single form. `pywebio.input.input_group()` accepts a list of single input function call as parameter, and returns a dictionary with the ``name`` from the single input function as the key and the input data as the value:
 
 
 .. exportable-codeblock::
@@ -175,13 +143,11 @@ PyWebIO uses input group to get multiple inputs in single form. `pywebio.input.i
     ])
     put_text(data['name'], data['age'])
 
-输入组中同样支持使用 ``validate`` 参数设置校验函数,其接受整个表单数据作为参数:
-
 The input group also supports using ``validate`` parameter to set the validation function, which accepts the entire form data as parameter:
 
 .. exportable-codeblock::
     :name: input-group
-    :summary: 输入组
+    :summary: Input Group
 
     def check_age(p):  # single input item validation  # ..demo-only
         if p < 10:                  # ..demo-only
@@ -189,7 +155,7 @@ The input group also supports using ``validate`` parameter to set the validation
         if p > 60:                  # ..demo-only
             return 'Too old!!'      # ..demo-only
                                     # ..demo-only
-    def check_form(data):  # input group validation: return (input name, error msg) when validation error
+    def check_form(data):  # input group validation: return (input name, error msg) when validation fail
         if len(data['name']) > 6:
             return ('name', 'Name too long!')
         if data['age'] <= 0:
@@ -202,25 +168,18 @@ The input group also supports using ``validate`` parameter to set the validation
     put_text(data['name'], data['age'])    # ..demo-only
 
 .. attention::
-   PyWebIO 根据是否在输入函数中传入 ``name`` 参数来判断输入函数是在 `input_group` 中还是被单独调用。
-   所以当单独调用一个输入函数时, **不要** 设置 ``name`` 参数;而在 `input_group` 中调用输入函数时,需 **务必提供** ``name`` 参数
-
-   PyWebIO determine whether the input function is in `input_group` or is called alone according to whether the ``name`` parameter is passed. So when calling an input function alone, **do not** set the ``name`` parameter; when calling the input function in `input_group`, you **must** provide the ``name`` parameter.
+   PyWebIO determines whether the input function is in `input_group` or is called alone according to whether the ``name`` parameter is passed. So when calling an input function alone, **do not** set the ``name`` parameter; when calling the input function in `input_group`, you **must** provide the ``name`` parameter.
 
 Output
 ------------
 
-输出函数都定义在 :doc:`pywebio.output </output>` 模块中,可以使用 ``from pywebio.output import *`` 引入。
-
 The output functions are all defined in the :doc:`pywebio.output </output>` module and can be imported using ``from pywebio.output import *``.
 
-When output functions is called, the content will be output to the browser in real time. The output functions can be called at any time during the application life cycle.
+When output functions is called, the content will be output to the browser in real time. The output functions can be called at any time during the application lifetime.
 
 Basic Output
 ^^^^^^^^^^^^^^
 
-PyWebIO提供了一系列函数来输出表格、链接等格式:
-
 PyWebIO provides a series of functions to output text, tables, links, etc:
 
 .. exportable-codeblock::
@@ -251,30 +210,25 @@ PyWebIO provides a series of functions to output text, tables, links, etc:
     popup('popup title', 'popup text content')
 
 
-PyWebIO提供的全部输出函数见 :doc:`pywebio.output </output>` 模块。另外,PyWebIO还支持一些第三方库来进行数据可视化,参见 :doc:`第三方库生态 </libraries_support>` 。
-
 For all output functions provided by PyWebIO, please refer to the :doc:`pywebio.output </output>` module. In addition, PyWebIO also supports data visualization with some third-party libraries, see :doc:`Third-party library ecology </libraries_support>`.
 
 .. _combine_output:
 
-Combined Output(组合输出)
+Combined Output
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-函数名以 ``put_`` 开始的输出函数,可以与一些输出函数组合使用,作为最终输出的一部分:
 
-The output function whose function name starts with ``put_`` can be combined with some output functions as part of the final output:
-
-`put_table() <pywebio.output.put_table>` 支持以 ``put_xxx()`` 调用作为单元格内容:
+The output functions whose name starts with ``put_`` can be combined with some output functions as part of the final output:
 
 You can pass ``put_xxx()`` calls to `put_table() <pywebio.output.put_table>` as cell content:
 
 .. exportable-codeblock::
     :name: putxxx
-    :summary: Combined output
+    :summary: Combination output
 
     put_table([
         ['Type', 'Content'],
         ['html', put_html('X<sup>2</sup>')],
-        ['text', '<hr/>'],  # 等价于 ['text', put_text('<hr/>')]
+        ['text', '<hr/>'],  # equal to ['text', put_text('<hr/>')]
         ['buttons', put_buttons(['A', 'B'], onclick=...)],  # ..doc-only
         ['buttons', put_buttons(['A', 'B'], onclick=put_text)],  # ..demo-only
         ['markdown', put_markdown('`Awesome PyWebIO!`')],
@@ -282,14 +236,10 @@ You can pass ``put_xxx()`` calls to `put_table() <pywebio.output.put_table>` as
         ['table', put_table([['A', 'B'], ['C', 'D']])]
     ])
 
-上例显示效果如下:
-
 The results of the above example are as follows:
 
 .. image:: /assets/put_table.png
 
-类似地, `popup() <pywebio.output.popup>` 也可以将 ``put_xxx()`` 调用作为弹窗内容:
-
 Similarly, you can pass ``put_xxx()`` calls to `popup() <pywebio.output.popup>` as the popup content:
 
 .. exportable-codeblock::
@@ -303,16 +253,9 @@ Similarly, you can pass ``put_xxx()`` calls to `popup() <pywebio.output.popup>`
         put_buttons(['close_popup()'], onclick=lambda _: close_popup())
     ])
 
-其他接受 ``put_xxx()`` 调用作为参数的输出函数还有 `put_collapse() <pywebio.output.put_collapse>` 、 `put_scrollable() <pywebio.output.put_scrollable>` 、`put_row() <pywebio.output.put_row>` 等,
-此外,还可以通过 `put_widget() <pywebio.output.put_widget>` 自定义可接收 ``put_xxx()`` 调用的输出组件,具体用法请参考函数文档。
-
 Other output functions that accept ``put_xxx()`` calls as parameters are `put_collapse() <pywebio.output.put_collapse>`, `put_scrollable() <pywebio.output.put_scrollable>`, `put_row() <pywebio.output.put_row>`, etc. In addition, you can use `put_widget() <pywebio.output.put_widget>` to make your own output widgets that can accept ``put_xxx()`` calls. For more information, please refer to corresponding function documentation.
 
-使用组合输出时,如果想在内容输出后,对其中的 ``put_xxx()`` 子项进行动态修改,可以使用 `output() <pywebio.output.output>` 函数,
-`output() <pywebio.output.output>` 就像一个占位符,它可以像 ``put_xxx()`` 一样传入 `put_table` 、 `popup` 、 `put_widget` 等函数中作为输出的一部分,
-并且,在输出后,还可以对其中的内容进行修改(比如重置或增加内容):
-
-When using combined output, if you want to dynamically update the ``put_xxx()`` content after it has been output, you can use the `output() <pywebio.output.output>` function. `output() <pywebio.output.output>` is like a placeholder, it can be passed in anywhere that ``put_xxx()`` can passed in. And after being output, the content can also be modified:
+When using combination output, if you want to dynamically update the ``put_xxx()`` content after it has been output, you can use the `output() <pywebio.output.output>` function. `output() <pywebio.output.output>` is like a placeholder, it can be passed in anywhere that ``put_xxx()`` can passed in. And after being output, the content can also be modified:
 
 .. exportable-codeblock::
     :name: output
@@ -335,13 +278,9 @@ When using combined output, if you want to dynamically update the ``put_xxx()``
 Callback
 ^^^^^^^^^^^^^^
 
-从上面可以看出,PyWebIO把交互分成了输入和输出两部分:输入函数为阻塞式调用,会在用户浏览器上显示一个表单,在用户提交表单之前输入函数将不会返回;输出函数将内容实时输出至浏览器。这种交互方式和控制台程序是一致的,因此PyWebIO应用非常适合使用控制台程序的编写逻辑来进行开发。
-
-As we can see from the above, PyWebIO divides the interaction into two parts: input and output. The input function is blocking, a form will be displayed on the user's web browser when calling input function, the input function will not return util the user submits the form. The output function is used to output content to the browser in real time. This input and output behavior is consistent with the console program. That's why we say PyWebIO turning the browser into a "rich text terminal". So you can write PyWebIO applications in script programing way.
+As we can see from the above, PyWebIO divides the interaction into two parts: input and output. The input function is blocking, a form will be displayed on the user's web browser when calling input function, the input function will not return util the user submits the form. The output function is used to output content to the browser in real time. The behavior of input and output is consistent with the console program. That's why we say PyWebIO turning the browser into a "rich text terminal". So you can write PyWebIO applications in script programing way.
 
-此外,PyWebIO还支持事件回调:PyWebIO允许你输出一些控件,当控件被点击时执行提供的回调函数。
-
-In addition, PyWebIO also supports event callbacks: PyWebIO allows you to output some buttons and the provided callback function will be executed when button is clicked.
+In addition, PyWebIO also supports event callbacks: PyWebIO allows you to output some buttons, and the provided callback function will be executed when the button is clicked.
 
 This is an example:
 
@@ -361,49 +300,36 @@ This is an example:
         [3, put_buttons(['edit', 'delete'], onclick=partial(edit_row, row=3))],
     ])
 
-`put_table() <pywebio.output.put_table>` 的调用不会阻塞。当用户点击了某行中的按钮时,PyWebIO会自动调用相应的回调函数:
-
-The call to `put_table() <pywebio.output.put_table>` will not block. When user clicks a button, the corresponding callback function will be called:
+The call to `put_table() <pywebio.output.put_table>` will not block. When user clicks a button, the corresponding callback function will be invoked:
 
 .. image:: /assets/table_onclick.*
 
-当然,PyWebIO还支持单独的按钮控件:
-
-PyWebIO also supports output button alone:
+Of course, PyWebIO also supports outputting individual button:
 
 .. exportable-codeblock::
     :name: put-buttons
-    :summary: 按钮控件
+    :summary: Event callback of button widget
 
     def btn_click(btn_val):
         put_text("You click %s button" % btn_val)
     put_buttons(['A', 'B', 'C'], onclick=btn_click)
 
 .. note::
-   在PyWebIO会话(关于会话的概念见下文 :ref:`Server与script模式 <server_and_script_mode>` )结束后,事件回调也将不起作用,你可以在任务函数末尾处使用 :func:`pywebio.session.hold()` 函数来将会话保持,这样在用户关闭浏览器页面前,事件回调将一直可用。
-
    After the PyWebIO session (see :ref:`Server and script mode <server_and_script_mode>` for more information about session) closed, the event callback will not work. You can call the :func:`pywebio.session.hold()` function at the end of the task function to hold the session, so that the event callback will always be available before the browser page is closed by user.
 
 Output Scope
 ^^^^^^^^^^^^^^
-PyWebIO使用Scope模型来对内容输出的位置进行灵活地控制,PyWebIO的内容输出区可以划分出不同的输出域,PyWebIO将输出域称作 `Scope` 。
 
 PyWebIO uses the scope model to give more control to the location of content output. The output area of PyWebIO can be divided into different output domains. The output domain is called Scope in PyWebIO.
 
-输出域为输出内容的容器,各个输出域之间上下排列,输出域也可以进行嵌套。
+The output domain is a container of output content, and each output domain is arranged vertically, and the output domains can also be nested.
 
-The output domain is a container for output content, and each output domain is arranged vertically, and the output domains can also be nested.
-
-每个输出函数(函数名形如 `put_xxx()` )都会将内容输出到一个Scope,默认为"当前Scope","当前Scope"由运行时上下文确定,输出函数也可以手动指定输出到的Scope。Scope名在会话内唯一。
-
-Each output function (function name like ``put_xxx()``) will output the content to a scope, the default is "current scope". "current scope" is determined by the runtime context. The output function can also manually specify the scope to be output to. The scope name is unique within the session.
+Each output function (function name like ``put_xxx()``) will output its content to a scope, the default is "current scope". "current scope" is determined by the runtime context. The output function can also manually specify the scope to output. The scope name is unique within the session.
 
 .. _use_scope:
 
 **use_scope()**
 
-可以使用 `use_scope() <pywebio.output.use_scope>` 开启并进入一个新的输出域,或进入一个已经存在的输出域:
-
 You can use `use_scope() <pywebio.output.use_scope>` to open and enter a new output scope, or enter an existing output scope:
 
 .. exportable-codeblock::
@@ -411,14 +337,12 @@ You can use `use_scope() <pywebio.output.use_scope>` to open and enter a new out
     :summary: use `use_scope()` to open or enter scope
 
     with use_scope('scope1'):  # open and enter a new output: 'scope1'
-        put_text('text1 in scope1')
+        put_text('text1 in scope1')  # output text to scope1
 
-    put_text('text in parent scope of scope1')
+    put_text('text in parent scope of scope1')  # output text to ROOT scope
 
-    with use_scope('scope1'):  # enter an existing output scope: 'scope1'
-        put_text('text2 in scope1')
-
-以上代码将会输出:
+    with use_scope('scope1'):  # enter an existing scope: 'scope1'
+        put_text('text2 in scope1')  # output text to scope1
 
 The results of the above code are as follows::
 
@@ -426,8 +350,6 @@ The results of the above code are as follows::
     text2 in scope1
     text in parent scope of scope1
 
-`use_scope() <pywebio.output.use_scope>` 还可以使用 `clear` 参数将scope中原有的内容清空:
-
 You can use ``clear`` parameter in `use_scope() <pywebio.output.use_scope>` to clear the previous content in the scope:
 
 .. exportable-codeblock::
@@ -440,18 +362,14 @@ You can use ``clear`` parameter in `use_scope() <pywebio.output.use_scope>` to c
     put_text('text in parent scope of scope2')
     ## ----
 
-    with use_scope('scope2', clear=True):  # enter an existing output scope and clear the original content
+    with use_scope('scope2', clear=True):  # enter the existing scope and clear the previous content
         put_text('text in scope2')
 
-以上代码将会输出:
-
 The results of the above code are as follows::
 
     text in scope2
     text in parent scope of scope2
 
-`use_scope() <pywebio.output.use_scope>` 还可以作为装饰器来使用:
-
 `use_scope() <pywebio.output.use_scope>` can also be used as a decorator:
 
 .. exportable-codeblock::
@@ -469,17 +387,10 @@ The results of the above code are as follows::
        show_time()    # ..demo-only
        time.sleep(1)  # ..demo-only
 
-第一次调用 ``show_time`` 时,将会在当前位置创建 ``time`` 输出域并在其中输出当前时间,之后每次调用 ``show_time()`` ,时间都会输出到相同的区域。
-
-When calling ``show_time()`` for the first time, a ``time`` scope will be created at the current position and the current time will be output to it, and then every time the ``show_time()`` is called, the time will be output to the same area.
-
-Scope是可嵌套的,初始条件下,PyWebIO应用只有一个最顶层的 ``ROOT`` Scope。每创建一个新Scope,Scope的嵌套层级便会多加一层,每退出当前Scope,Scope的嵌套层级便会减少一层。
-PyWebIO使用Scope栈来保存运行时的Scope的嵌套层级。
+When calling ``show_time()`` for the first time, a ``time`` scope will be created at the current position, and the current time will be output to it. And then every time the ``show_time()`` is called, the new content will replace the previous content.
 
 Scopes can be nested. At the beginning, PyWebIO applications have only one ``ROOT`` Scope. Each time a new scope is created, the nesting level of the scope will increase by one level, and each time the current scope is exited, the nesting level of the scope will be reduced by one. PyWebIO uses the Scope stack to save the nesting level of scope at runtime.
 
-例如,如下代码将会创建3个Scope:
-
 For example, the following code will create 3 scopes:
 
 .. exportable-codeblock::
@@ -504,9 +415,7 @@ For example, the following code will create 3 scopes:
     put_buttons([('Put text to %s' % i, i) for i in ('A', 'B', 'C')], lambda s: put_text(s, scope=s))  # ..demo-only
 
 
-以上代码将会产生如下Scope布局:
-
-The above code will make the following Scope layout::
+The above code will generate the following Scope layout::
 
    ┌─ROOT────────────────────┐
    │                         │
@@ -526,11 +435,7 @@ The above code will make the following Scope layout::
 
 **Scope related parameters of output function**
 
-输出函数(函数名形如 ``put_xxx()`` )在默认情况下,会将内容输出到"当前Scope",可以通过 ``use_scope()`` 设置运行时上下文的"当前Scope"。
-
-The output function (function name like ``put_xxx()``) will output the content to the "current scope" by default, and the "current scope" of the runtime context can be set by use_scope().
-
-此外,也可以通过输出函数的 ``scope`` 参数指定输出的目的Scope:
+The output function (function name like ``put_xxx()``) will output the content to the "current scope" by default, and the "current scope" of the runtime context can be set by ``use_scope()``.
 
 In addition, you can use the ``scope`` parameter of the output function to specify the destination scope to output:
 
@@ -539,34 +444,24 @@ In addition, you can use the ``scope`` parameter of the output function to speci
     :summary: ``scope`` parameter of the output function
 
     with use_scope('scope3'):
-        put_text('text1 in scope3')   # output to scope3
+        put_text('text1 in scope3')   # output to current scope: scope3
         put_text('text in ROOT scope', scope='ROOT')   # output to ROOT Scope
 
     put_text('text2 in scope3', scope='scope3')   # output to scope3
 
-以上将会输出:
-
 The results of the above code are as follows::
 
     text1 in scope3
     text2 in scope3
     text in ROOT scope
 
-``scope`` 参数除了直接指定目标Scope名,还可以使用一个整形通过索引Scope栈来确定Scope:0表示最顶层也就是ROOT Scope,-1表示当前Scope,-2表示进入当前Scope前所使用的Scope,......
-
 In addition to directly specifying the target scope name, the ``scope`` parameter can also accept an integer to determine the scope by indexing the scope stack: 0 means the top level scope(the ROOT Scope), -1 means the current Scope, -2 means the scope used before entering the current scope, ...
 
-默认条件下,在同一Scope中的输出内容,会根据输出函数的调用顺序从上往下排列,最后调用的输出函数会输出内容到目标Scope的底部。通过输出函数的 ``position`` 参数可以将输出内容插入到目标Scope的其他位置。
-
-By default, the output content in the same scope will be arranged from top to bottom according to the calling order of the output function, and the output function called last will output the content to the bottom of the target scope. The output content can be inserted into other positions of the target scope by using the ``position`` parameter of the output function.
+By default, the content output to the same scope will be arranged from top to bottom according to the calling order of the output function, and the output function called last will output the content to the bottom of the target scope. The output content can be inserted into other positions of the target scope by using the ``position`` parameter of the output function.
 
-一个Scope中各次输出的元素具有像数组一样的索引,最前面的编号为0,以此往后递增加一;同样可以使用负数对Scope中的元素进行索引,-1表示最后面的元素,-2表示次后面的元素......
+Each output item in a scope has an index, the first item's index is 0, and the next item's index is incremented by one. You can also use a negative number to index the items in the scope, -1 means the last item, -2 means the item before the last...
 
-Each output element in a scope has an index like Python list, the first element's index is 0, and the next element's index is incremented by one. You can also use a negative number to index the elements in the scope, -1 means the last element, -2 means the element before the last...
-
-``position`` 参数类型为整形, ``position>=0`` 时表示输出内容到目标Scope的第position号元素的前面; ``position<0`` 时表示输出内容到目标Scope第position号元素之后:
-
-The ``position`` parameter is integer. When ``position>=0``, it means to insert content before the element whose index equal ``position``; when ``position<0``, it means to insert content after the element whose index equal ``position``:
+The ``position`` parameter of output functions is an integer. When ``position>=0``, it means to insert content before the item whose index equal ``position``; when ``position<0``, it means to insert content after the item whose index equal ``position``:
 
 .. exportable-codeblock::
     :name: put-xxx-position
@@ -586,8 +481,6 @@ The ``position`` parameter is integer. When ``position>=0``, it means to insert
 
 **Scope control**
 
-除了 `use_scope()` , PyWebIO同样提供了以下scope控制函数:
-
 In addition to `use_scope() <pywebio.output.use_scope>`, PyWebIO also provides the following scope control functions:
 
 * `set_scope(name) <pywebio.output.set_scope>` : Create scope at current location(or specified location)
@@ -605,38 +498,26 @@ You can call `set_env(title=...) <pywebio.session.set_env>` to set the page titl
 
 **Auto Scroll**
 
-在进行一些持续性的输出时(比如日志输出),有时希望在有新输出后自动将页面滚动到最下方,这时可以调用 `set_env(auto_scroll_bottom=True) <pywebio.session.set_env>` 来开启自动滚动。
-注意,开启后,只有输出到ROOT Scope才可以触发自动滚动。
-
-When performing some continuous output (such as log output), you may want to automatically scroll the page to the bottom when there is new output. You can call `set_env(auto_scroll_bottom=True) <pywebio.session.set_env>` to enable automatic scrolling. Note that after enabled, only outputting to ROOT scope can trigger automatic scrolling.
+When performing some continuous output (such as log output), you may want to scroll the page to the bottom automatically when there is new output. You can call `set_env(auto_scroll_bottom=True) <pywebio.session.set_env>` to enable automatic scrolling. Note that when enabled, only outputting to ROOT scope can trigger automatic scrolling.
 
 **Output Animation**
 
-PyWebIO在输出内容时默认会使用淡入的动画效果来显示内容,可使用 `set_env(output_animation=False) <pywebio.session.set_env>` 来关闭动画。
-
-PyWebIO will use the fade-in animation effect to display the content by default. You can use `set_env(output_animation=False) <pywebio.session.set_env>` to turn off the animation.
-
-有关不同环境配置的效果可查看 :demo_host:`set_env Demo </?pywebio_api=set_env_demo>`
+By default, PyWebIO will use the fade-in animation effect to display the content. You can use `set_env(output_animation=False) <pywebio.session.set_env>` to turn off the animation.
 
-For the effects of different environment settings, please see :demo_host:`set_env Demo </?pywebio_api=set_env_demo>`
+To view the effects of environment settings, please visit :demo_host:`set_env Demo </?pywebio_api=set_env_demo>`
 
 Layout
 ^^^^^^^^^^^^^^
-一般情况下,使用上文介绍的各种输出函数足以完成各种内容的展示,但直接调用输出函数产生的输出之间都是竖直排列的,如果想实现更复杂的布局(比如在页面左侧显示一个代码块,在右侧显示一个图像),就需要借助布局函数。
 
-In general, using the various output functions introduced above to output all kinds of content is enough, but these outputs are arranged vertically. If you want to make a more complex layout (such as displaying a code block on the left side of the page and an image on the right left), you need to use layout functions.
+In general, using the various output functions introduced above is enough to output what you want, but these outputs are arranged vertically. If you want to make a more complex layout (such as displaying a code block on the left side of the page and an image on the right), you need to use layout functions.
 
-``pywebio.output`` 模块提供了3个布局函数,通过对他们进行组合可以完成各种复杂的布局:
+The ``pywebio.output`` module provides 3 layout functions, and you can create complex layouts by combining them:
 
-The ``pywebio.output`` module provides three layout functions, and you can make complex layouts by combining them:
+* `put_row() <pywebio.output.put_row>` : Use row layout to output content. The content is arranged horizontally
+* `put_column() <pywebio.output.put_column>` : Use column layout to output content. The content is arranged vertically
+* `put_grid() <pywebio.output.put_grid>` : Output content using grid layout
 
-* `put_row() <pywebio.output.put_row>` : 使用行布局输出内容. 内容在水平方向上排列 Use row layout to output content. The content is arranged horizontally
-* `put_column() <pywebio.output.put_column>` : 使用列布局输出内容. 内容在竖直方向上排列 Use column layout to output content. The content is arranged vertically
-* `put_grid() <pywebio.output.put_grid>` : 使用网格布局输出内容 Output content using grid layout
-
-通过组合 ``put_row()`` 和 ``put_column()`` 可以实现灵活布局:
-
-Here is a layout example by combining ``put_row()`` and ``put_column()``:
+Here is an example by combining ``put_row()`` and ``put_column()``:
 
 .. exportable-codeblock::
     :name: put-row-column
@@ -656,31 +537,22 @@ Here is a layout example by combining ``put_row()`` and ``put_column()``:
         put_code('E')
     ])
 
-显示效果如下:
-
 The results of the above example are as follows:
 
 .. image:: /assets/layout.png
    :align: center
 
-布局函数还支持自定义各部分的尺寸:
-
 The layout function also supports customizing the size of each part::
 
     put_row([put_image(...), put_image(...)], size='40% 60%')  # The ratio of the width of two images is 2:3
 
-更多布局函数的用法及代码示例请查阅 :ref:`布局函数文档 <style_and_layout>` .
-
 For more information, please refer to the :ref:`layout function documentation <style_and_layout>`.
 
 Style
 ^^^^^^^^^^^^^^
-如果你熟悉 `CSS样式 <https://www.google.com/search?q=CSS%E6%A0%B7%E5%BC%8F>`_ ,你还可以使用 `style() <pywebio.output.style>` 函数给输出设定自定义样式。
 
 If you are familiar with `CSS <https://en.wikipedia.org/wiki/CSS>`_ styles, you can use the `style() <pywebio.output.style>` function to set a custom style for the output.
 
-可以给单个的 ``put_xxx()`` 输出设定CSS样式,也可以配合组合输出使用:
-
 You can set the CSS style for a single ``put_xxx()`` output:
 
 .. exportable-codeblock::
@@ -695,9 +567,7 @@ You can set the CSS style for a single ``put_xxx()`` output:
         ['C', style(put_text('Red'), 'color: red')],
     ])
 
-``style()`` 也接受列表作为输入,``style()`` 会为列表的每一项都设置CSS样式,返回值可以直接输出,可用于任何接受 ``put_xxx()`` 列表的地方:
-
-`style() <pywebio.output.style>` also accepts a list of output calls, `style() <pywebio.output.style>` will set the CSS style for each item in the list:
+`style() <pywebio.output.style>` also accepts a list of output calls, `style() <pywebio.output.style>` will set the CSS style for each item of the list:
 
 .. exportable-codeblock::
     :name: style-list
@@ -720,21 +590,13 @@ You can set the CSS style for a single ``put_xxx()`` output:
 Server mode and Script mode
 ------------------------------------
 
-在 :ref:`Hello, world <hello_word>` 一节中,已经知道,PyWebIO支持在普通的脚本中调用和使用
-`start_server() <pywebio.platform.tornado.start_server>` 启动一个Web服务两种模式。
-
-In the :ref:`Hello, world <hello_word>` section, we already know that PyWebIO supports two modes of running as a script and  using `start_server() <pywebio.platform.tornado.start_server>` to run as a web service.
+In the :ref:`Hello, world <hello_word>` section, we already know that PyWebIO supports two modes: running as a script and using `start_server() <pywebio.platform.tornado.start_server>` to run as a web service.
 
 **Server mode**
 
-在Server模式下,PyWebIO会启动一个Web服务来持续性地提供服务。需要提供一个任务函数(类似于Web开发中的视图函数),当用户访问服务地址时,PyWebIO会开启一个新会话并运行任务函数。
-
-In Server mode, PyWebIO will start a web server to continuously provide services. A task function (similar to the view function in Flask) needs to be provided. When the user accesses the service address, PyWebIO will open a new session and run the task function.
+In Server mode, PyWebIO will start a web server to continuously provide services. A task function needs to be provided. When the user accesses the service address, PyWebIO will open a new session and run the task function.
 
-使用 `start_server() <pywebio.platform.tornado.start_server>` 来启动PyWebIO的Server模式, `start_server() <pywebio.platform.tornado.start_server>` 除了接收一个函数作为任务函数外,
-还支持传入函数列表或字典,从而使一个PyWebIO Server下可以有多个不同功能的服务,服务之间可以通过 `go_app() <pywebio.session.go_app>` 或 `put_link() <pywebio.output.put_link>` 进行跳转
-
-Use `start_server() <pywebio.platform.tornado.start_server>` to start a web service. In addition to accepting a function as task function, ``start_server()`` also accepts a list of task function or a dictionary of it, so that a PyWebIO Server can have multiple services with different functions. You can use `go_app() <pywebio.session.go_app>` or `put_link() <pywebio.output.put_link>` to jump between services::
+Use `start_server() <pywebio.platform.tornado.start_server>` to start a web service. In addition to accepting a function as task function, ``start_server()`` also accepts a list of task function or a dictionary of it, so that one PyWebIO Server can have multiple services with different functions. You can use `go_app() <pywebio.session.go_app>` or `put_link() <pywebio.output.put_link>` to jump between services::
 
     def task_1():
         put_text('task_1')
@@ -752,13 +614,12 @@ Use `start_server() <pywebio.platform.tornado.start_server>` to start a web serv
 
     start_server([index, task_1, task_2])  # or start_server({'index': index, 'task_1': task_1, 'task_2': task_2}) For more information, please refer to the function documentation.
 
-可以使用 `pywebio.platform.seo()` 函数来设置任务函数SEO信息(在被搜索引擎索引时提供的网页信息,包含应用标题和应用简介),如果不使用 ``seo()`` 函数,默认条件下,PyWebIO会将任务函数的函数注释作为SEO信息(应用标题和简介之间使用一个空行分隔)。
 
-.. attention::
+You can use `pywebio.platform.seo()` to set the `SEO <https://en.wikipedia.org/wiki/Search_engine_optimization>`_ information. If not ``seo()`` is not used, the `docstring <https://www.python.org/dev/peps/pep-0257/>`_ of the task function will be regarded as SEO information by default.
 
-    注意,在Server模式下,仅能在任务函数上下文中对PyWebIO的交互函数进行调用。比如如下调用是 **不被允许的**
+.. attention::
 
-    Note that in Server mode, PyWebIO's input and output functions can only be called in the context of task functions. For example, the following code is not allowed::
+    Note that in Server mode, PyWebIO's input and output functions can only be called in the context of task functions. For example, the following code is **not allowed**::
 
         import pywebio
         from pywebio.input import input
@@ -769,12 +630,8 @@ Use `start_server() <pywebio.platform.tornado.start_server>` to start a web serv
 
 **Script mode**
 
-Script模式下,在任何位置都可以调用PyWebIO的交互函数。
-
 In Script mode, PyWebIO input and output functions can be called anywhere.
 
-如果用户在会话结束之前关闭了浏览器,那么之后会话内对于PyWebIO交互函数的调用将会引发一个 `SessionException <pywebio.exceptions.SessionException>` 异常。
-
 If the user closes the browser before the end of the session, then calls to PyWebIO input and output functions in the session will cause a `SessionException <pywebio.exceptions.SessionException>` exception.
 
 .. _thread_in_server_mode:
@@ -782,26 +639,16 @@ If the user closes the browser before the end of the session, then calls to PyWe
 Concurrent
 ^^^^^^^^^^^^^^
 
-PyWebIO 支持在多线程环境中使用。
-
 PyWebIO can be used in a multi-threading environment.
 
 **Script mode**
 
-在 Script模式下,你可以自由地启动线程,并在其中调用PyWebIO的交互函数。当所有非 `Daemon线程 <https://docs.python.org/3/library/threading.html#thread-objects>`_ 运行结束后,脚本退出。
-
 In Script mode, you can freely start new thread and call PyWebIO interactive functions in it. When all `non-daemonic <https://docs.python.org/3/library/threading.html#thread-objects>`_ threads finish running, the script exits.
 
 **Server mode**
 
-Server模式下,如果需要在新创建的线程中使用PyWebIO的交互函数,需要手动调用 `register_thread(thread) <pywebio.session.register_thread>` 对新进程进行注册(这样PyWebIO才能知道新创建的线程属于哪个会话)。
-如果新创建的线程中没有使用到PyWebIO的交互函数,则无需注册。没有使用 `register_thread(thread) <pywebio.session.register_thread>` 注册的线程不受会话管理,其调用PyWebIO的交互函数将会产生 `SessionNotFoundException <pywebio.exceptions.SessionNotFoundException>` 异常。
-当会话的任务函数和会话内通过 `register_thread(thread) <pywebio.session.register_thread>` 注册的线程都结束运行时,会话关闭。
-
 In Server mode, if you need to use PyWebIO interactive functions in new thread, you need to use `register_thread(thread) <pywebio.session.register_thread>` to register the new thread (so that PyWebIO can know which session the thread belongs to). If the PyWebIO interactive function is not used in the new thread, no registration is required. Threads that are not registered with `register_thread(thread) <pywebio.session.register_thread>` calling PyWebIO's interactive functions will cause `SessionNotFoundException <pywebio.exceptions.SessionNotFoundException>`. When both the task function of the session and the thread registered through `register_thread(thread) <pywebio.session.register_thread>` in the session have finished running, the session is closed.
 
-Server模式下多线程的使用示例:
-
 Example of using multi-threading in Server mode::
 
    def show_time():
@@ -830,36 +677,23 @@ Example of using multi-threading in Server mode::
 Close of session
 ^^^^^^^^^^^^^^^^^
 
-会话还会因为用户的关闭浏览器而结束,这时当前会话内还未返回的PyWebIO输入函数调用将抛出 `SessionClosedException <pywebio.exceptions.SessionClosedException>` 异常,之后对于PyWebIO交互函数的调用将会产生 `SessionNotFoundException <pywebio.exceptions.SessionNotFoundException>` 或 `SessionClosedException <pywebio.exceptions.SessionClosedException>` 异常。
-
-The session will also close because the user closes the browser page. After the browser page closed, PyWebIO input function calls that have not yet returned in the current session will cause `SessionClosedException <pywebio.exceptions.SessionClosedException>`, and subsequent calls to PyWebIO interactive functions will cause `SessionNotFoundException <pywebio.exceptions.SessionNotFoundException>` or `SessionClosedException <pywebio.exceptions.SessionClosedException>`.
-
-可以使用 `defer_call(func) <pywebio.session.defer_call>` 来设置会话结束时需要调用的函数。无论是因为用户主动关闭页面还是任务结束使得会话关闭,设置的函数都会被执行。
-`defer_call(func) <pywebio.session.defer_call>` 可以用于资源清理等工作。在会话中可以多次调用 `defer_call() <pywebio.session.defer_call>` ,会话结束后将会顺序执行设置的函数。
+The close of session may also be caused by the user closing the browser page. After the browser page is closed, PyWebIO input function calls that have not yet returned in the current session will cause `SessionClosedException <pywebio.exceptions.SessionClosedException>`, and subsequent calls to PyWebIO interactive functions will cause `SessionNotFoundException <pywebio.exceptions.SessionNotFoundException>` or `SessionClosedException <pywebio.exceptions.SessionClosedException>`.
 
 You can use `defer_call(func) <pywebio.session.defer_call>` to set the function to be called when the session closes. Whether it is because the user closes the page or the task finishes to cause session closed, the function set by `defer_call(func) <pywebio.session.defer_call>` will be executed. `defer_call(func) <pywebio.session.defer_call>` can be used for resource cleaning. You can call `defer_call(func) <pywebio.session.defer_call>` multiple times in the session, and the set functions will be executed sequentially after the session closes.
 
-Integration with web framework
----------------------------------
-
 .. _integration_web_framework:
 
-可以将PyWebIO应用集成到现有的Python Web项目中,PyWebIO应用与Web项目共用一个Web框架。目前支持与Flask、Tornado、Django和aiohttp Web框架的集成。
+Integration with web framework
+---------------------------------
 
 The PyWebIO application can be integrated into an existing Python Web project, and the PyWebIO application and the Web project share a web framework. PyWebIO currently supports integration with Flask, Tornado, Django and aiohttp web frameworks.
 
-集成方法
-^^^^^^^^^^^
-
-不同Web框架的集成方法如下:
-
 The integration methods of different web frameworks are as follows:
 
 .. tabs::
 
    .. tab:: Tornado
 
-        需要在Tornado应用中引入一个 ``RequestHandler``
         Need to add a ``RequestHandler`` to Tornado application::
 
             import tornado.ioloop
@@ -879,23 +713,16 @@ The integration methods of different web frameworks are as follows:
                 application.listen(port=80, address='localhost')
                 tornado.ioloop.IOLoop.current().start()
 
-        以上代码调用 `webio_handler(task_func) <pywebio.platform.tornado.webio_handler>` 来获得PyWebIO和浏览器进行通讯的Tornado `WebSocketHandler <https://www.tornadoweb.org/en/stable/websocket.html#tornado.websocket.WebSocketHandler>`_ ,
-        并将其绑定在 ``/tool`` 路由下。启动Tornado服务器后,访问 ``http://localhost/tool`` 即可打开PyWebIO应用
 
         In above code, we use `webio_handler(task_func) <pywebio.platform.tornado.webio_handler>` to get the Tornado `WebSocketHandler <https://www.tornadoweb.org/en/stable/websocket.html#tornado.websocket.WebSocketHandler>`_  that communicates with the browser, and bind it to the ``/tool`` path. After starting the Tornado server, you can visit ``http://localhost/tool`` to open the PyWebIO application.
 
         .. attention::
 
-           当使用Tornado后端时,PyWebIO使用WebSocket协议和浏览器进行通讯,如果你的Tornado应用处在反向代理(比如Nginx)之后,
-           可能需要特别配置反向代理来支持WebSocket协议,:ref:`这里 <nginx_ws_config>` 有一个Nginx配置WebSocket的例子。
-
            PyWebIO uses the WebSocket protocol to communicate with the browser in Tornado. If your Tornado application is behind a reverse proxy (such as Nginx), you may need to configure the reverse proxy to support the WebSocket protocol. :ref:`Here <nginx_ws_config>` is an example of Nginx WebSocket configuration.
 
    .. tab:: Flask
 
-        需要添加一个PyWebIO相关的路由,用来和浏览器进行Http通讯
-        One route need to be added to communicate with the browser through WebSocket::
-
+        One route need to be added to communicate with the browser through HTTP::
 
             from pywebio.platform.flask import webio_view
             from pywebio import STATIC_PATH
@@ -909,16 +736,12 @@ The integration methods of different web frameworks are as follows:
 
             app.run(host='localhost', port=80)
 
-        以上代码使用 `webio_view(task_func) <pywebio.platform.flask.webio_view>` 来获得运行PyWebIO应用的Flask视图 ,
-        并调用 `Flask.add_url_rule <https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.add_url_rule>`_ 将其绑定在 ``/tool`` 路径下。启动Flask应用后,访问 ``http://localhost/tool`` 即可打开PyWebIO应用
 
-        In above code, we use `webio_view(task_func) <pywebio.platform.flask.webio_view>` to get the Flask view of the PyWebIO application, and use `Flask.add_url_rule <https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.add_url_rule>`_ to bind it to ``/tool`` path. After starting the Flask application, visit ``http://localhost/tool`` to open the PyWebIO application.
+        In above code, we use `webio_view(task_func) <pywebio.platform.flask.webio_view>` to get the Flask view of the PyWebIO application, and bind it to ``/tool`` path. After starting the Flask application, visit ``http://localhost/tool`` to open the PyWebIO application.
 
    .. tab:: Django
 
-        在django的路由配置文件 ``urls.py`` 中加入PyWebIO相关的路由即可
-
-        Need to add two routes in ``urls.py``::
+        Need to add a route in ``urls.py``::
 
             # urls.py
 
@@ -932,18 +755,15 @@ The integration methods of different web frameworks are as follows:
             webio_view_func = webio_view(task_func)
 
             urlpatterns = [
-                path(r"tool", webio_view_func),  # http通信接口
+                path(r"tool", webio_view_func),
             ]
 
-        以上代码使用添加了一条路由规则将PyWebIO应用的视图函数绑定到 ``/tool`` 路径下。
-        启动Django应用后,访问 ``http://localhost/tool`` 即可打开PyWebIO应用
 
-        Add a routing rule that binds the view function of the PyWebIO application to the ``/tool`` path
+        In above code, we add a routing rule to bind the view function of the PyWebIO application to the ``/tool`` path
         After starting the Django server, visit ``http://localhost/tool`` to open the PyWebIO application
 
    .. tab:: aiohttp
 
-      需要添加一个PyWebIO相关的路由,用来和浏览器进行WebSocket通讯
       One route need to be added to communicate with the browser through WebSocket:::
 
             from aiohttp import web
@@ -951,19 +771,14 @@ The integration methods of different web frameworks are as follows:
 
             app = web.Application()
             # `task_func` is PyWebIO task function
-            app.add_routes([web.get('/tool', webio_handler(task_func))])  # websocket通信接口
+            app.add_routes([web.get('/tool', webio_handler(task_func))])
 
             web.run_app(app, host='localhost', port=80)
 
-      启动aiohttp应用后,访问 ``http://localhost/tool`` 即可打开PyWebIO应用
-
       After starting the aiohttp server, visit ``http://localhost/tool`` to open the PyWebIO application
 
       .. attention::
 
-        当使用aiohttp后端时,PyWebIO使用WebSocket协议和浏览器进行通讯,如果你的aiohttp应用处在反向代理(比如Nginx)之后,
-        可能需要特别配置反向代理来支持WebSocket协议,:ref:`这里 <nginx_ws_config>` 有一个Nginx配置WebSocket的例子。
-
         PyWebIO uses the WebSocket protocol to communicate with the browser in aiohttp. If your aiohttp server is behind a reverse proxy (such as Nginx), you may need to configure the reverse proxy to support the WebSocket protocol. :ref:`Here <nginx_ws_config>` is an example of Nginx WebSocket configuration.
 
 .. _integration_web_framework_note:
@@ -972,38 +787,30 @@ Notes
 ^^^^^^^^^^^
 **Static resources Hosting**
 
-PyWebIO默认使用CDN来获取前端的静态资源,如果要将PyWebIO应用部署到离线环境中,需要自行托管静态文件,
-并将 ``webio_view()`` 或 ``webio_handler()`` 的 ``cdn`` 参数设置为 ``False`` ,此时需要将静态资源托管在和PyWebIO应用同级的目录下。
-同时,也可以通过 ``cdn`` 参数直接设置PyWebIO静态资源的部署目录。
+By default, the front-end of PyWebIO gets required static resources from CDN. If you want to deploy PyWebIO applications in an offline environment, you need to host static files by yourself, and set the ``cdn`` parameter of ``webio_view()`` or ``webio_handler()`` to ``False``.
+
+When setting ``cdn=False`` , you need to host the static resources in the same directory as the PyWebIO application.
+In addition, you can also pass a string to ``cdn`` parameter to directly set the deployment directory of PyWebIO static resources.
 
-PyWebIO的静态文件的路径可保存在 ``pywebio.STATIC_PATH`` 中,可使用命令 ``python3 -c "import pywebio; print(pywebio.STATIC_PATH)"`` 将其打印出来。
+The path of the static file of PyWebIO is stored in ``pywebio.STATIC_PATH``, you can use the command ``python3 -c "import pywebio; print(pywebio.STATIC_PATH)"`` to print it out.
 
-.. note:: 使用 ``start_server()`` 启动的应用,如果将 ``cdn`` 参数设置为 ``False`` ,会自动启动一个本地的静态资源托管服务,无需手动托管。
+.. note:: ``start_server()`` also support ``cdn`` parameter, if it is set to ``False``, the static resource will be hosted in local server automatically, without manual hosting.
 
 
 .. _coroutine_based_session:
 
 Coroutine-based session
 -------------------------------
-此部分内容属于高级特性,您不必使用此部分也可以实现PyWebIO支持的全部功能。PyWebIO中所有仅用于协程会话的函数或方法都在文档中有特别说明。
 
-This section will introduce the advanced features of PyWebIO. In most cases, you don’t need it. All functions or methods in PyWebIO that are only used for coroutine sessions are specifically noted in the document.
+This section will introduce the advanced features of PyWebIO --- coroutine-based session. In most cases, you don’t need it. All functions or methods in PyWebIO that are only used for coroutine sessions are specifically noted in the document.
 
-PyWebIO的会话实现默认是基于线程的,用户每打开一个和服务端的会话连接,PyWebIO会启动一个线程来运行任务函数。
-除了基于线程的会话,PyWebIO还提供了基于协程的会话。基于协程的会话接受协程函数作为任务函数。
+PyWebIO's session is based on thread by default. Each time a user opens a session connection to the server, PyWebIO will start a thread to run the task function. In addition to thread-based sessions, PyWebIO also provides coroutine-based sessions. Coroutine-based sessions accept coroutine functions as task functions.
 
-PyWebIO's session is based on thread by default. Each time a user opens a session connection with the server, PyWebIO will start a thread to run task functions. In addition to thread-based sessions, PyWebIO also provides coroutine-based sessions. Coroutine-based sessions accept coroutine functions as task functions.
-
-基于协程的会话为单线程模型,所有会话都运行在一个线程内。对于IO密集型的任务,协程比线程占用更少的资源同时又拥有媲美于线程的性能。
-另外,协程的上下文切换具有可预测性,能够减少程序同步与加锁的需要,可以有效避免大多数临界区问题。
-
-The session based on the coroutine uses a single-threaded model, which means that all sessions run in a single thread. For IO-bound tasks, coroutines take up fewer resources than threads and have performance comparable to threads. In addition, the context switching of the coroutine is predictable, which can reduce the need for program synchronization and locking, and can effectively avoid most critical section problems.
+The session based on the coroutine is a single-thread model, which means that all sessions run in a single thread. For IO-bound tasks, coroutines take up fewer resources than threads and have performance comparable to threads. In addition, the context switching of the coroutine is predictable, which can reduce the need for program synchronization and locking, and can effectively avoid most critical section problems.
 
 Using coroutine session
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-要使用基于协程的会话,需要使用 ``async`` 关键字将任务函数声明为协程函数,并使用 ``await`` 语法调用PyWebIO输入函数:
-
 To use coroutine-based session, you need to use the ``async`` keyword to declare the task function as a coroutine function, and use the ``await`` syntax to call the PyWebIO input function:
 
 .. code-block:: python
@@ -1019,7 +826,6 @@ To use coroutine-based session, you need to use the ``async`` keyword to declare
 
     start_server(say_hello, auto_open_webbrowser=True)
 
-在协程任务函数中,也可以使用 ``await`` 调用其他协程或标准库 `asyncio <https://docs.python.org/3/library/asyncio.html>`_ 中的可等待对象( `awaitable objects <https://docs.python.org/3/library/asyncio-task.html#asyncio-awaitables>`_ ):
 
 In the coroutine task function, you can also use ``await`` to call other coroutines or ( `awaitable objects <https://docs.python.org/3/library/asyncio-task.html#asyncio-awaitables>`_ ) in the standard library `asyncio <https://docs.python.org/3/library/asyncio.html>`_:
 
@@ -1031,24 +837,19 @@ In the coroutine task function, you can also use ``await`` to call other corouti
 
     async def hello_word():
         put_text('Hello ...')
-        await asyncio.sleep(1)  # await asyncio 库中的 awaitable objects
+        await asyncio.sleep(1)  # await awaitable objects in asyncio
         put_text('... World!')
 
     async def main():
-        await hello_word()  # await 协程
+        await hello_word()  # await coroutine
         put_text('Bye, bye')
 
     start_server(main, auto_open_webbrowser=True)
 
 .. attention::
 
-   在基于协程的会话中, :doc:`pywebio.input </input>` 模块中的定义输入函数都需要使用 ``await`` 语法来获取返回值,
-   忘记使用 ``await`` 将会是在使用基于协程的会话时常出现的错误。
-
    In coroutine-based session, all input functions defined in the :doc:`pywebio.input </input>` module need to use ``await`` syntax to get the return value. Forgetting to use ``await`` will be a common error when using coroutine-based session.
 
-   其他在协程会话中也需要使用 ``await`` 语法来进行调用函数有:
-
    Other functions that need to use ``await`` syntax in the coroutine session are:
 
     * `pywebio.session.run_asyncio_coroutine(coro_obj) <pywebio.session.run_asyncio_coroutine>`
@@ -1057,13 +858,9 @@ In the coroutine task function, you can also use ``await`` to call other corouti
 
 .. warning::
 
-   虽然PyWebIO的协程会话兼容标准库 ``asyncio`` 中的 ``awaitable objects`` ,但 ``asyncio`` 库不兼容PyWebIO协程会话中的 ``awaitable objects`` .
-
    Although the PyWebIO coroutine session is compatible with the ``awaitable objects`` in the standard library ``asyncio``, the ``asyncio`` library is not compatible with the ``awaitable objects`` in the PyWebIO coroutine session.
 
-   也就是说,无法将PyWebIO中的 ``awaitable objects`` 传入 ``asyncio`` 中的接受 ``awaitable objects`` 作为参数的函数中,比如如下调用是 **不被支持的**
-
-   That is to say, you can't pass PyWebIO ``awaitable objects`` to the `asyncio`` function that accepts ``awaitable objects``. For example, the following calls are **unsupported** ::
+   That is to say, you can't pass PyWebIO ``awaitable objects`` to the `asyncio`` functions that accept ``awaitable objects``. For example, the following calls are **not supported** ::
 
       await asyncio.shield(pywebio.input())
       await asyncio.gather(asyncio.sleep(1), pywebio.session.eval_js('1+1'))
@@ -1074,9 +871,6 @@ In the coroutine task function, you can also use ``await`` to call other corouti
 Concurrency in coroutine-based sessions
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-在基于协程的会话中,你可以启动线程,但是无法在其中调用PyWebIO交互函数( `register_thread() <pywebio.session.register_thread>` 在协程会话中不可用)。
-但你可以使用 `run_async(coro) <pywebio.session.run_async>` 来异步执行一个协程对象,新协程内可以使用PyWebIO交互函数
-
 In coroutine-based session, you can start new thread, but you cannot call PyWebIO interactive functions in it (`register_thread() <pywebio.session.register_thread>` is not available in coroutine session). But you can use `run_async(coro) <pywebio.session.run_async>` to execute a coroutine object asynchronously, and PyWebIO interactive functions can be used in the new coroutine:
 
 .. code-block:: python
@@ -1097,46 +891,31 @@ In coroutine-based session, you can start new thread, but you cannot call PyWebI
 
     start_server(main, auto_open_webbrowser=True)
 
-`run_async(coro) <pywebio.session.run_async>` 返回一个 `TaskHandle <pywebio.session.coroutinebased.TaskHandle>` ,通过 `TaskHandle <pywebio.session.coroutinebased.TaskHandle>` 可以查询协程运行状态和关闭协程。
 
 `run_async(coro) <pywebio.session.run_async>` returns a `TaskHandle <pywebio.session.coroutinebased.TaskHandle>`, which can be used to query the running status of the coroutine or close the coroutine.
 
 Close of session
 ^^^^^^^^^^^^^^^^^^^
-与基于线程的会话类似,在基于协程的会话中,当任务函数和在会话内通过 `run_async() <pywebio.session.run_async>` 运行的协程全部结束后,会话关闭。
 
 Similar to thread-based session, in coroutine-based session, when the task function and the coroutine running through `run_async() <pywebio.session.run_async>` in the session are all finished, the session is closed.
 
-对于因为用户的关闭浏览器而造成的会话结束,处理逻辑和 :ref:`基于线程的会话 <session_close>` 一致:
-此时当前会话内还未返回的PyWebIO输入函数调用将抛出 `SessionClosedException <pywebio.exceptions.SessionClosedException>` 异常,之后对于PyWebIO交互函数的调用将会产生 `SessionNotFoundException <pywebio.exceptions.SessionNotFoundException>` 或 `SessionClosedException <pywebio.exceptions.SessionClosedException>` 异常。
-
 If the close of the session is caused by the user closing the browser, the behavior of PyWebIO is the same as :ref:`Thread-based session <session_close>`: After the browser page closed, PyWebIO input function calls that have not yet returned in the current session will cause `SessionClosedException <pywebio.exceptions.SessionClosedException>`, and subsequent calls to PyWebIO interactive functions will cause `SessionNotFoundException <pywebio.exceptions.SessionNotFoundException>` or `SessionClosedException <pywebio.exceptions.SessionClosedException>`.
 
-协程会话也同样支持使用 `defer_call(func) <pywebio.session.defer_call>` 来设置会话结束时需要调用的函数。
-
 `defer_call(func) <pywebio.session.defer_call>` also available in coroutine session.
 
+.. _coroutine_web_integration:
+
 Integration with Web Framework
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-基于协程的会话同样可以与Web框架进行集成,只需要在原来传入任务函数的地方改为传入协程函数即可。
-
-The coroutine-based session can also be integrated with the web framework.
-
-但当前在使用基于协程的会话集成进Flask或Django时,存在一些限制:
+The PyWebIO application that using coroutine-based session can also be integrated to the web framework.
 
 However, there are some limitations when using coroutine-based sessions to integrate into Flask or Django:
 
-一是协程函数内还无法直接通过 ``await`` 直接等待asyncio库中的协程对象,目前需要使用 `run_asyncio_coroutine() <pywebio.session.run_asyncio_coroutine>` 进行包装。
-
-First, when ``await`` the coroutine object in the ``asyncio`` module, you need use `run_asyncio_coroutine() <pywebio.session.run_asyncio_coroutine>` to wrap the coroutine object.
-
-二是,在启动Flask/Django这类基于线程的服务器之前需要启动一个单独的线程来运行事件循环。
+First, when ``await`` the coroutine objects/awaitable objects in the ``asyncio`` module, you need to use `run_asyncio_coroutine() <pywebio.session.run_asyncio_coroutine>` to wrap the coroutine object.
 
 Secondly, you need to start a new thread to run the event loop before starting a Flask/Django server.
 
-使用基于协程的会话集成进Flask的示例:
-
 Example of coroutine-based session integration into Flask:
 
 .. code-block:: python
@@ -1164,22 +943,14 @@ Example of coroutine-based session integration into Flask:
     threading.Thread(target=run_event_loop, daemon=True).start()
     app.run(host='localhost', port=80)
 
-最后,使用PyWebIO编写的协程函数不支持Script模式,总是需要使用 ``start_server`` 来启动一个服务或者集成进Web框架来调用。
-
-Finally, coroutine-based session is not available in the Script mode.
+Finally, coroutine-based session is not available in the Script mode. You always need to use ``start_server()`` to run coroutine task function or integrate it to a web framework.
 
 Last but not least
 ---------------------
 
-以上就是PyWebIO的全部功能了,你可以继续阅读接下来的文档,或者立即开始PyWebIO应用的编写了。
-
 This is all features of PyWebIO, you can continue to read the rest of the documents, or start writing your PyWebIO applications now.
 
-最后再提供一条建议,当你在使用PyWebIO遇到设计上的问题时,可以问一下自己:如果在是在终端程序中我会怎么做?
-如果你已经有答案了,那么在PyWebIO中一样可以使用这样的方式完成。如果问题依然存在或者觉得解决方案不够好,
-你可以考虑使用 `put_buttons() <pywebio.output.put_buttons>` 提供的回调机制。
-
-Finally, please allow me to provide one more suggestion. When you encounter design problems when using PyWebIO, you can ask yourself a question: What would I do if it is in a terminal program?
-If you already have the answer, it can be done in the same way with PyWebIO. If the problem persists or the solution is not good enough, you can consider using the callback mechanism provided by `put_buttons() <pywebio.output.put_buttons>`.
+Finally, please allow me to provide one more suggestion. When you encounter a design problem when using PyWebIO, you can ask yourself a question: What would I do if it is in a terminal program?
+If you already have the answer, it can be done in the same way with PyWebIO. If the problem persists or the solution is not good enough, you can consider the callback mechanism provided by `put_buttons() <pywebio.output.put_buttons>`.
 
 OK, Have fun with PyWebIO!

+ 5 - 5
docs/index.rst

@@ -1,12 +1,12 @@
 PyWebIO
 ==========
 
-PyWebIO provides a series of imperative functions to obtain user input and output on the browser, turning the browser into a "rich text terminal", which can be used to build simple web applications or browser-based GUI applications. Using PyWebIO, developers can write applications just like writing terminal scripts (interaction based on input and print), without the need to have relevant knowledge of HTML and JS. PyWebIO can also be easily integrated into existing Web services. PyWebIO is very suitable for quickly building applications that do not require complex UI.
+PyWebIO provides a series of imperative functions to obtain user input and output on the browser, turning the browser into a "rich text terminal", and can be used to build simple web applications or browser-based GUI applications. Using PyWebIO, developers can write applications just like writing terminal scripts (interaction based on input and print), without the need to have knowledge of HTML and JS. PyWebIO can also be easily integrated into existing Web services. PyWebIO is very suitable for quickly building applications that do not require complex UI.
 
 Features
 ------------
 
-- Use synchronization instead of callback-based method to get input, making programing logic more natural
+- Use synchronization instead of callback-based method to get input
 - Non-declarative layout, simple and efficient
 - Less intrusive: old script code can be transformed into a Web service only by modifying the input and output logic
 - Support integration into existing web services, currently supports Flask, Django, Tornado, aiohttp framework
@@ -55,15 +55,15 @@ Here is a simple PyWebIO script to calculate the `BMI <https://en.wikipedia.org/
     if __name__ == '__main__':
         bmi()
 
-This is just a very simple script if you ignore PyWebIO, but by using the input and output functions provided by PyWebIO, you can interact with the code in the browser:
+This is just a very simple script if you ignore PyWebIO, but after using the input and output functions provided by PyWebIO, you can interact with the code in the browser:
 
 .. image:: /assets/demo.*
    :width: 450px
    :align: center
 
-In the last line of the above code, change the function call ``bmi()`` to `pywebio.start_server(bmi, port=80) <pywebio.platform.tornado.start_server>` to provide bmi service on port 80 ( :demo_host:`online Demo </?pywebio_api=bmi>` ).
+In the last line of the above code, changing the function call ``bmi()`` to `pywebio.start_server(bmi, port=80) <pywebio.platform.tornado.start_server>` will start a bmi web service on port 80 ( :demo_host:`online Demo </?pywebio_api=bmi>` ).
 
-If you want to integrate the ``bmi()`` service into an existing web framework, you can visit :ref:`Integration with a web framework <integration_web_framework>` part of this document.
+If you want to integrate the ``bmi()`` service into an existing web framework, you can visit :ref:`Integration with a web framework <integration_web_framework>` section of this document.
 
 Documentation
 -------------

+ 3 - 21
docs/libraries_support.rst

@@ -9,13 +9,11 @@ PyWebIO supports for data visualization with the third-party libraries.
 
 Bokeh
 ^^^^^^^^^^^^^^^^^^^^^^
-`Bokeh <https://github.com/bokeh/bokeh>`_ 是一个支持创建实时交互的数据可视化库。
 
 `Bokeh <https://github.com/bokeh/bokeh>`_ is an interactive visualization library for modern web browsers. It provides elegant, concise construction of versatile graphics, and affords high-performance interactivity over large or streaming datasets.
 
-在 PyWebIO 会话中调用 ``bokeh.io.output_notebook(notebook_type='pywebio')`` 来设置Bokeh输出到PyWebIO:
-
-You can use ``bokeh.io.output_notebook(notebook_type='pywebio')`` in the PyWebIO session to set Bokeh output to PyWebIO::
+You can use ``bokeh.io.output_notebook(notebook_type='pywebio')`` in the PyWebIO session to setup Bokeh environment.
+Then you can use ``bokeh.io.show()`` to output a boken chart::
 
     from bokeh.io import output_notebook
     from bokeh.io import show
@@ -27,26 +25,19 @@ You can use ``bokeh.io.output_notebook(notebook_type='pywebio')`` in the PyWebIO
 
 See related demo on :charts_demo_host:`bokeh demo </?app=bokeh>`
 
-除了创建普通图表,Bokeh还可以通过启动 `Bokeh server <https://docs.bokeh.org/en/latest/docs/user_guide/server.html>`_ 来显示Bokeh app,Bokeh app支持向图表的添加按钮、输入框等交互组件,并向组件注册Python回调,从而创建可以与Python代码交互的图表。
-
 In addition to creating ordinary charts, Bokeh can also build the Bokeh applications by starting the `Bokeh server <https://docs.bokeh.org/en/latest/docs/user_guide/server.html>`_. The purpose of the Bokeh server is to make it easy for Python users to create interactive web applications that can connect front-end UI events to real, running Python code.
 
-在PyWebIO中,你也可以使用 ``bokeh.io.show()`` 来显示一个Bokeh App,代码示例见 `bokeh_app.py <https://github.com/wang0618/PyWebIO/blob/dev/demos/bokeh_app.py>`_。
-
 In PyWebIO, you can also use ``bokeh.io.show()`` to display a Bokeh App. For the example, see `bokeh_app.py <https://github.com/wang0618/PyWebIO/blob/dev/demos/bokeh_app.py>`_.
 
-.. note:: Bokeh App当前仅支持默认的Tornado后端
+.. note:: Bokeh App currently is only available in the default Tornado backend
 
 .. image:: https://cdn.jsdelivr.net/gh/wang0618/pywebio-chart-gallery@master/assets/bokeh.png
 
 pyecharts
 ^^^^^^^^^^^^^^^^^^^^^^
-`pyecharts <https://github.com/pyecharts/pyecharts>`_ 是一个使用Python创建 `Echarts <https://github.com/ecomfe/echarts>`_ 可视化图表的库。
 
 `pyecharts <https://github.com/pyecharts/pyecharts>`_  is a python plotting library which uses `Echarts <https://github.com/ecomfe/echarts>`_ as underlying implementation.
 
-在 PyWebIO 中使用 `put_html() <pywebio.output.put_html>` 可以输出 pyecharts 库创建的图表:
-
 In PyWebIO, you can use the following code to output the pyecharts chart instance::
 
     # `chart` is pyecharts chart instance
@@ -60,12 +51,9 @@ See related demo on :charts_demo_host:`pyecharts demo </?app=pyecharts>`
 
 plotly
 ^^^^^^^^^^^^^^^^^^^^^^
-`plotly.py <https://github.com/plotly/plotly.py>`_ 是一个非常流行的Python数据可视化库,可以生成高质量的交互式图表。
 
 `plotly.py <https://github.com/plotly/plotly.py>`_ is an interactive, open-source, and browser-based graphing library for Python.
 
-PyWebIO 支持输出使用 plotly 库创建的图表。使用方式为在PyWebIO会话中调用:
-
 In PyWebIO, you can use the following code to output the plotly chart instance::
 
     # `fig` is plotly chart instance
@@ -79,14 +67,8 @@ See related demo on :charts_demo_host:`plotly demo </?app=plotly>`
 cutecharts.py
 ^^^^^^^^^^^^^^^^^^^^^^
 
-`cutecharts.py <https://github.com/cutecharts/cutecharts.py>`_ 是一个可以创建具有卡通风格的可视化图表的python库。
-底层使用了 `chart.xkcd <https://github.com/timqian/chart.xkcd>`_ Javascript库。
-
 `cutecharts.py <https://github.com/cutecharts/cutecharts.py>`_ is a hand drawing style charts library for Python which uses `chart.xkcd <https://github.com/timqian/chart.xkcd>`_ as underlying implementation.
 
-
-在 PyWebIO 中使用 `put_html() <pywebio.output.put_html>` 可以输出 cutecharts.py 库创建的图表:
-
 In PyWebIO, you can use the following code to output the cutecharts.py chart instance::
 
     # `chart` is cutecharts chart instance

+ 1 - 4
docs/misc.rst

@@ -43,11 +43,8 @@ Assuming that the backend server is running at the ``localhost:5000`` address, a
         }
     }
 
-以上配置文件将PyWebIO的静态文件托管到 ``/`` 目录下, 并将 ``/tool`` 反向代理到 ``localhost:5000``
 
-The above configuration file hosts the static files of PyWebIO on the ``/tool/`` path, and reverse proxy ``/tool/io`` to ``localhost:5000``
-
-PyWebIO的静态文件的路径可使用命令 ``python3 -c "import pywebio; print(pywebio.STATIC_PATH)"`` 获得,你也可以将静态文件复制到其他目录下
+The above configuration file hosts the static files of PyWebIO on the ``/`` path, and reverse proxy ``/tool`` to ``localhost:5000/tool``
 
 The path of the static file of PyWebIO can be obtained with the command ``python3 -c "import pywebio; print(pywebio.STATIC_PATH)"``, you can also copy the static file to other directories::
 

+ 17 - 17
docs/releases/v1.1.0.rst

@@ -4,29 +4,29 @@ What's new in PyWebIO 1.1
 2021 2/7
 ----------
 
-距离写下PyWebIO的第一行代码过去已经整整一年了🎂 ,2020年发生了太多的事情,但对我来说又多了一份特殊的意义。新的一年继续努力💪 ,将PyWebIO做得越来越好。
+It's been a whole year since the first line of PyWebIO code was written. 🎂 There have been too many things in 2020, but it has a special meaning to me. In 2021, we will continue to work hard to make PyWebIO better and better.
 
 Highlights
 ^^^^^^^^^^^
-* 添加安全性支持: `put_html() <pywebio.output.put_html>`, `put_markdown() <pywebio.output.put_markdown>` 中支持使用 ``sanitize`` 参数开启防 XSS 攻击
-* UI国际化支持
-* 添加SEO支持: 通过任务函数的注释或 `pywebio.platform.seo()` 来设置SEO信息
-* CDN支持,Web框架整合更加方便,仅需引入一条路由即可
-* 应用访问速度提升,不再使用探测请求的方式确定通信协议
+* Security support: `put_html() <pywebio.output.put_html>`, `put_markdown() <pywebio.output.put_markdown>` can use ``sanitize`` parameter to prevent XSS attack.
+* UI internationalization support
+* SEO support: Set SEO info through `pywebio.platform.seo()` or function docstring
+* CDN support, more convenient to web framework integration
+* Application access speed is improved, and no probe requests are used to determine the communication protocol
 
 Backwards-incompatible changes
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-* 移除使用 django 和 flask 框架 `start_server()` 中的 `disable_asyncio` 参数
-* 废弃 `pywebio.session.data()` ,使用 `pywebio.session.local` 作为会话本地状态存储对象
-* 整合到Web框架的应用,访问地址发生变化,参见 :ref:`Web框架整合文档 <integration_web_framework>`
-* `put_scrollable() <pywebio.output.put_scrollable>` 废弃 `max_height` 参数,使用 `height` 替代
+* Remove `disable_asyncio` parameter of `start_server()` in django and flask.
+* Deprecated `pywebio.session.data()`, use `pywebio.session.local` instead
+* Application integrated into the web framework, the access address changes, see :ref:`Web framework integration<integration_web_framework>`
+* Remove `max_height` parameter of `put_scrollable() <pywebio.output.put_scrollable>`, use `height` instead
 
 Detailed changes
 ^^^^^^^^^^^^^^^^^
-* `put_code() <pywebio.output.put_code>` 支持使用 `rows` 参数限制最大显示行数
-* `put_scrollable() <pywebio.output.put_scrollable>` 支持使用 `keep_bottom` 参数设定自动滚动到底部
-* `put_markdown() <pywebio.output.put_markdown>` 支持配置Markdown解析参数
-*  `put_code() <pywebio.output.put_code>`, `put_image() <pywebio.output.put_image>`, `put_link() <pywebio.output.put_link>`, `put_row() <pywebio.output.put_row>`, `put_grid() <pywebio.output.put_grid>` 中的参数添加转义
-* `output()  <pywebio.output.output>` 的 ``reset()``, ``append()``, ``insert()`` 方法接受字符串作为输出内容
-* 修复: `file_upload() <pywebio.input.file_upload>` 的 `max_size` and `max_total_size` 参数解析错误
-* 修复: py3.6自动打开浏览器失败
+* `put_code() <pywebio.output.put_code>` add `rows` parameter to limit the maximum number of displayed lines
+* `put_scrollable() <pywebio.output.put_scrollable>` add `keep_bottom` parameter
+* `put_markdown() <pywebio.output.put_markdown>` add ``options`` to config Markdown parsing options.
+* Add html escaping for parameters of `put_code() <pywebio.output.put_code>`, `put_image() <pywebio.output.put_image>`, `put_link() <pywebio.output.put_link>`, `put_row() <pywebio.output.put_row>`, `put_grid() <pywebio.output.put_grid>`
+* Methods ``reset()``, ``append()``, ``insert()`` of `output()  <pywebio.output.output>`  accept string content
+* Fix: Parsing error in `max_size` and `max_total_size` parameters of `file_upload() <pywebio.input.file_upload>`
+* Fix: Auto open browser failed in python 3.6

+ 43 - 58
docs/spec.rst

@@ -1,45 +1,30 @@
 Server-Client communication protocol
 ========================================
 
-PyWebIO采用服务器-客户端架构,服务端运行任务代码,通过网络与客户端(也就是用户浏览器)交互
-
-PyWebIO uses a server-client architecture, the server executes task code, and interacts with the client (that is, the user browser) through the network. This section is the protocol specification for the communication between PyWebIO server and client.
-
-服务器与客户端有两种通信方式:WebSocket 和 Http 通信。
+PyWebIO uses a server-client architecture, the server executes task code, and interacts with the client (that is, the user browser) through the network. This section introduce the protocol specification for the communication between PyWebIO server and client.
 
 There are two communication methods between server and client: WebSocket and Http.
 
-使用 Tornado或aiohttp 后端时,服务器与客户端通过 WebSocket 通信,使用 Flask或Django 后端时,服务器与客户端通过 Http 通信。
-
 When using Tornado or aiohttp backend, the server and client communicate through WebSocket, when using Flask or Django backend, the server and client communicate through Http.
 
 **WebSocket communication**
 
-服务器与客户端通过WebSocket连接发送json序列化之后的PyWebIO消息
-The server and the client send the PyWebIO message which are json serialized through WebSocket connection
+The server and the client send json-serialized message through WebSocket connection
 
 **Http communication**
 
-* 客户端通过Http GET请求向后端轮询,后端返回json序列化之后的PyWebIO消息列表
-
 * The client polls the backend through Http GET requests, and the backend returns a list of PyWebIO messages serialized in json
 
-* 当用户提交表单或者点击页面按钮后,客户端通过Http POST请求向后端提交数据
-
-* When the user submits the form or clicks the page button, the client submits data to the backend through Http POST request
-
-为方便区分,下文将由服务器向客户端发送的数据称作command,将客户端发向服务器的数据称作event
+* When the user submits the form or clicks the button, the client submits data to the backend through Http POST request
 
 In the following, the data sent by the server to the client is called command, and the data sent by the client to the server is called event.
 
-以下介绍command和event的格式
-
 The following describes the format of command and event
 
 Command
 ------------
 
-command is sent by the server to the client. The basic format of command is::
+Command is sent by the server to the client. The basic format of command is::
 
     {
         "command": ""
@@ -55,9 +40,8 @@ Each fields are described as follows:
 
  * ``spec`` : the data of the command, which is different depending on the command name
 
-需要注意,以下不同命令的参数和 PyWebIO 的对应函数的参数大部分含义一致,但是也有些许不同。
-
-The arguments shown above are merely the same with the parameters of corresponding PyWebIO functions.
+Note that: the arguments shown above are merely the same with the parameters of corresponding PyWebIO functions,
+but there are some differences.
 
 The following describes the ``spec`` fields of different commands:
 
@@ -175,7 +159,7 @@ The ``spec`` fields of ``update_input`` commands:
   * placeholder
   * invalid_feedback
   * valid_feedback
-  * other fields of item's ``spec`` // not support to inline adn label fields
+  * other fields of item's ``spec`` // not support to inline and label fields
 
 
 close_session
@@ -285,88 +269,89 @@ Output control
 
 The ``spec`` fields of ``output_ctl`` commands:
 
-* set_scope: 要创建的scope的名字
+* set_scope: scope name
 
-    * container: 新创建的scope的父scope的css选择器
-    * position: 在父scope中创建此scope的位置. int, position>=0表示在父scope的第position个(从0计数)子元素的前面创建;position<0表示在父scope的倒数第position个(从-1计数)元素之后创建新scope
-    * if_exist: scope已经存在时如何操作:
+    * container: Specify css selector to the parent scope of target scope.
+    * position: int, The index where this scope is created in the parent scope.
+    * if_exist: What to do when the specified scope already exists:
 
-        - null/不指定时表示立即返回不进行任何操作
-        - `'remove'` 表示先移除旧scope再创建新scope
-        - `'clear'` 表示将旧scope的内容清除,不创建新scope
+        - null: Do nothing
+        - `'remove'`: Remove the old scope first and then create a new one
+        - `'clear'`: Just clear the contents of the old scope, but don’t create a new scope
 
-* clear: 需要清空的scope的css选择器
+* clear: css selector of the scope need to clear
 * clear_before
 * clear_after
 * clear_range:[,]
 * scroll_to
-* position: top/middle/bottom 与scroll_to一起出现, 表示滚动页面,让scope位于屏幕可视区域顶部/中部/底部
-* remove: 将给定的scope连同scope处的内容移除
+    * position: top/middle/bottom, Where to place the scope in the visible area of the page
+* remove: Remove the specified scope
 
 run_script
 ^^^^^^^^^^^^^^^
-运行js代码
+run javascript code in user's browser
 
-命令 spec 字段:
+The ``spec`` fields of ``run_script`` commands:
 
-* code: 字符串格式的要运行的js代码
-* args: 传递给代码的局部变量。字典类型,字典键表示变量名,字典值表示变量值(变量值需要可以被json序列化)
+* code: str, code
+* args: dict, Local variables passed to js code
 
 download
 ^^^^^^^^^^^^^^^
-下载文件
+Send file to user
 
-命令 spec 字段:
+The ``spec`` fields of ``download`` commands:
 
-* name: 下载保存为的文件名
-* content: 文件base64编码的内容
+* name: str, File name when downloading
+* content: str, File content in base64 encoding.
 
 Event
 ------------
 
-客户端->服务器,事件格式::
+Event is sent by the client to the server. The basic format of event is::
 
     {
-        event: ""
+        event: event name
         task_id: ""
         data: object/str
     }
 
-``event`` 表示事件名称。 ``data`` 为事件所携带的数据,其根据事件不同内容也会不同,不同事件对应的 ``data`` 字段如下:
+The ``data`` field is the data carried by the event, and its content varies according to the event.
+The ``data`` field of different events is as follows:
 
 input_event
 ^^^^^^^^^^^^^^^
-表单发生更改时触发
+Triggered when the form changes
 
-* event_name: ``'blur'``,表示输入项失去焦点
-* name: 输入项name
-* value: 输入项值
+* event_name: Current available value is ``'blur'``, which indicates that the input item loses focus
+* name: name of input item
+* value: value of input item
 
-注意: checkbox_radio 不产生blur事件
+note: checkbox and radio do not generate blur events
 
 .. _callback_event:
 
 callback
 ^^^^^^^^^^^^^^^
-用户点击显示区的按钮时触发
+Triggered when the user clicks the button in the page
 
-在 ``callback`` 事件中,``task_id`` 为对应的 ``button`` 组件的 ``callback_id`` 字段;
-事件的 ``data`` 为被点击button的 ``value``
+In the ``callback`` event, ``task_id`` is the ``callback_id`` field of the ``button``;
+The ``data`` of the event is the ``value`` of the button that was clicked
 
 from_submit
 ^^^^^^^^^^^^^^^
-用户提交表单时触发
+Triggered when the user submits the form
 
-事件 ``data`` 字段为表单 ``name`` -> 表单值 的字典
+The ``data`` of the event is a dict, whose key is the name of the input item, and whose value is the value of the input item.
 
 from_cancel
 ^^^^^^^^^^^^^^^
-取消输入表单
+Cancel input form
 
-事件 ``data`` 字段为 ``None``
+The ``data`` of the event is ``None``
 
 js_yield
 ^^^^^^^^^^^^^^^
-js代码提交数据
+submit data from js
 
-事件 ``data`` 字段为相应的数据
+The ``data`` of the event is the data need to submit

+ 14 - 28
pywebio/input.py

@@ -1,18 +1,12 @@
 """
 
-本模块提供了一系列函数来从浏览器接收用户不同的形式的输入
+This module provides many functions to get all kinds of input of user from the browser
 
-This module provides a series of functions to get all kinds of input of user from the browser
-
-输入函数的使用有两种方式,一种是单独调用输入函数的单项输入:
-
-There are two ways to use the input function, one is to call the input function alone to get a single input::
+There are two ways to use the input functions, one is to call the input function alone to get a single input::
 
     name = input("What's your name")
     print("Your name is %s" % name)
 
-另一种是使用 `input_group` 的输入组:
-
 The other is to use `input_group` to get multiple inputs at once::
 
     info = input_group("User info",[
@@ -21,17 +15,13 @@ The other is to use `input_group` to get multiple inputs at once::
     ])
     print(info['name'], info['age'])
 
-输入组中需要在每一项输入函数中提供 ``name`` 参数来用于在结果中标识不同输入项.
-
 When use `input_group`, you needs to provide the ``name`` parameter in each input function to identify the input items in the result.
 
 .. note::
-   PyWebIO 根据是否在输入函数中传入 ``name`` 参数来判断输入函数是在 `input_group` 中还是被单独调用。
-   所以当你想要单独调用一个输入函数时,请不要设置 ``name`` 参数;而在 `input_group` 中调用输入函数时,**务必提供** ``name`` 参数
 
-   PyWebIO determine whether the input function is in `input_group` or is called alone according to whether the ``name`` parameter is passed. So when calling an input function alone, **do not** set the ``name`` parameter; when calling the input function in input_group, you **must** provide the ``name`` parameter.
+   PyWebIO determines whether the input function is in `input_group` or is called alone according to whether the ``name`` parameter is passed. So when calling an input function alone, **do not** set the ``name`` parameter; when calling the input function in `input_group`, you **must** provide the ``name`` parameter.
 
-输入默认可以忽略,如果需要用户必须提供输入值,则需要在输入函数中传入 ``required=True`` (部分输入函数不支持 ``required`` 参数)
+By default, the user can submit an input of empty value. If the user must provide a non-empty input value, you need to pass ``required=True`` to the input function (some input functions do not support the ``required`` parameter)
 
 Functions list
 -----------------
@@ -191,7 +181,7 @@ def input(label='', type=TEXT, *, validate=None, name=None, value=None, action=N
 
     item_spec, valid_func = _parse_args(locals(), excludes=('action',))
 
-    # 参数检查
+    # check input type
     allowed_type = {TEXT, NUMBER, FLOAT, PASSWORD, URL, DATE, TIME}
     assert type in allowed_type, 'Input type not allowed.'
 
@@ -221,7 +211,7 @@ def input(label='', type=TEXT, *, validate=None, name=None, value=None, action=N
         callback_id = output_register_callback(lambda _: callback(_set_value))
         item_spec['action'] = dict(label=label, callback_id=callback_id)
 
-    def preprocess_func(d):  # 将用户提交的原始数据进行转换
+    def preprocess_func(d):  # Convert the original data submitted by the user
         if value_setter is not None and value_setter.label == d:
             return value_setter.value
 
@@ -242,7 +232,7 @@ def textarea(label='', *, rows=6, code=None, maxlength=None, minlength=None, val
     :param int rows: The number of visible text lines for the input area. Scroll bar will be used when content exceeds.
     :param int maxlength: The maximum number of characters (UTF-16 code units) that the user can enter. If this value isn't specified, the user can enter an unlimited number of characters.
     :param int minlength: The minimum number of characters (UTF-16 code units) required that the user should enter.
-    :param dict code: Make the text input field have a code editor style by providing the `Codemirror <https://codemirror.net/>`_ options:
+    :param dict code: Enable a code style editor by providing the `Codemirror <https://codemirror.net/>`_ options:
 
         .. exportable-codeblock::
             :name: textarea-code
@@ -254,6 +244,8 @@ def textarea(label='', *, rows=6, code=None, maxlength=None, minlength=None, val
             })
             put_code(res, language='python')  # ..demo-only
 
+        You can simply use ``code={}`` or ``code=True`` to enable code style editor.
+
         Some commonly used Codemirror options are listed :ref:`here <codemirror_options>`.
 
     :param - label, validate, name, value, placeholder, required, readonly, help_text, other_html_attrs: Those arguments have the same meaning as for `input()`
@@ -396,11 +388,11 @@ def _parse_action_buttons(buttons):
     :param actions: action list
         action available format:
 
-        * dict: ``{label:选项标签, value:选项值, [type: 按钮类型], [disabled:是否禁止选择]}``
+        * dict: ``{label:button label, value:button value, [type: button type], [disabled:is disabled?]}``
         * tuple or list: ``(label, value, [type], [disabled])``
-        * 单值: 此时label和value使用相同的值
+        * single value: label and value of button share the same value
 
-    :return: 规格化后的 buttons
+    :return: dict format
     """
     act_res = []
     for act in buttons:
@@ -425,8 +417,6 @@ def _parse_action_buttons(buttons):
 def actions(label='', buttons=None, name=None, help_text=None):
     r"""Actions selection
 
-    在表单上显示为一组按钮,用户点击按钮后依据按钮类型的不同有不同的表现。
-    
     It is displayed as a group of buttons on the page. After the user clicks the button of it, it will behave differently depending on the type of the button.
 
     :param list buttons: list of buttons. The available formats of the list items are:
@@ -456,8 +446,6 @@ def actions(label='', buttons=None, name=None, help_text=None):
     :param - label, name, help_text: Those arguments have the same meaning as for `input()`
     :return: If the user clicks the ``type=submit`` button to submit the form, return the value of the button clicked by the user. If the user clicks the ``type=cancel`` button or submits the form by other means, ``None`` is returned.
 
-    当 ``actions()`` 作为 `input_group()` 中的最后一个输入项、并且含有 ``type='submit'`` 的按钮时,`input_group()` 表单默认的提交按钮会被当前 ``actions()`` 替换
-
     When ``actions()`` is used as the last input item in `input_group()` and contains a button with ``type='submit'``, the default submit button of the `input_group()` form will be replace with the current ``actions()``
 
     **usage scenes of ``actions()``**
@@ -473,10 +461,9 @@ def actions(label='', buttons=None, name=None, help_text=None):
         confirm = actions('Confirm to delete file?', ['confirm', 'cancel'], help_text='Unrecoverable after file deletion')
         if confirm=='confirm':  # ..doc-only
             ...  # ..doc-only
-        put_markdown('点击了`%s`按钮' % confirm)  # ..demo-only
+        put_markdown('You clicked the `%s` button' % confirm)  # ..demo-only
 
-    相比于其他输入项,使用 `actions()` 用户只需要点击一次就可完成提交。
-    Compared with other input items, when using `actions()`, the user just needs to click once to complete the submission.
+    Compared with other input items, when using `actions()`, the user only needs to click once to complete the submission.
 
     * Replace the default submit button:
 
@@ -598,7 +585,6 @@ def input_group(label='', inputs=None, validate=None, cancelable=False):
     :param callable validate: validation function for the group. If provided, the validation function will be called when the user submits the form.
 
         Function signature: ``callback(data) -> (name, error_msg)``.
-        ``validate`` 接收整个表单的值为参数,当校验表单值有效时,返回 ``None`` ,当某项输入值无效时,返回出错输入项的 ``name`` 值和错误提示. 比如:
         ``validate`` receives the value of the entire group as a parameter. When the form value is valid, it returns ``None``. When an input item's value is invalid, it returns the ``name`` value of the item and an error message. For example:
 
     .. exportable-codeblock::

+ 21 - 16
pywebio/output.py

@@ -1,5 +1,5 @@
 r"""
-This module provides a series of functions to output all kinds of content to the user's browser, and supply flexible output control.
+This module provides many functions to output all kinds of content to the user's browser, and supply flexible output control.
 
 Functions list
 ---------------
@@ -339,7 +339,7 @@ def put_code(content, language='', rows=None, scope=Scope.Current, position=Outp
 
     :param str content: code string
     :param str language: language of code
-    :param int rows: 代码块最多可显示的文本行数,默认不限制。内容超出时会使用滚动条。
+    :param int rows: The max lines of code can be displayed, no limit by default. The scroll bar will be displayed when the content exceeds.
     :param int scope, position: Those arguments have the same meaning as for `put_text()`
     """
     if not isinstance(content, str):
@@ -814,9 +814,9 @@ def set_processbar(name, value, label=None):
 def put_loading(shape='border', color='dark', scope=Scope.Current, position=OutputPosition.BOTTOM) -> Output:
     """Output loading prompt
 
-    :param str shape: The shape of loading prompt. The available values are : `'border'` (default)、 `'grow'`
-    :param str color: 加载提示的颜色, 可选值: `'primary'` 、 `'secondary'` 、 `'success'` 、 `'danger'` 、
-     `'warning'` 、`'info'`  、`'light'`  、 `'dark'` (默认)
+    :param str shape: The shape of loading prompt. The available values are: `'border'` (default)、 `'grow'`
+    :param str color: The color of loading prompt. The available values are: `'primary'` 、 `'secondary'` 、 `'success'` 、 `'danger'` 、
+     `'warning'` 、`'info'`  、`'light'`  、 `'dark'` (default)
     :param int scope, position: Those arguments have the same meaning as for `put_text()`
 
     Example:
@@ -893,17 +893,17 @@ def put_scrollable(content, height=400, keep_bottom=False, horizon_scroll=False,
 
     :type content: list/str/put_xxx()
     :param content: The content can be a string, the ``put_xxx()`` calls , or a list of them.
-    :param int/tuple height: 区域的高度(像素),内容超出此高度则使用滚动条。
-       可以传入 ``(min_height, max_height)`` 来表示高度的范围,比如 ``(100, 200)`` 表示区域高度最小100像素、最高200像素。
+    :param int/tuple height: The height of the area (in pixels).
+       ``height`` parameter also accepts ``(min_height, max_height)`` to indicate the range of height, for example, ``(100, 200)`` means that the area has a minimum height of 100 pixels and a maximum of 200 pixels.
     :param bool horizon_scroll: Whether to use the horizontal scroll bar
     :param bool border: Whether to show border
     :param int scope, position: Those arguments have the same meaning as for `put_text()`
 
-    使用示例:
+    Example:
 
     .. exportable-codeblock::
         :name: put_scrollable
-        :summary: `put_scrollable()` 使用示例
+        :summary: `put_scrollable()` usage
 
         import time
 
@@ -915,8 +915,8 @@ def put_scrollable(content, height=400, keep_bottom=False, horizon_scroll=False,
             time.sleep(0.5)
 
     .. versionchanged:: 1.1
-       添加 ``height`` 参数,移除 ``max_height`` 参数
-       添加 ``keep_bottom`` 参数
+       add ``height`` parameter,remove ``max_height`` parameter
+       add ``keep_bottom`` parameter
     """
     if not isinstance(content, (list, tuple, OutputList)):
         content = [content]
@@ -1116,7 +1116,7 @@ def put_grid(content, cell_width='auto', cell_height='auto', cell_widths=None, c
 
     .. exportable-codeblock::
         :name: put_grid
-        :summary: 使用`put_grid()`进行网格布局
+        :summary: `put_grid()` usage
 
         put_grid([
             [put_text('A'), put_text('B'), put_text('C')],
@@ -1143,6 +1143,7 @@ def put_grid(content, cell_width='auto', cell_height='auto', cell_widths=None, c
                 content[x][y] = put_html('<div></div>')
 
     # 为长度不足的行添加空元素
+    # Add empty elements for rows with insufficient length
     m = max(lens)
     for idx, i in enumerate(content):
         i.extend(put_html('<div></div>') for _ in range(m - lens[idx]))
@@ -1178,8 +1179,9 @@ def output(*contents):
 
      ``output()`` can be passed in anywhere that ``put_xxx()`` can passed in. A handler it returned by ``output()``, and after being output, the content can also be modified by the handler (See code example below).
 
-    :param contents: 要输出的初始内容. 元素为 ``put_xxx()`` 调用,其他类型会被转换成 ``put_text(content)``
-    :return: OutputHandler 实例, 实例支持的方法如下:
+    :param contents: The initial contents to be output.
+       The item is ``put_xxx()`` call, and any other type will be coverted to ``put_text(content)``.
+    :return: An OutputHandler instance, the methods of the instance are as follows:
 
     * ``reset(*contents)`` : Reset original contents to ``contents``
     * ``append(*contents)`` : Append ``contents`` to original contents
@@ -1188,7 +1190,7 @@ def output(*contents):
        | when idx>=0, the output content is inserted before the element of the ``idx`` index.
        | when idx<0, the output content is inserted after the element of the ``idx`` index.
 
-    其中,参数 ``contents`` 同 ``output()`` 。
+    Among them, the parameter ``contents`` is the same as ``output()``.
 
     :Example:
 
@@ -1240,7 +1242,10 @@ def output(*contents):
 
         @safely_destruct_output_when_exp('outputs')
         def insert(self, idx, *outputs):
-            """idx可为负,"""
+            """
+            idx可为负
+            idx can be negative
+            """
             direction = 1 if idx >= 0 else -1
             for acc, o in enumerate(outputs):
                 if not isinstance(o, Output):

+ 11 - 10
pywebio/platform/aiohttp.py

@@ -38,12 +38,11 @@ def _is_same_site(origin, host):
 
 
 def _webio_handler(applications, cdn, websocket_settings, check_origin_func=_is_same_site):
-    """获取用于Tornado进行整合的RequestHandle类
-
-    :param dict applications: 任务名->任务函数 的映射
-    :param bool/str cdn: 是否从CDN加载前端静态资源. 支持传入URL来自定义CDN地址。
+    """
+    :param dict applications: dict of `name -> task function`
+    :param bool/str cdn: Whether to load front-end static resources from CDN
     :param callable check_origin_func: check_origin_func(origin, handler) -> bool
-    :return: Tornado RequestHandle类
+    :return: aiohttp Request Handler
     """
     ioloop = asyncio.get_event_loop()
 
@@ -117,8 +116,8 @@ def webio_handler(applications, cdn=True, allowed_origins=None, check_origin=Non
     The handler communicates with the browser by WebSocket protocol.
 
     :param list/dict/callable applications: PyWebIO application.
-    :param bool/str cdn: 是否从CDN加载前端静态资源,默认为 ``True`` 。设置成 ``False`` 时会从PyWebIO应用部署URL的同级目录下加载静态资源。
-       支持传入自定义的URL来指定静态资源的部署地址
+    :param bool/str cdn: Whether to load front-end static resources from CDN, the default is ``True``.
+       Can also use a string to directly set the url of PyWebIO static resources.
     :param list allowed_origins: Allowed request source list.
     :param callable check_origin: The validation function for request source.
     :param dict websocket_settings: The  parameters passed to the constructor of ``aiohttp.web.WebSocketResponse``.
@@ -147,9 +146,10 @@ def webio_handler(applications, cdn=True, allowed_origins=None, check_origin=Non
 
 def static_routes(prefix='/'):
     """获取用于提供PyWebIO静态文件的aiohttp路由列表
+    Get the aiohttp routes list for PyWebIO static files hosting.
 
-    :param str prefix: 静态文件托管的URL路径,默认为根路径 ``/``
-    :return: aiohttp路由列表
+    :param str prefix: The URL path of static file hosting, the default is the root path ``/``
+    :return: aiohttp routes list
     """
 
     async def index(request):
@@ -175,7 +175,8 @@ def start_server(applications, port=0, host='', debug=False,
        When set to ``0``, the server will automatically select a available port.
     :param str host: The host the server listens on. ``host`` may be either an IP address or hostname. If it’s a hostname, the server will listen on all IP addresses associated with the name. ``host`` may be an empty string or None to listen on all available interfaces.
     :param bool debug: aiohttp debug mode.
-    :param bool/str cdn: 是否从CDN加载前端静态资源,默认为 ``True`` 。支持传入自定义的URL来指定静态资源的部署地址
+    :param bool/str cdn: Whether to load front-end static resources from CDN, the default is ``True``.
+       Can also use a string to directly set the url of PyWebIO static resources.
     :param list allowed_origins: Allowed request source list.
        The argument has the same meaning as for :func:`pywebio.platform.tornado.start_server`
     :param callable check_origin: The validation function for request source.

+ 4 - 3
pywebio/platform/django.py

@@ -80,8 +80,8 @@ def webio_view(applications, cdn=True,
     The view communicates with the browser by HTTP protocol.
 
     :param list/dict/callable applications: PyWebIO application.
-    :param bool/str cdn: 是否从CDN加载前端静态资源,默认为 ``True`` 。设置成 ``False`` 时会从PyWebIO应用部署URL的同级目录下加载静态资源。
-       支持传入自定义的URL来指定静态资源的部署地址
+    :param bool/str cdn: Whether to load front-end static resources from CDN, the default is ``True``.
+       Can also use a string to directly set the url of PyWebIO static resources.
     :param int session_expire_seconds: Session expiration time.
     :param int session_cleanup_interval: Session cleanup interval, in seconds.
     :param list allowed_origins: Allowed request source list.
@@ -120,7 +120,8 @@ def start_server(applications, port=8080, host='localhost', cdn=True,
     :param int port: The port the server listens on.
        When set to ``0``, the server will automatically select a available port.
     :param str host: The host the server listens on. ``host`` may be either an IP address or hostname. If it’s a hostname, the server will listen on all IP addresses associated with the name. ``host`` may be an empty string or None to listen on all available interfaces.
-    :param bool/str cdn: 是否从CDN加载前端静态资源,默认为 ``True`` 。支持传入自定义的URL来指定静态资源的部署地址
+    :param bool/str cdn: Whether to load front-end static resources from CDN, the default is ``True``.
+       Can also use a string to directly set the url of PyWebIO static resources.
     :param list allowed_origins: Allowed request source list.
        The argument has the same meaning as for :func:`pywebio.platform.tornado.start_server`
     :param callable check_origin: The validation function for request source.

+ 4 - 6
pywebio/platform/flask.py

@@ -1,8 +1,5 @@
 """
 Flask backend
-
-.. note::
-    在 CoroutineBasedSession 会话中,若在协程任务函数内调用 asyncio 中的协程函数,需要使用 asyncio_coroutine
 """
 import json
 import logging
@@ -86,8 +83,8 @@ def webio_view(applications, cdn=True,
     The view communicates with the browser by HTTP protocol.
 
     :param list/dict/callable applications: PyWebIO application.
-    :param bool/str cdn: 是否从CDN加载前端静态资源,默认为 ``True`` 。设置成 ``False`` 时会从PyWebIO应用部署URL的同级目录下加载静态资源。
-       支持传入自定义的URL来指定静态资源的部署地址
+    :param bool/str cdn: Whether to load front-end static resources from CDN, the default is ``True``.
+       Can also use a string to directly set the url of PyWebIO static resources.
     :param int session_expire_seconds: Session expiration time.
     :param int session_cleanup_interval: Session cleanup interval, in seconds.
     :param list allowed_origins: Allowed request source list.
@@ -123,7 +120,8 @@ def start_server(applications, port=8080, host='localhost', cdn=True,
     :param int port: The port the server listens on.
        When set to ``0``, the server will automatically select a available port.
     :param str host: The host the server listens on. ``host`` may be either an IP address or hostname. If it’s a hostname, the server will listen on all IP addresses associated with the name. ``host`` may be an empty string or None to listen on all available interfaces.
-    :param bool/str cdn: 是否从CDN加载前端静态资源,默认为 ``True`` 。支持传入自定义的URL来指定静态资源的部署地址
+    :param bool/str cdn: Whether to load front-end static resources from CDN, the default is ``True``.
+       Can also use a string to directly set the url of PyWebIO static resources.
     :param list allowed_origins: Allowed request source list.
        The argument has the same meaning as for :func:`pywebio.platform.tornado.start_server`
     :param callable check_origin: The validation function for request source.

+ 44 - 50
pywebio/platform/httpbased.py

@@ -2,15 +2,9 @@
 本模块提供基于Http轮训的后端通用类和函数
 
 .. attention::
-    PyWebIO 的会话状态保存在进程内,所以不支持多进程部署的后端服务
-        比如使用 ``uWSGI`` 部署后端服务,并使用 ``--processes n`` 选项设置了多进程;
-        或者使用 ``nginx`` 等反向代理将流量负载到多个后端副本上。
-
-    A note on run backend server with uWSGI:
-
-    If you start uWSGI without threads, the Python GIL will not be enabled,
-    so threads generated by your application will never run.
-    `uWSGI doc <https://uwsgi-docs.readthedocs.io/en/latest/WSGIquickstart.html#a-note-on-python-threads>`_
+    PyWebIO 的会话状态保存在进程内,基于HTTP的会话不支持多进程部署的后端服务
+    比如使用 ``uWSGI`` 部署后端服务,并使用 ``--processes n`` 选项设置了多进程;
+    或者使用 ``nginx`` 等反向代理将流量负载到多个后端副本上。
 
 """
 import asyncio
@@ -27,52 +21,64 @@ from ..utils import random_str, LRUDict, isgeneratorfunction, iscoroutinefunctio
 
 
 class HttpContext:
-    """一次Http请求的上下文, 不同的后端框架需要根据框架提供的方法实现本类的方法"""
+    """一次Http请求的上下文, 不同的后端框架需要根据框架提供的方法实现本类的方法
+
+    The context of an Http request"""
 
     backend_name = ''  # 当前使用的Web框架名
 
     def request_obj(self):
-        """返回当前请求对象"""
+        """返回当前请求对象
+        Return the current request object"""
         pass
 
     def request_method(self):
-        """返回当前请求的方法,大写"""
+        """返回当前请求的方法,大写
+        Return the HTTP method of the current request, uppercase"""
         pass
 
     def request_headers(self):
-        """返回当前请求的header字典"""
+        """返回当前请求的header字典
+        Return the header dictionary of the current request"""
         pass
 
     def request_url_parameter(self, name, default=None):
-        """返回当前请求的URL参数"""
+        """返回当前请求的URL参数
+        Returns the value of the given URL parameter of the current request"""
         pass
 
     def request_json(self) -> dict:
-        """返回当前请求的json反序列化后的内容,若请求数据不为json格式,返回None"""
+        """返回当前请求的json反序列化后的内容,若请求数据不为json格式,返回None
+        Return the data (json deserialization) of the currently requested, if the data is not in json format, return None"""
         pass
 
     def set_header(self, name, value):
-        """为当前响应设置header"""
+        """为当前响应设置header
+        Set a header for the current response"""
         pass
 
     def set_status(self, status):
-        """为当前响应设置http status"""
+        """为当前响应设置http status
+        Set http status for the current response"""
         pass
 
     def set_content(self, content, json_type=False):
         """设置响应的内容。方法应该仅被调用一次
+        Set the content of the response. This method should only be called once
 
         :param str/bytes/json-able content:
-        :param bool json_type: content是否要序列化成json格式,并将 content-type 设置为application/json
+        :param bool json_type: Whether to serialize content into json str and set content-type to application/json
         """
         pass
 
     def get_response(self):
-        """获取当前的响应对象,用于在视图函数中返回"""
+        """获取当前的响应对象,用于在视图函数中返回
+        Get the current response object"""
         pass
 
     def get_client_ip(self):
-        """获取用户的ip"""
+        """获取用户的ip
+        Get the user's ip"""
         pass
 
 
@@ -85,21 +91,22 @@ class HttpHandler:
     """基于HTTP的后端Handler实现
 
     .. note::
-        对 HttpHandler._webio_sessions 的访问不需要加锁, See:
-            https://stackoverflow.com/questions/1312331/using-a-global-dictionary-with-threads-in-python
+        Don't need a lock when access HttpHandler._webio_sessions, See:
+        https://stackoverflow.com/questions/1312331/using-a-global-dictionary-with-threads-in-python
 
     """
     # type: Dict[str, Session]
     _webio_sessions = {}  # WebIOSessionID -> WebIOSession()
-    _webio_expire = LRUDict()  # WebIOSessionID -> last active timestamp。按照最后活跃时间递增排列
+    _webio_expire = LRUDict()  # WebIOSessionID -> last active timestamp. In increasing order of last active time
     _webio_expire_lock = threading.Lock()
 
-    _last_check_session_expire_ts = 0  # 上次检查session有效期的时间戳
+    _last_check_session_expire_ts = 0  # Timestamp of the last check session validation
 
-    WAIT_MS_ON_POST = 100  # 在处理完POST请求时,等待WAIT_MS_ON_POST毫秒再读取返回数据。Task的command可以立即返回
+    # After processing the POST request, wait for WAIT_MS_ON_POST milliseconds before generate response
+    WAIT_MS_ON_POST = 100
 
-    DEFAULT_SESSION_EXPIRE_SECONDS = 60  # 默认会话过期时间
-    DEFAULT_SESSIONS_CLEANUP_INTERVAL = 20  # 默认清理过期会话间隔(秒)
+    DEFAULT_SESSION_EXPIRE_SECONDS = 60  # Default session expiration time
+    DEFAULT_SESSIONS_CLEANUP_INTERVAL = 20  # Default interval for clearing expired sessions (in seconds)
 
     @classmethod
     def _remove_expired_sessions(cls, session_expire_seconds):
@@ -109,12 +116,12 @@ class HttpHandler:
             sid, active_ts = cls._webio_expire.popitem(last=False)  # 弹出最不活跃的session info
 
             if time.time() - active_ts < session_expire_seconds:
-                # 当前session未过期
+                # this session is not expired
                 cls._webio_expire[sid] = active_ts
                 cls._webio_expire.move_to_end(sid, last=False)
                 break
 
-            # 清理session
+            # clean this session
             logger.debug("session %s expired" % sid)
             session = cls._webio_sessions.get(sid)
             if session:
@@ -127,7 +134,7 @@ class HttpHandler:
         cls._webio_expire.pop(sid, None)
 
     def _process_cors(self, context: HttpContext):
-        """处理跨域请求:检查请求来源并根据可访问性设置headers"""
+        """Handling cross-domain requests: check the source of the request and set headers"""
         origin = context.request_headers().get('Origin', '')
         if self.check_origin(origin):
             context.set_header('Access-Control-Allow-Origin', origin)
@@ -149,7 +156,7 @@ class HttpHandler:
             cls._remove_expired_sessions(self.session_expire_seconds)
 
     def handle_request(self, context: HttpContext):
-        """处理请求"""
+        """called when every http request"""
         cls = type(self)
 
         if _event_loop:
@@ -233,23 +240,10 @@ class HttpHandler:
                  session_expire_seconds=None,
                  session_cleanup_interval=None,
                  allowed_origins=None, check_origin=None):
-        """获取用于与后端实现进行整合的view函数,基于http请求与前端进行通讯
-
-        :param list/dict/callable applications: PyWebIO应用. 可以是任务函数或者任务函数的字典或列表。
-        :param bool/str cdn: 是否从CDN加载前端静态资源. 支持传入URL来自定义CDN地址。
-        :param int session_expire_seconds: 会话不活跃过期时间。
-        :param int session_cleanup_interval: 会话清理间隔。
-        :param list allowed_origins: 除当前域名外,服务器还允许的请求的来源列表。
-            来源包含协议和域名和端口部分,允许使用 Unix shell 风格的匹配模式:
-
-            - ``*`` 为通配符
-            - ``?`` 匹配单个字符
-            - ``[seq]`` 匹配seq内的字符
-            - ``[!seq]`` 匹配不在seq内的字符
-
-            比如 ``https://*.example.com`` 、 ``*://*.example.com``
-        :param callable check_origin: 请求来源检查函数。接收请求来源(包含协议和域名和端口部分)字符串,
-            返回 ``True/False`` 。若设置了 ``check_origin`` , ``allowed_origins`` 参数将被忽略
+        """Get the view function for running PyWebIO applications in Web framework.
+        The view communicates with the client by HTTP protocol.
+
+        The arguments of the constructor have the same meaning as for :func:`pywebio.platform.flask.start_server()`
         """
         check_webio_js()
 
@@ -272,9 +266,9 @@ class HttpHandler:
 
 
 def run_event_loop(debug=False):
-    """运行事件循环
+    """run asyncio event loop
 
-    基于协程的会话在启动基于线程的http服务器之前需要启动一个单独的线程来运行事件循环。
+    See also: :ref:`Integration coroutine-based session with Web framework <coroutine_web_integration>`
 
     :param debug: Set the debug mode of the event loop.
        See also: https://docs.python.org/3/library/asyncio-dev.html#asyncio-debug-mode

+ 28 - 13
pywebio/platform/tornado.py

@@ -26,7 +26,10 @@ _ioloop = None
 
 
 def ioloop() -> tornado.ioloop.IOLoop:
-    """获得运行Tornado server的IOLoop"""
+    """获得运行Tornado server的IOLoop
+
+    本方法当前仅在显示boken app时使用
+    This method is currently only used when displaying boken app"""
     global _ioloop
     return _ioloop
 
@@ -53,12 +56,11 @@ def _is_same_site(origin, handler: WebSocketHandler):
 
 
 def _webio_handler(applications, cdn, check_origin_func=_is_same_site):
-    """获取用于Tornado进行整合的RequestHandle类
-
-    :param dict applications: 任务名->任务函数 的字典
-    :param bool/str cdn:
+    """
+    :param dict applications: dict of `name -> task function`
+    :param bool/str cdn: Whether to load front-end static resources from CDN
     :param callable check_origin_func: check_origin_func(origin, handler) -> bool
-    :return: Tornado RequestHandler
+    :return: Tornado RequestHandler class
     """
     check_webio_js()
 
@@ -93,7 +95,9 @@ def _webio_handler(applications, cdn, check_origin_func=_is_same_site):
             logger.debug("WebSocket opened")
             # self.set_nodelay(True)
 
-            self._close_from_session_tag = False  # 由session主动关闭连接
+            # 由session主动关闭连接
+            # connection is closed from session
+            self._close_from_session_tag = False
 
             session_info = get_session_info_from_headers(self.request.headers)
             session_info['user_ip'] = self.request.remote_ip
@@ -122,7 +126,9 @@ def _webio_handler(applications, cdn, check_origin_func=_is_same_site):
             self.close()
 
         def on_close(self):
-            if not self._close_from_session_tag:  # 只有在由客户端主动断开连接时,才调用 session.close()
+            # Session.close() is called only when connection is closed from the client.
+            # 只有在由客户端主动断开连接时,才调用 session.close()
+            if not self._close_from_session_tag:
                 self.session.close()
             logger.debug("WebSocket closed")
 
@@ -179,7 +185,7 @@ def start_server(applications, port=0, host='',
                  websocket_ping_interval=None,
                  websocket_ping_timeout=None,
                  **tornado_app_settings):
-    """启动一个 Tornado server 将PyWebIO应用作为Web服务提供。
+    """Start a Tornado server to provide the PyWebIO application as a web service.
 
     Tornado is the default backend server for PyWebIO applications,
     and ``start_server`` can be imported directly using ``from pywebio import start_server``.
@@ -201,7 +207,8 @@ def start_server(applications, port=0, host='',
     :param str host: The host the server listens on. ``host`` may be either an IP address or hostname. If it’s a hostname, the server will listen on all IP addresses associated with the name. ``host`` may be an empty string or None to listen on all available interfaces.
     :param bool debug: Tornado Server's debug mode. If enabled, the server will automatically reload for code changes.
        See `tornado doc <https://www.tornadoweb.org/en/stable/guide/running.html#debug-mode>`_ for more detail.
-    :param bool/str cdn: 是否从CDN加载前端静态资源,默认为 ``True`` 。支持传入自定义的URL来指定静态资源的部署地址
+    :param bool/str cdn: Whether to load front-end static resources from CDN, the default is ``True``.
+       Can also use a string to directly set the url of PyWebIO static resources.
     :param list allowed_origins: The allowed request source list. (The current server host is always allowed)
        The source contains the protocol, domain name, and port part.
        Can use Unix shell-style wildcards:
@@ -252,8 +259,10 @@ def start_server(applications, port=0, host='',
 
 def start_server_in_current_thread_session():
     """启动 script mode 的server,监听可用端口,并自动打开浏览器
+    Start the server for script mode, and automatically open the browser when the server port is available.
 
     PYWEBIO_SCRIPT_MODE_PORT环境变量可以设置监听端口,并关闭自动打开浏览器,用于测试
+    The PYWEBIO_SCRIPT_MODE_PORT environment variable can set the listening port, just used in testing.
     """
     websocket_conn_opened = threading.Event()
     thread = threading.current_thread()
@@ -286,8 +295,12 @@ def start_server_in_current_thread_session():
                 logger.debug('ScriptModeSession closed')
 
     async def wait_to_stop_loop(server):
-        """当只剩当前线程和Daemon线程运行时,关闭Server"""
-        alive_none_daemonic_thread_cnt = None  # 包括当前线程在内的非Daemon线程数
+        """当只剩当前线程和Daemon线程运行时,关闭Server
+        When only the current thread and Daemon thread are running, close the Server"""
+
+        # 包括当前线程在内的非Daemon线程数
+        # The number of non-Daemon threads(including the current thread)
+        alive_none_daemonic_thread_cnt = None
         while alive_none_daemonic_thread_cnt != 1:
             alive_none_daemonic_thread_cnt = sum(
                 1 for t in threading.enumerate() if t.is_alive() and not t.isDaemon()
@@ -295,6 +308,7 @@ def start_server_in_current_thread_session():
             await asyncio.sleep(1)
 
         # 关闭Websocket连接
+        # Close the Websocket connection
         if SingleSessionWSHandler.instance:
             SingleSessionWSHandler.instance.close()
 
@@ -303,7 +317,8 @@ def start_server_in_current_thread_session():
         tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task() and not t.done()]
         for task in tasks: task.cancel()
 
-        # 必须需要 await asyncio.sleep ,否则 t.cancel() 调用无法调度生效
+        # 必须需要 await asyncio.sleep ,否则上方 task.cancel() 调用无法调度生效
+        # This line must be required, otherwise the `task.cancel()` call cannot be scheduled to take effect
         await asyncio.sleep(0)
 
         tornado.ioloop.IOLoop.current().stop()

+ 10 - 8
pywebio/platform/utils.py

@@ -162,14 +162,15 @@ def make_applications(applications):
 
 
 def seo(title, description=None, app=None):
-    '''设置PyWebIO应用的SEO信息(在被搜索引擎索引时提供的网页信息)
+    '''Set the SEO information of the PyWebIO application (web page information provided when indexed by search engines)
 
-    :param str title: 应用标题
-    :param str description: 应用简介
-    :param callable app: PyWebIO任务函数
+    :param str title: Application title
+    :param str description: Application description
+    :param callable app: PyWebIO task function
 
-    可以通过装饰器或直接调用的方式使用 ``seo()`` 。
-    除了使用 ``seo()`` 函数,PyWebIO默认会将任务函数的函数注释作为SEO信息::
+    If not ``seo()`` is not used, the `docstring <https://www.python.org/dev/peps/pep-0257/>`_ of the task function will be regarded as SEO information by default.
+
+    ``seo()`` can be used in 2 ways: direct call and decorator::
 
         @seo("title", "description")
         def foo():
@@ -179,9 +180,10 @@ def seo(title, description=None, app=None):
             pass
 
         def hello():
-            """应用标题
+            """Application title
 
-            应用简介... (应用简介和标题之间使用一个空行分隔)
+            Application description...
+            (A empty line is used to separate the description and title)
             """
 
         start_server([

+ 29 - 66
pywebio/session/__init__.py

@@ -11,15 +11,17 @@ r"""
 
 .. data:: local
 
-    当前会话的数据对象(session-local object)。
+    The session-local object for current session.
 
-    ``local`` 是一个可以通过属性访问的字典,访问不存在的属性时会返回 ``None`` 而不是抛出异常。
-    ``local`` 不支持字典的方法,支持使用 ``in`` 操作符来判断键是否存在,可以使用 ``local._dict`` 获取底层的字典表示。
+    ``local`` is a dictionary that can be accessed through attributes. When accessing a property that does not exist in the data object, it returns ``None`` instead of throwing an exception.
+    The method of dictionary is not supported in ``local``. It supports the ``in`` operator to determine whether the key exists. You can use ``local._dict`` to get the underlying dictionary data.
 
-    :使用场景:
 
-    当需要在多个函数中保存一些会话独立的数据时,使用session-local对象保存状态会比通过函数参数传递更方便。
-    以下是一个会话独立的计数器的实现示例::
+    :Usage Scenes:
+
+    When you need to share some session-independent data with multiple functions, it is more convenient to use session-local objects to save state than to use function parameters.
+
+    Here is a example of a session independent counter implementation::
 
         from pywebio.session import local
         def add():
@@ -28,11 +30,11 @@ r"""
         def show():
             put_text(local.cnt or 0)
 
-        def main():  # 会话独立的计数器
+        def main():
             put_buttons(['Add counter', 'Show counter'], [add, show])
             hold()
 
-    而通过函数参数传递状态的实现方式为::
+    The way to pass state through function parameters is::
 
         from functools import partial
         def add(cnt):
@@ -41,14 +43,14 @@ r"""
         def show(cnt):
             put_text(cnt[0])
 
-        def main():  # 会话独立的计数器
-            cnt = [0]  # 将计数器保存在数组中才可以实现引用传参
+        def main():
+            cnt = [0]  # Trick: to pass by reference
             put_buttons(['Add counter', 'Show counter'], [partial(add, cnt), partial(show, cnt)])
             hold()
 
-    当然,还可以通过函数闭包来实现相同的功能::
+    Of course, you can also use function closures to achieved the same::
 
-        def main():  # 会话独立的计数器
+        def main():
             cnt = 0
 
             def add():
@@ -61,7 +63,7 @@ r"""
             put_buttons(['Add counter', 'Show counter'], [add, show])
             hold()
 
-    :local 支持的操作:
+    :``local`` usage:
 
     ::
 
@@ -80,53 +82,6 @@ r"""
 
     .. versionadded:: 1.1
 
-    Get the session-local object of current session.
-
-    When accessing a property that does not exist in the data object, it returns ``None`` instead of throwing an exception.
-
-    When you need to save some session-independent data with multiple functions, it is more convenient to use session-local objects to save state than to use function parameters.
-
-    Here is a example of a session independent counter implementation::
-
-        def add():
-            data().cnt = (data().cnt or 0) + 1
-
-        def show():
-            put_text(data().cnt or 0)
-
-        def main():
-            put_buttons(['Add counter', 'Show counter'], [add, show])
-            hold()
-
-    The way to pass state through function parameters is::
-
-        from functools import partial
-        def add(cnt):
-            cnt[0] += 1
-
-        def show(cnt):
-            put_text(cnt[0])
-
-        def main():
-            cnt = [0]  # 将计数器保存在数组中才可以实现引用传参
-            put_buttons(['Add counter', 'Show counter'], [partial(add, cnt), partial(show, cnt)])
-            hold()
-
-    Of course, you can also use function closures to achieved the same::
-
-        def main():
-            cnt = 0
-
-            def add():
-                nonlocal cnt
-                cnt += 1
-
-            def show():
-                put_text(cnt)
-
-            put_buttons(['Add counter', 'Show counter'], [add, show])
-            hold()
-
 .. autofunction:: data
 .. autofunction:: set_env
 .. autofunction:: go_app
@@ -147,6 +102,7 @@ from ..exceptions import SessionNotFoundException, SessionException
 from ..utils import iscoroutinefunction, isgeneratorfunction, run_as_function, to_coroutine, ObjectDictProxy
 
 # 当前进程中正在使用的会话实现的列表
+# List of session implementations currently in use
 _active_session_cls = []
 
 __all__ = ['run_async', 'run_asyncio_coroutine', 'register_thread', 'hold', 'defer_call', 'data', 'get_info',
@@ -154,7 +110,8 @@ __all__ = ['run_async', 'run_asyncio_coroutine', 'register_thread', 'hold', 'def
 
 
 def register_session_implement_for_target(target_func):
-    """根据target_func函数类型注册会话实现,并返回会话实现"""
+    """根据target_func函数类型注册会话实现,并返回会话实现
+    Register the session implementation according to the target_func function type, and return the session implementation"""
     if iscoroutinefunction(target_func) or isgeneratorfunction(target_func):
         cls = CoroutineBasedSession
     else:
@@ -170,16 +127,19 @@ def register_session_implement_for_target(target_func):
 
 
 def get_session_implement():
-    """获取当前会话实现。仅供内部实现使用。应在会话上下文中调用"""
+    """获取当前会话实现。仅供内部实现使用。应在会话上下文中调用
+    Get the current session implementation. For internal implementation use only. Should be called in session context"""
     if not _active_session_cls:
         _active_session_cls.append(ScriptModeSession)
         _start_script_mode_server()
 
     # 当前正在使用的会话实现只有一个
+    # There is only one session implementation currently in use
     if len(_active_session_cls) == 1:
         return _active_session_cls[0]
 
     # 当前有多个正在使用的会话实现
+    # There are currently multiple session implementations in use
     for cls in _active_session_cls:
         try:
             cls.get_current_session()
@@ -205,7 +165,8 @@ def get_current_task_id():
 
 def check_session_impl(session_type):
     def decorator(func):
-        """装饰器:在函数调用前检查当前会话实现是否满足要求"""
+        """装饰器:在函数调用前检查当前会话实现是否满足要求
+        Decorator: Check whether the current session implementation meets the requirements before the function call"""
 
         @wraps(func)
         def inner(*args, **kwargs):
@@ -229,7 +190,9 @@ def check_session_impl(session_type):
 
 def chose_impl(gen_func):
     """
-    装饰器,使用chose_impl对gen_func进行装饰后,gen_func() 操作将根据当前会话实现 返回协程对象 或 直接运行函数体
+    装饰器,使用chose_impl对gen_func进行装饰后,gen_func() 调用将根据当前会话实现来确定是 返回协程对象 还是 直接运行函数体
+
+    Decorator, after using `choose_impl` to decorate `gen_func`, according to the current session implementation, the `gen_func()` call will either return the coroutine object or directly run the function body
     """
 
     @wraps(gen_func)
@@ -496,7 +459,7 @@ def get_info():
             * ``device.brand`` (str): Device brand. such as 'Apple'
             * ``device.model`` (str): Device model. such as 'iPhone'
 
-       * ``user_language`` (str): Language used by the user's operating system. 比如 ``'zh-CN'``
+       * ``user_language`` (str): Language used by the user's operating system. (e.g., ``'zh-CN'``)
        * ``server_host`` (str): PyWebIO server host, including domain and port, the port can be omitted when 80.
        * ``origin`` (str): Indicate where the user from. Including protocol, host, and port parts. Such as ``'http://localhost:8080'`` .
          It may be empty, but it is guaranteed to have a value when the user's page address is not under the server host. (that is, the host, port part are inconsistent with ``server_host``).
@@ -506,7 +469,7 @@ def get_info():
 
             * When using Tornado, ``request`` is instance of
               `tornado.httputil.HTTPServerRequest <https://www.tornadoweb.org/en/stable/httputil.html#tornado.httputil.HTTPServerRequest>`_
-            * When using Flask, ``request`` is instance of `flask.Request <https://flask.palletsprojects.com/en/1.1.x/api/#incoming-request-data>`_ 实例
+            * When using Flask, ``request`` is instance of `flask.Request <https://flask.palletsprojects.com/en/1.1.x/api/#incoming-request-data>`_
             * When using Django, ``request`` is instance of `django.http.HttpRequest <https://docs.djangoproject.com/en/3.0/ref/request-response/#django.http.HttpRequest>`_
             * When using aiohttp, ``request`` is instance of `aiohttp.web.BaseRequest <https://docs.aiohttp.org/en/stable/web_reference.html#aiohttp.web.BaseRequest>`_