diff --git a/.drone.yml b/.drone.yml index e4a44fec..36cad6e8 100644 --- a/.drone.yml +++ b/.drone.yml @@ -2,24 +2,13 @@ kind: pipeline type: exec name: default -clone: - disable: true - trigger: branch: - - dev + - dev-release event: - push steps: - - name: clone - commands: - - sleep 300 # wait aliyun repo to sync - - git init - - git remote add aliyun "https://code.aliyun.com/wang0618/pywebio.git" - - git fetch --no-tags --prune --progress --no-recurse-submodules --depth=1 aliyun $DRONE_BRANCH - - git checkout --progress --force -B $DRONE_BRANCH aliyun/$DRONE_BRANCH - - git log -1 - name: deploy demos commands: - | # https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#pipe-dockerfile-through-stdin diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index b92bd490..36ee4617 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,12 +1,11 @@ --- -name: Bug report -about: Create a bug report to help us improve -title: '' -labels: bug -assignees: '' +name: Bug report about: Create a bug report to help us improve title: '' +labels: bug assignees: '' --- -Note: For inquiries while using PyWebIO or questions that might be helpful to others, please consider moving to [Discussions](https://github.com/wang0618/PyWebIO/discussions) for posting. +Note: For inquiries while using PyWebIO or questions that might be helpful to others, please consider moving +to [Discussions](https://github.com/wang0618/PyWebIO/discussions) for posting. You can +try [PyWebIO QA Bot](https://github.com/pywebio/PyWebIO/discussions/596) to let AI answer the questions you encounter. **BUG Description** @@ -14,9 +13,9 @@ A clear and concise description of what the bug is and how to reproduce it. If the browser console reports an error or the script throws an exception, please also report them. - **Environment Information** - - OS and Version: - - Browser and Version: - - Python Version: Use `python3 --version` to view - - PyWebIO Version: Use `python3 -c "import pywebio;print(pywebio.__version__)"` to view + +- OS and Version: +- Browser and Version: +- Python Version: Use `python3 --version` to view +- PyWebIO Version: Use `python3 -c "import pywebio;print(pywebio.__version__)"` to view diff --git a/.github/ISSUE_TEMPLATE/bug_report_zh.md b/.github/ISSUE_TEMPLATE/bug_report_zh.md index 5688c572..e9323053 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_zh.md +++ b/.github/ISSUE_TEMPLATE/bug_report_zh.md @@ -7,6 +7,7 @@ assignees: '' --- 注: 对于PyWebIO使用咨询或对于其他人也可能有帮助的问题,请考虑移至 [Discussions](https://github.com/wang0618/PyWebIO/discussions) 进行发帖。 +另,可使用[PyWebIO QA Bot](https://github.com/pywebio/PyWebIO/discussions/596) 来让AI对你遇到的问题进行解答。 **BUG描述** 描述BUG表现以及复现方式。 diff --git a/.github/workflows/build_dev.yml b/.github/workflows/build_dev.yml new file mode 100644 index 00000000..7e23d453 --- /dev/null +++ b/.github/workflows/build_dev.yml @@ -0,0 +1,56 @@ +name: build dev version +on: + push: + branches: + - dev + repository_dispatch: + +jobs: + build_dev: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@master + - name: Set up Python 3 + uses: actions/setup-python@v1 + with: + python-version: 3.12 + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: '22' + - name: Build frontend + working-directory: ./webiojs + run: | + npm install + npx gulp + cp dist/pywebio.min.* ../pywebio/html/js + - name: Build doc demos + run: | + pip3 install -e ".[all]" + pip3 install -r requirements.txt + cd docs && CODE_EXPORT_PATH=../demos/doc_demos make clean html + - name: Set dev version + run: python3 tools/build_dev_version.py + - name: Release dev version + run: | + git config --global user.email "$(git log -n 1 --pretty=format:%ae)" + git config --global user.name "${{ github.actor }}" + + # ref: https://stackoverflow.com/questions/8536732/can-i-hold-git-credentials-in-environment-variables + git config --global credential.helper '!f() { sleep 1; echo "username=${{ github.actor }}"; echo "password=${GH_TOKEN}"; }; f' + + git fetch --unshallow origin + git branch -D dev-release || true + git checkout -b dev-release + + rm .gitignore + git add pywebio/__version__.py + git add pywebio/html/js + git add demos/doc_demos + + git commit -m "Build at `date`" + git push -f -u origin dev-release + env: + # This token is provided by Actions, you do not need to create your own token + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ba8711b4..9a4ac56a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -2,21 +2,21 @@ name: Python lint -on: [push, pull_request] +on: [ push, pull_request ] jobs: lint: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"] + python-version: ["3.9", "3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v2 - uses: codespell-project/actions-codespell@master with: ignore_words_list: datas - skip: "*.js,*.po,i18n.ts" + skip: "*.js,*.po,i18n.ts,*.json" - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3f983c13..7c4083d6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,7 +1,8 @@ name: Release +# https://github.community/t/how-to-run-github-actions-workflow-only-for-new-tags/16075/22 on: - create: + push: tags: - v* @@ -14,20 +15,20 @@ jobs: - name: Set up Python 3 uses: actions/setup-python@v1 with: - python-version: 3.7 + python-version: 3.12 - name: Set up Node.js uses: actions/setup-node@v2 with: - node-version: '14' + node-version: '22' - name: Build frontend working-directory: ./webiojs run: | npm install - gulp + npx gulp cp dist/pywebio.min.js ../pywebio/html/js - name: PyPi Upload run: | - pip3 install twine + pip3 install twine setuptools python3 setup.py sdist twine upload --username "__token__" --disable-progress-bar --verbose dist/* env: diff --git a/.github/workflows/sync_repo.yml b/.github/workflows/sync_repo.yml deleted file mode 100644 index a07a9c07..00000000 --- a/.github/workflows/sync_repo.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Sync with mirror repo -on: - push: - branches: - - dev -jobs: - sync: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@master - - name: Set up Python 3.7 - uses: actions/setup-python@v1 - with: - python-version: 3.7 - - name: Set up Node.js - uses: actions/setup-node@v2 - with: - node-version: '14' - - name: Build frontend - working-directory: ./webiojs - run: | - npm install - gulp - cp dist/pywebio.min.* ../pywebio/html/js - - name: Build doc demos - run: | - pip3 install -e ".[all]" - pip3 install -r requirements.txt - cd docs && CODE_EXPORT_PATH=../demos/doc_demos make clean html - - name: Set dev version - run: python3 tools/build_dev_version.py - - name: Push - run: | - git fetch --unshallow origin - git remote add aliyun "https://code.aliyun.com/wang0618/pywebio.git" - git config credential.helper '!f() { sleep 1; echo "username=${ALIYUN_GIT_USER}"; echo "password=${ALIYUN_GIT_PASSWORD}"; }; f' - rm .gitignore - git add pywebio/__version__.py - git add pywebio/html/js - git add demos/doc_demos - git config user.email "${ALIYUN_GIT_USER}" - git config user.name "${ALIYUN_GIT_USER}" - git commit --amend --no-edit - git push -f -u aliyun --tags || true - git push -f -u aliyun || true - env: - ALIYUN_GIT_USER: ${{ secrets.ALIYUN_GIT_USER }} - ALIYUN_GIT_PASSWORD: ${{ secrets.ALIYUN_GIT_PASSWORD }} \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0a3c12cc..f9dfba49 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,41 +6,40 @@ jobs: steps: - name: Checkout uses: actions/checkout@master - - name: Set up Python 3.7 + - name: Set up Python 3 uses: actions/setup-python@v1 with: - python-version: 3.7 + python-version: 3.12 - name: Set up Node.js uses: actions/setup-node@v2 with: - node-version: '14' + node-version: '22' - name: Build frontend working-directory: ./webiojs run: | npm install - gulp + npx gulp cp dist/pywebio.min.* ../pywebio/html/js - - name: Install Test JS deps - run: npm install -D @percy/agent - name: Install package run: pip3 install ".[all]" - name: Install dev dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt - - name: Install env - run: echo "PERCY_TOKEN=${{ secrets.PERCY_TOKEN }}" >> $GITHUB_ENV + - run: npm install --save-dev @percy/cli - name: Percy Test - uses: percy/exec-action@v0.3.1 - with: - working-directory: ./test - command: "./run_all.sh" + run: npx percy exec -- bash ./run_all.sh + working-directory: ./test + env: + PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }} - name: Upload test output uses: actions/upload-artifact@v1 if: failure() with: name: test output path: test/output - - name: Upload Codecov Report - working-directory: ./test - run: bash <(curl -s https://codecov.io/bash) + - name: Upload test output + uses: codecov/codecov-action@v3 + with: + working-directory: ./test + verbose: true # optional (default = false) diff --git a/.readthedocs.yml b/.readthedocs.yml index 16d5d9fa..905a6cfa 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -5,6 +5,12 @@ # Required version: 2 +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-lts-latest + tools: + python: "3.9" + # Build documentation in the docs/ directory with Sphinx sphinx: configuration: docs/conf.py @@ -14,11 +20,11 @@ sphinx: # configuration: mkdocs.yml # Optionally build your docs in additional formats such as PDF and ePub -formats: all +formats: + - pdf # Optionally set the version of Python and requirements required to build your docs python: - version: 3.7 install: - requirements: requirements.txt - method: pip diff --git a/README-zh.md b/README-zh.md index 4ae5af6a..5ff7652e 100644 --- a/README-zh.md +++ b/README-zh.md @@ -22,17 +22,11 @@ Python Version
- - Python code quality - - - Javascript code quality - License
- [Document] | [Demos] | [Why PyWebIO?] + [Document] | [Demos] | [Playground] | [Why PyWebIO?]

[English](README.md) | [中文](README-zh.md) @@ -65,7 +59,7 @@ pip3 install -U pywebio 开发版安装: ```bash -pip3 install -U https://code.aliyun.com/wang0618/pywebio/repository/archive.zip +pip3 install -U https://github.com/pywebio/PyWebIO/archive/dev-release.zip ``` **系统要求**: PyWebIO要求 Python 版本在 3.5.2 及以上 @@ -155,6 +149,7 @@ if __name__ == "__main__": - [基本demo](http://pywebio-demos.pywebio.online/) : 包含PyWebIO基本输入输出演示和使用PyWebIO编写的小应用 - [数据可视化demo](http://pywebio-charts.pywebio.online/) : 使用 bokeh、plotly、pyecharts 等库进行数据可视化 -## Document +## Links -使用手册和实现文档见 [https://pywebio.readthedocs.io](https://pywebio.readthedocs.io/zh_CN/latest/) +* 使用手册和实现文档见 [pywebio.readthedocs.io](https://pywebio.readthedocs.io/zh_CN/latest/) +* [PyWebIO Playground](https://play.pywebio.online/): 在线编辑、运行和分享PyWebIO代码 diff --git a/README.md b/README.md index 322aa4a4..ae0a1967 100644 --- a/README.md +++ b/README.md @@ -22,17 +22,11 @@ Python Version
- - Python code quality - - - Javascript code quality - License
- [Document] | [Demos] | [Why PyWebIO?] + [Document] | [Demos] | [Playground] | [Why PyWebIO?]

[English](README.md) | [中文](README-zh.md) @@ -64,7 +58,7 @@ pip3 install -U pywebio Development version: ```bash -pip3 install -U https://code.aliyun.com/wang0618/pywebio/repository/archive.zip +pip3 install -U https://github.com/pywebio/PyWebIO/archive/dev-release.zip ``` **Prerequisites**: PyWebIO requires Python 3.5.2 or newer @@ -153,6 +147,7 @@ For integration with other web frameworks, please refer to [document](https://py - [Basic demo](http://pywebio-demos.pywebio.online/) : PyWebIO basic input and output demos and some small applications written using PyWebIO. - [Data visualization demo](http://pywebio-charts.pywebio.online/) : Data visualization with the third-party libraries, e.g., `plotly`, `bokeh`, `pyecharts`. -## Document +## Links -Document is on [https://pywebio.readthedocs.io](https://pywebio.readthedocs.io) +* Document [pywebio.readthedocs.io](https://pywebio.readthedocs.io) +* [PyWebIO Playground](https://play.pywebio.online/): Edit, Run, Share PyWebIO Code Online \ No newline at end of file diff --git a/demos/chat_room.py b/demos/chat_room.py index 52bd503e..afe6e9ac 100644 --- a/demos/chat_room.py +++ b/demos/chat_room.py @@ -5,11 +5,10 @@ from pywebio.output import * from pywebio.session import defer_call, info as session_info, run_async -# 最大消息记录保存 MAX_MESSAGES_CNT = 10 ** 4 -chat_msgs = [] # 聊天记录 (name, msg) -online_users = set() # 在线用户 +chat_msgs = [] # The chat message history. The item is (name, message content) +online_users = set() def t(eng, chinese): @@ -17,7 +16,7 @@ def t(eng, chinese): return chinese if 'zh' in session_info.user_language else eng -async def refresh_msg(my_name, msg_box): +async def refresh_msg(my_name): """send new message to current session""" global chat_msgs last_idx = len(chat_msgs) @@ -25,7 +24,7 @@ async def refresh_msg(my_name, msg_box): await asyncio.sleep(0.5) for m in chat_msgs[last_idx:]: if m[0] != my_name: # only refresh message that not sent by current user - msg_box.append(put_markdown('`%s`: %s' % m, sanitize=True)) + put_markdown('`%s`: %s' % m, sanitize=True, scope='msg-box') # remove expired message if len(chat_msgs) > MAX_MESSAGES_CNT: @@ -38,26 +37,24 @@ async def main(): """PyWebIO chat room You can chat with everyone currently online. - 和当前所有在线的人聊天 """ global chat_msgs put_markdown(t("## PyWebIO chat room\nWelcome to the chat room, you can chat with all the people currently online. You can open this page in multiple tabs of your browser to simulate a multi-user environment. This application uses less than 90 lines of code, the source code is [here](https://github.com/wang0618/PyWebIO/blob/dev/demos/chat_room.py)", "## PyWebIO聊天室\n欢迎来到聊天室,你可以和当前所有在线的人聊天。你可以在浏览器的多个标签页中打开本页面来测试聊天效果。本应用使用不到90行代码实现,源代码[链接](https://github.com/wang0618/PyWebIO/blob/dev/demos/chat_room.py)")) - msg_box = output() - put_scrollable(msg_box, height=300, keep_bottom=True) + put_scrollable(put_scope('msg-box'), height=300, keep_bottom=True) nickname = await input(t("Your nickname", "请输入你的昵称"), required=True, validate=lambda n: t('This name is already been used', '昵称已被使用') if n in online_users or n == '📢' else None) online_users.add(nickname) chat_msgs.append(('📢', '`%s` joins the room. %s users currently online' % (nickname, len(online_users)))) - msg_box.append(put_markdown('`📢`: `%s` join the room. %s users currently online' % (nickname, len(online_users)), sanitize=True)) + put_markdown('`📢`: `%s` join the room. %s users currently online' % (nickname, len(online_users)), sanitize=True, scope='msg-box') @defer_call def on_close(): online_users.remove(nickname) chat_msgs.append(('📢', '`%s` leaves the room. %s users currently online' % (nickname, len(online_users)))) - refresh_task = run_async(refresh_msg(nickname, msg_box)) + refresh_task = run_async(refresh_msg(nickname)) while True: data = await input_group(t('Send message', '发送消息'), [ @@ -68,7 +65,7 @@ def on_close(): break if data['cmd'] == t('Multiline Input', '多行输入'): data['msg'] = '\n' + await textarea('Message content', help_text=t('Message content supports Markdown syntax', '消息内容支持Markdown语法')) - msg_box.append(put_markdown('`%s`: %s' % (nickname, data['msg']), sanitize=True)) + put_markdown('`%s`: %s' % (nickname, data['msg']), sanitize=True, scope='msg-box') chat_msgs.append((nickname, data['msg'])) refresh_task.close() diff --git a/demos/chatgpt.py b/demos/chatgpt.py new file mode 100644 index 00000000..d25c3b6c --- /dev/null +++ b/demos/chatgpt.py @@ -0,0 +1,211 @@ +import json +import time +from typing import Dict, List + +from openai import OpenAI, Stream +from openai.types.chat import ChatCompletionChunk + +import pywebio_battery +from pywebio.input import * +from pywebio.output import * +from pywebio.pin import * +from pywebio.session import set_env, download + + +class ChatGPTStreamResponse: + """ + A wrapper to Stream[ChatCompletionChunk], add a `result()` method to get the final result. + """ + def __init__(self, response: Stream[ChatCompletionChunk]): + self.response = response + self.yielded = [] + self.finish_reason = None + + def __next__(self): + chunk = next(self.response) + self.finish_reason = chunk.choices[0].finish_reason + delta = chunk.choices[0].delta + if delta.content: + self.yielded.append(delta.content) + return delta.content + + def __iter__(self): + return self + + def result(self): + return ''.join(self.yielded) + + +class ChatGPT: + + def __init__(self, messages: List[Dict] = None, model: str = "gpt-3.5-turbo", client: OpenAI = None, **model_kwargs): + """ + Create a chatgpt client + + :param messages: A list of messages comprising the conversation so far. + Each message is a dict with keys "role" and "content". + See: https://platform.openai.com/docs/api-reference/chat/create#chat/create-messages + :param model: The model to use. + :param OpenAI client: The openai client to use. If not provided, a new client will be created. + :param model_kwargs: Other parameters to pass to model, + See https://platform.openai.com/docs/api-reference/chat + """ + self._client = client or OpenAI() + self._messages = list(messages or []) + self.model_kwargs = dict(model=model, **model_kwargs) + + self.pending_stream_reply: ChatGPTStreamResponse = None + self.latest_nonstream_finish_reason = None + + def set_model(self, model: str): + """Set the model to use""" + self.model_kwargs['model'] = model + + def _ask(self, message: str, stream=True, **model_kwargs): + if self.pending_stream_reply: + self._messages.append({"role": "assistant", "content": self.pending_stream_reply.result()}) + self.pending_stream_reply = None + + self._messages.append({"role": "user", "content": message}) + resp = self._client.chat.completions.create( + **self.model_kwargs, + **model_kwargs, + messages=self._messages, + stream=stream, + ) + return resp + + def ask(self, message: str, **model_kwargs) -> str: + """ + Send a message to chatgpt and get the reply in string + + :param message: The message to send + :param model_kwargs: Other parameters to pass to openai.ChatCompletion.create() + :return: The reply from chatgpt + """ + resp = self._ask(message, stream=False, **model_kwargs) + reply = resp['choices'][0] + reply_content = reply['message']['content'] + self._messages.append({"role": "assistant", "content": reply_content}) + self.latest_nonstream_finish_reason = reply['finish_reason'] + + return reply_content + + def ask_stream(self, message: str, **model_kwargs) -> ChatGPTStreamResponse: + """ + Send a message to chatgpt and get the reply in stream + + :param message: The message to send + :param model_kwargs: Other parameters to pass to openai.ChatCompletion.create() + :return: A iterator that yields the reply from chatgpt. + The iterator will be exhausted when the reply is complete. + """ + resp = self._ask(message, stream=True, **model_kwargs) + self.pending_stream_reply = ChatGPTStreamResponse(resp) + return self.pending_stream_reply + + def latest_finish_reason(self) -> str: + """The finish reason for the latest reply of chatgpt. + + The possible values for finish_reason are: + 'stop': API returned complete model output + 'length': Incomplete model output due to max_tokens parameter or token limit + 'content_filter': Omitted content due to a flag from our content filters + 'null': API response still in progress or incomplete + + See: https://platform.openai.com/docs/guides/chat/response-format + """ + if self.pending_stream_reply: + return self.pending_stream_reply.finish_reason + return self.latest_nonstream_finish_reason + + def messages(self) -> List[Dict]: + """Get all messages of the conversation """ + if self.pending_stream_reply: + self._messages.append({"role": "assistant", "content": self.pending_stream_reply.result()}) + self.pending_stream_reply = None + + return self._messages + + +def get_openai_config(): + openai_config = json.loads(pywebio_battery.get_localstorage('openai_config') or '{}') + if not openai_config: + openai_config = input_group('OpenAI API Config', [ + input('API Key', name='api_key', type=TEXT, required=True, + help_text='Get your API key from https://platform.openai.com/account/api-keys'), + input('API Server', name='api_base', type=TEXT, value='https://api.openai.com', required=True), + ]) + openai_config['api_base'] = openai_config['api_base'].removesuffix('/v1').strip('/') + '/v1' + pywebio_battery.set_localstorage('openai_config', json.dumps(openai_config)) + + put_button('Reset OpenAI API Key', reset_openai_config, link_style=True) + return openai_config + + +def reset_openai_config(): + pywebio_battery.set_localstorage('openai_config', json.dumps(None)) + toast("Please refresh the page to take effect") + + +def main(): + """""" + set_env(input_panel_fixed=False, output_animation=False) + put_markdown(""" + # ChatGPT + A ChatGPT client implemented with PyWebIO. [Source Code](https://github.com/pywebio/PyWebIO/blob/dev/demos/chatgpt.py) + TIPS: refresh page to open a new chat. + """) + put_select('model', ['gpt-3.5-turbo', 'gpt-4'], label='Model') + + openai_config = get_openai_config() + client = OpenAI(api_key=openai_config['api_key'], base_url=openai_config['api_base']) + + bot = ChatGPT(client=client, model=pin.model) + pin_on_change('model', lambda v: bot.set_model(v)) + while True: + form = input_group('', [ + input(name='msg', placeholder='Ask ChatGPT'), + actions(name='cmd', buttons=['Send', 'Multi-line Input', 'Save Chat']) + ]) + if form['cmd'] == 'Multi-line Input': + form['msg'] = textarea(value=form['msg']) + elif form['cmd'] == 'Save Chat': + messages = [ + msg['content'] if msg['role'] == 'user' else f"> {msg['content']}" + for msg in bot.messages() + ] + download(f"chatgpt_{time.strftime('%Y%m%d%H%M%S')}.md", + '\n\n'.join(messages).encode('utf8')) + continue + + user_msg = form['msg'] + if not user_msg: + continue + + put_info(put_text(user_msg, inline=True)) + + with use_scope(f'reply-{int(time.time())}'): + put_loading('grow', 'info') + try: + reply_chunks = bot.ask_stream(user_msg) + except Exception as e: + popup('ChatGPT Error', put_error(e)) + continue + finally: + clear() # clear loading + for chunk in reply_chunks: + put_text(chunk, inline=True) + clear() # clear above text + put_markdown(reply_chunks.result()) + + if bot.latest_finish_reason() == 'length': + put_error('Incomplete model output due to max_tokens parameter or token limit.') + elif bot.latest_finish_reason() == 'content_filter': + put_warning("Omitted content due to a flag from OpanAI's content filters.") + + +if __name__ == '__main__': + from pywebio import start_server + + start_server(main, port=8080, debug=True, cdn=False) diff --git a/demos/doc_demo.py b/demos/doc_demo.py index 826160f9..281d201a 100644 --- a/demos/doc_demo.py +++ b/demos/doc_demo.py @@ -1,12 +1,14 @@ """ Run the example code in the documentation online """ +import base64 + from functools import partial from os import path, listdir - from pywebio import start_server from pywebio.platform import config from pywebio.session import local as session_local, info as session_info +import pywebio_battery ########################################## # Pre-import modules for demo @@ -15,17 +17,29 @@ from pywebio.output import * from pywebio.session import * from pywebio.pin import * - +from pywebio_battery import * ########################################## +here_dir = path.dirname(path.abspath(__file__)) +playground_host = "https://play.pywebio.online" + def t(eng, chinese): """return English or Chinese text according to the user's browser language""" return chinese if 'zh' in session_info.user_language else eng -here_dir = path.dirname(path.abspath(__file__)) +def playground(code): + pre_import = PRE_IMPORT + battery_apis = pywebio_battery.__all__ + if 'pywebio_battery import' not in code and any(api in code for api in battery_apis): + pre_import += 'from pywebio_battery import *\n' + + code = f"{pre_import}\n{code}" + encode = base64.b64encode(code.encode('utf8')).decode('utf8') + url = f"{playground_host}/#{encode}" + run_js('window.open(url)', url=url) def gen_snippets(code): @@ -51,42 +65,46 @@ def run_code(code, scope): toast('Exception occurred: "%s:%s"' % (type(e).__name__, e), color='error') -IMPORT_CODE = """from pywebio import start_server -from pywebio.input import * +PRE_IMPORT = """from pywebio.input import * from pywebio.output import * from pywebio.session import * from pywebio.pin import * +from pywebio import start_server +""" +APP_TPL = f"""{PRE_IMPORT} def main(): %s start_server(main, port=8080, debug=True) """ +CLIPBOARD_SETUP = """ +window.writeText = function(text) { + const input = document.createElement('textarea'); + input.style.opacity = 0; + input.style.position = 'absolute'; + input.style.left = '-100000px'; + document.body.appendChild(input); + + input.value = text; + input.select(); + input.setSelectionRange(0, text.length); + document.execCommand('copy'); + document.body.removeChild(input); + return true; +} +""" + def copytoclipboard(code): - code = IMPORT_CODE % code.replace('\n', '\n ') + code = APP_TPL % code.replace('\n', '\n ') run_js("writeText(text)", text=code) toast('The code has been copied to the clipboard') def handle_code(code, title): - run_js(""" - window.writeText = function(text) { - const input = document.createElement('textarea'); - input.style.opacity = 0; - input.style.position = 'absolute'; - input.style.left = '-100000px'; - document.body.appendChild(input); - - input.value = text; - input.select(); - input.setSelectionRange(0, text.length); - document.execCommand('copy'); - document.body.removeChild(input); - return true; - } - """) + run_js(CLIPBOARD_SETUP) session_local.globals = dict(globals()) if title: put_markdown('## %s' % title) @@ -95,10 +113,16 @@ def handle_code(code, title): with use_scope() as scope: put_code(p, 'python') - put_buttons([t('Run', '运行'), t("Copy to clipboard", '复制代码')], onclick=[ - partial(run_code, code=p, scope=scope), - partial(copytoclipboard, code=p) - ]) + put_buttons( + [t('Run', '运行'), + t("Edit", '编辑'), + t("Copy to clipboard", '复制代码')], + onclick=[ + partial(run_code, code=p, scope=scope), + partial(playground, code=p), + partial(copytoclipboard, code=p) + ] + ) put_markdown('----') diff --git a/demos/gomoku_game.py b/demos/gomoku_game.py index a9c168bc..0086d825 100644 --- a/demos/gomoku_game.py +++ b/demos/gomoku_game.py @@ -1,8 +1,7 @@ import time -import pywebio +from pywebio import session, start_server from pywebio.output import * -from pywebio import session goboard_size = 15 # -1 -> none, 0 -> black, 1 -> white @@ -92,4 +91,4 @@ def show_goboard(): if __name__ == '__main__': - pywebio.start_server(main, debug=True, port=8080) + start_server(main, debug=True, port=8080) diff --git a/demos/index.py b/demos/index.py index 02410216..856d9fc4 100644 --- a/demos/index.py +++ b/demos/index.py @@ -4,6 +4,7 @@ from pywebio.session import info as session_info index_md = r"""### Basic demo +The source code of the demos can be found [here](https://github.com/pywebio/PyWebIO/tree/dev/demos). - [BMI calculation](./bmi): Calculating Body Mass Index based on height and weight - [Online chat room](./chat_room): Chat with everyone currently online (using less than 90 lines of code) @@ -11,6 +12,8 @@ - [Online Gomoku game](./gomoku_game): An online shared Gomoku game (using less than 100 lines of code) - [Input demo](./input_usage): Demonstrate the usage of PyWebIO input module - [Output demo](./output_usage): Demonstrate the usage of PyWebIO output module + - [ChatGPT](./chatgpt): A ChatGPT client implemented with PyWebIO + - [Wordle](./wordle): A wordle-like game implemented with PyWebIO - [Theme preview](./theme): Demo page with various themes supported by PyWebIO ### Data visualization demo @@ -25,35 +28,40 @@ **Screenshots** - bokeh demo + bokeh demo - plotly demo + plotly demo - pyecharts demo + pyecharts demo - cutecharts demo + cutecharts demo ### Links * PyWebIO Github [github.com/wang0618/PyWebIO](https://github.com/wang0618/PyWebIO) * Document [pywebio.readthedocs.io](https://pywebio.readthedocs.io) +* [PyWebIO Playground](https://play.pywebio.online/): Edit, Run, Share PyWebIO Code Online """.format(charts_demo_host=charts_demo_host) index_md_zh = r"""### 基本demo +Demo源码[链接](https://github.com/pywebio/PyWebIO/tree/dev/demos) + - [BMI计算](./bmi): 根据身高体重计算BMI指数 - [聊天室](./chat_room): 和当前所有在线的人聊天 (不到90行代码实现) - [Markdown实时预览](./markdown_previewer): 可以实时预览的在线Markdown编辑器 (不到40行代码实现) - [在线五子棋游戏](./gomoku_game): 多人协作对战的五子棋游戏 (不到100行代码实现) - [输入演示](./input_usage): 演示PyWebIO输入模块的用法 - [输出演示](./output_usage): 演示PyWebIO输出模块的用法 + - [ChatGPT](./chatgpt): 使用PyWebIO编写的ChatGPT客户端 + - [Wordle](./wordle): 使用PyWebIO编写的猜字游戏(wordle) - [主题预览](./theme): 展示PyWebIO支持的各种主题 - 更多Demo请见[文档](https://pywebio.readthedocs.io)中示例代码的在线Demo @@ -69,24 +77,25 @@ **数据可视化demo截图** - bokeh demo + bokeh demo - plotly demo + plotly demo - pyecharts demo + pyecharts demo - cutecharts demo + cutecharts demo ### Links * PyWebIO Github [github.com/wang0618/PyWebIO](https://github.com/wang0618/PyWebIO) * 使用手册和实现文档见 [pywebio.readthedocs.io](https://pywebio.readthedocs.io/zh_CN/latest/) +* [PyWebIO Playground](https://play.pywebio.online/): 在线编辑、运行和分享PyWebIO代码 """.format(charts_demo_host=charts_demo_host) diff --git a/demos/theme.py b/demos/theme.py index 771766e9..d4eeb779 100644 --- a/demos/theme.py +++ b/demos/theme.py @@ -348,7 +348,7 @@ def page(): put_markdown('# Switch Theme') themes = [ - put_image(f"https://cdn.jsdelivr.net/gh/wang0618/PyWebIO@dev/docs/assets/theme/{name}.png").onclick( + put_image(f"https://fastly.jsdelivr.net/gh/wang0618/PyWebIO@dev/docs/assets/theme/{name}.png").onclick( partial(go_app, name=name, new_window=False)) for name in ALL_THEME if name != theme ] diff --git a/demos/wordle.py b/demos/wordle.py new file mode 100644 index 00000000..cc9b75f3 --- /dev/null +++ b/demos/wordle.py @@ -0,0 +1,110 @@ +import time +from pywebio import start_server, config +from pywebio.output import * +from pywebio.session import run_js, local as session_local + +TODAY_WORD = 'PYWEBIO' # need to be uppercase + +MAX_TRY = 6 +WORD_LEN = len(TODAY_WORD) + + +CSS = """ +.pywebio {padding-top: 0} .markdown-body table {display:table; width:250px; margin:10px auto;} +.markdown-body table th, .markdown-body table td {font-weight:bold; padding:0; line-height:50px;} +th>div,td>div {width:50px; height:50px}.btn-light {background-color:#d3d6da;} +@media (max-width: 435px) {.btn{padding:0.375rem 0.5rem;}} +@media (max-width: 355px) {.btn{padding:0.375rem 0.4rem;}} +""" + + +# To check if a user's input word is actually a legit word +# We just implement a placeholder function in this example +# If a guess word is UNHAPPY, toast a message +def is_word(s): + return 'UNHAPPY' not in s + + +def on_key_press(char): + if session_local.curr_row >= MAX_TRY or session_local.game_pass: + return + + if char == '◀': + session_local.curr_word = session_local.curr_word[:-1] + return clear(f's-{session_local.curr_row}-{len(session_local.curr_word)}') + + # show the char in grid + with use_scope(f's-{session_local.curr_row}-{len(session_local.curr_word)}', clear=True): + put_text(char) + + session_local.curr_word += char + if len(session_local.curr_word) == WORD_LEN: # submit a word guess + if not is_word(session_local.curr_word): + toast('Not in word list!', color='error') + session_local.curr_word = '' + for i in range(WORD_LEN): + clear(f's-{session_local.curr_row}-{i}') + else: + for idx, c in enumerate(session_local.curr_word): + time.sleep(0.2) + if TODAY_WORD[idx] == c: + session_local.green_chars.add(c) + run_js('$("button:contains(%s)").css({"background-color":"#6aaa64", "color":"white"})' % c) + text_bg = '#6aaa64' + session_local.game_result += '🟩' + elif c in TODAY_WORD: + text_bg = '#c9b458' + session_local.game_result += '🟨' + if c not in session_local.green_chars: + run_js('$("button:contains(%s)").css({"background-color":"#c9b458", "color":"white"})' % c) + else: + text_bg = '#787c7e' + session_local.game_result += '⬜' + run_js('$("button:contains(%s)").css({"background-color":"#787c7e", "color":"white"})' % c) + + with use_scope(f's-{session_local.curr_row}-{idx}', clear=True): + put_text(c).style(f'color:white;background:{text_bg}') + + session_local.game_result += '\n' + if session_local.curr_word == TODAY_WORD: + toast('Genius', color='success') + session_local.game_pass = True + + session_local.curr_row += 1 + session_local.curr_word = '' + + if session_local.game_pass: + message = f'Wordle {session_local.curr_row}/{MAX_TRY}\n' + session_local.game_result + with popup("Game Result", size='small'): + put_text(message).style('text-align: center') + put_button('Share', color='success', onclick=lambda: toast('Copied to clipboard') or run_js("""navigator.clipboard.write([new ClipboardItem({"text/plain":new Blob([text],{type:"text/plain"})})]);""", text=message)).style('text-align: center') + + +@config(title="WORDLE with PyWebIO", description="A wordle-like game implemented with PyWebIO", css_style=CSS) +def main(): + put_markdown( + '# WORDLE \n A pure python implementation of a [Wordle-like game](https://en.wikipedia.org/wiki/Wordle), using PyWebIO library. ' + '[Source code](https://github.com/pywebio/PyWebIO/blob/dev/demos/wordle.py)' + ).style('text-align:center') + + grid = [ + [put_scope(f's-{x}-{y}', content=put_text(' ')) for y in range(WORD_LEN)] + for x in range(MAX_TRY) + ] + put_table(grid).style('text-align: center') + + keyboard = [ + put_buttons([dict(label=c, value=c, color='light') for c in keys], on_key_press, serial_mode=True) + for keys in ['QWERTYUIOP', 'ASDFGHJKL', 'ZXCVBNM◀'] + ] + put_column(keyboard).style('text-align: center') + + session_local.curr_row = 0 + session_local.curr_word = '' + session_local.green_chars = set() + session_local.game_pass = False + session_local.game_result = '' + + +if __name__ == '__main__': + start_server(main, port=8080, cdn=False) diff --git a/docs/arch.rst b/docs/arch.rst index 81794437..7b6b745e 100644 --- a/docs/arch.rst +++ b/docs/arch.rst @@ -4,20 +4,17 @@ Architecture 概念 ------------ -``Session`` 表示浏览器与程序交互产生的一次会话。PyWebIO在会话中运行 ``Task`` ,任务是 +``Session`` 表示浏览器访问PyWebIO应用产生的一次会话。其生命周期从浏览器打开PyWebIO应用开始,到用户关闭浏览器页面或PyWebIO应用逻辑运行结束为止。 -会话中除了起始的执行单元,也可以并发启动新的执行单元,在新的执行单元中也可以进行输入输出。 +会话建立后,PyWebIO创建一个线程或协程来执行应用逻辑。这里的线程或协程在PyWebIO中被称为 ``Task`` (执行单元)。 +除了起始的执行单元(由PyWebIO框架启动),应用在会话中也可以自行启动新的执行单元,在新的执行单元中也可以进行输入输出。 -在用户端,相同会话中的不同的执行单元的输入是独立的,共享输出空间,但输出域的栈结构各自独立。 +在浏览器端,相同会话中的不同的执行单元的输入是独立的,共享输出空间,但输出域的栈结构各自独立。 -若用户正在填写一个执行单元的表单,会话中的其他执行单元也开始向用户请求输入,此时用户正在填写的表单将会隐藏, -新的输入表单将会显示给用户,当用户填写完新表单并提交后,旧表单重新显示,之前在旧表单上的输入也会保留。 +若用户正在填写一个执行单元的表单,会话中的其他执行单元也开始向用户请求输入,此时用户正在填写的表单将会被新的表单覆盖, +当用户填写完新表单并提交后,旧表单重新显示,之前在旧表单上的输入也会保留。 -在基于线程的会话中,会话中的每个执行单元都是一个线程 - -在基于协程的会话中,会话中的每个执行单元都是一个协程 - -除了并发执行的执行单元,会话中还有事件回调函数,目前就只有按钮控件可以绑定点击事件的回调函数。 +在基于线程的会话中,会话中的每个执行单元都是一个线程;在基于协程的会话中,会话中的每个执行单元都是一个协程。 架构 ------------ diff --git a/docs/conf.py b/docs/conf.py index a79edbc8..6c8d8a5e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -37,6 +37,9 @@ 'sphinx_toolbox.collapse', ] +# https://github.com/sphinx-doc/sphinx/issues/6316 +toc_object_entries = False + primary_domain = "py" default_role = "py:obj" # intersphinx_mapping = {"python": ("https://docs.python.org/3.6/", None)} @@ -74,6 +77,8 @@ def setup(app): """Configure Sphinx""" app.add_css_file('pywebio.css') + # from docutils.parsers.rst.directives.admonitions import Note + # app.add_directive('collapse', Note) # -- Extension configuration ------------------------------------------------- diff --git a/docs/cookbook.rst b/docs/cookbook.rst index 42c7eca3..d22b6d2f 100644 --- a/docs/cookbook.rst +++ b/docs/cookbook.rst @@ -38,7 +38,7 @@ Output pandas dataframe Output Matplotlib figure ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Simply do not call ``matplotlib.pyplot.show``, directly save the figure to in-memory buffer and output the buffer +Instead of using ``matplotlib.pyplot.show()``, to show matplotlib figure in PyWebIO, you need to save the figure to in-memory buffer fist and then output the buffer via :func:`pywebio.output.put_image`: .. exportable-codeblock:: diff --git a/docs/guide.rst b/docs/guide.rst index bf6effab..5b955ed4 100644 --- a/docs/guide.rst +++ b/docs/guide.rst @@ -13,7 +13,8 @@ user input. In addition, PyWebIO also provides support for click events, layout, 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 example -codes in this document, where you can run the example code online and see what happens. +codes in this document, where you can run the example code online and see what happens. Also, the +`PyWebIO Playground `_ is a good place to write, run and share your PyWebIO code online. Input ------------ diff --git a/docs/index.rst b/docs/index.rst index b69c63c2..8fa9200a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -26,7 +26,7 @@ Stable version:: Development version:: - pip3 install -U https://code.aliyun.com/wang0618/pywebio/repository/archive.zip + pip3 install -U https://github.com/pywebio/PyWebIO/archive/dev-release.zip **Prerequisites**: PyWebIO requires Python 3.5.2 or newer diff --git a/docs/libraries_support.rst b/docs/libraries_support.rst index efd5a09e..636cc0d9 100644 --- a/docs/libraries_support.rst +++ b/docs/libraries_support.rst @@ -15,7 +15,7 @@ You can use PyInstaller to packages PyWebIO application into a stand-alone execu You need replace ``app.py`` to your PyWebIO application file name. -2. Edit the spec file, change the ``datas`` parameter of ``Analysis``:: +2. Only for PyWebIO before v1.8: Edit the spec file, change the ``datas`` parameter of ``Analysis``:: from pywebio.utils import pyinstaller_datas @@ -64,7 +64,7 @@ In PyWebIO, you can also use ``bokeh.io.show()`` to display a Bokeh App. For the .. 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 +.. image:: https://fastly.jsdelivr.net/gh/wang0618/pywebio-chart-gallery@master/assets/bokeh.png pyecharts ^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ See related demo on :charts_demo_host:`pyecharts demo ` .. only:: not latex - .. image:: https://cdn.jsdelivr.net/gh/wang0618/pywebio-chart-gallery@master/assets/pyecharts.gif + .. image:: https://fastly.jsdelivr.net/gh/wang0618/pywebio-chart-gallery@master/assets/pyecharts.gif plotly ^^^^^^^^^^^^^^^^^^^^^^ @@ -95,7 +95,7 @@ In PyWebIO, you can use the following code to output the plotly chart instance:: See related demo on :charts_demo_host:`plotly demo ` -.. image:: https://cdn.jsdelivr.net/gh/wang0618/pywebio-chart-gallery@master/assets/plotly.png +.. image:: https://fastly.jsdelivr.net/gh/wang0618/pywebio-chart-gallery@master/assets/plotly.png pyg2plot ^^^^^^^^^^^^^^^^^^^^^^ @@ -121,4 +121,4 @@ In PyWebIO, you can use the following code to output the cutecharts.py chart ins See related demo on :charts_demo_host:`cutecharts demo ` -.. image:: https://cdn.jsdelivr.net/gh/wang0618/pywebio-chart-gallery@master/assets/cutecharts.png +.. image:: https://fastly.jsdelivr.net/gh/wang0618/pywebio-chart-gallery@master/assets/cutecharts.png diff --git a/docs/locales/fa/LC_MESSAGES/FAQ.po b/docs/locales/fa/LC_MESSAGES/FAQ.po new file mode 100644 index 00000000..f99bd65c --- /dev/null +++ b/docs/locales/fa/LC_MESSAGES/FAQ.po @@ -0,0 +1,71 @@ +# Copyright (C) Weimin Wang +# This file is distributed under the same license as the PyWebIO package. +# +# FIRST AUTHOR , 2022. +# Pikhosh , 2022. +msgid "" +msgstr "" +"Project-Id-Version: PyWebIO 1.5.2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-02-26 16:35+0330\n" +"PO-Revision-Date: 2022-02-26 20:27+0330\n" +"Last-Translator: Pikhosh \n" +"Language-Team: Persian <>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.9.1\n" +"Language: fa\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Lokalize 21.12.2\n" + +#: ../../FAQ.rst:2 +msgid "FAQ" +msgstr "سوالات متداول" + +#: ../../FAQ.rst:8 +msgid "" +"How to make the input form not disappear after submission, and can " +"continue to receive input?" +msgstr "" +"چجوری فرم ورودی رو طوری کنیم که بعد از ارسال ناپدید نشه، و بتونه " +"به دریافت ورودی ادامه بده؟" + +#: ../../FAQ.rst:10 +msgid "" +"You can consider the :doc:`pin <./pin>` module. It achieves persistent " +"input by pinning input widgets to the page." +msgstr "" +"شما می توانید ماژول :doc:`pin <./pin>` را در نظر بگیرید. اون به ورودی " +"مداوم با پین کردن ویجت های ورودی به صفحه دست پیدا می کند." + +#: ../../FAQ.rst:14 +msgid "How to output an input widget such as a search bar?" +msgstr "چجوری یک ویجت ورودی رو به عنوان خروجی نشون بدم مثل یه نوار جست جو؟" + +#: ../../FAQ.rst:16 +msgid "You can consider the :doc:`pin <./pin>` module." +msgstr "شما می توانید ماژول :doc:`pin <./pin>` را در نظر بگیرید." + +#: ../../FAQ.rst:20 +msgid "Why the callback of ``put_buttons()`` does not work?" +msgstr "چرا فراخوانی ``put_buttons()`` کار نمی کنه؟" + +#: ../../FAQ.rst:22 +msgid "" +"You might use the old version of PyWebIO, upgrade it to the latest " +"version or see `the old document " +"`_" +msgstr "" +"شما ممکن است از نسخه قدیمی PyWebIO استفاده کنید، به آخرین " +"نسخه ارتقا اش دهید یا `the old document " +"`_را ببینید" + +#: ../../FAQ.rst:25 +msgid "Why I cannot download the file using ``put_file()``?" +msgstr "چرا من نمی تونم با استفاده از ``put_file()`` فایل رو دانلود کنم؟" + +#: ../../FAQ.rst:27 +msgid "The reason is the same as above." +msgstr "دلیل مشابه بالاست." + diff --git a/docs/locales/fa/LC_MESSAGES/advanced.po b/docs/locales/fa/LC_MESSAGES/advanced.po new file mode 100644 index 00000000..1e10a02c --- /dev/null +++ b/docs/locales/fa/LC_MESSAGES/advanced.po @@ -0,0 +1,664 @@ +# Copyright (C) Weimin Wang +# This file is distributed under the same license as the PyWebIO package. +# +# FIRST AUTHOR , 2022. +# Pikhosh , 2022. +msgid "" +msgstr "" +"Project-Id-Version: PyWebIO 1.5.2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-02-26 16:35+0330\n" +"PO-Revision-Date: 2022-02-28 12:30+0330\n" +"Last-Translator: Pikhosh \n" +"Language-Team: Persian <>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.9.1\n" +"Language: fa\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Lokalize 21.12.2\n" + +#: ../../advanced.rst:2 +msgid "Advanced topic" +msgstr "موضوع پیشرفته" + +#: ../../advanced.rst:4 +msgid "This section will introduce the advanced features of PyWebIO." +msgstr "" + +#: ../../advanced.rst:10 +msgid "Start multiple applications with start_server()" +msgstr "" + +#: ../../advanced.rst:12 +msgid "" +"`start_server() ` accepts a " +"function as PyWebIO application. In addition, `start_server() " +"` also accepts a list of " +"application function or a dictionary of it to start multiple " +"applications. You can use `pywebio.session.go_app() " +"` or `put_link() ` to " +"jump between application::" +msgstr "" + +#: ../../advanced.rst:17 +msgid "" +"def task_1():\n" +" put_text('task_1')\n" +" put_buttons(['Go task 2'], [lambda: go_app('task_2')])\n" +"\n" +"def task_2():\n" +" put_text('task_2')\n" +" put_buttons(['Go task 1'], [lambda: go_app('task_1')])\n" +"\n" +"def index():\n" +" put_link('Go task 1', app='task_1') # Use `app` parameter to specify" +" the task name\n" +" put_link('Go task 2', app='task_2')\n" +"\n" +"# equal to `start_server({'index': index, 'task_1': task_1, 'task_2': " +"task_2})`\n" +"start_server([index, task_1, task_2])" +msgstr "" + +#: ../../advanced.rst:32 +msgid "" +"When the first parameter of `start_server() " +"` is a dictionary, whose key is " +"application name and value is application function. When it is a list, " +"PyWebIO will use function name as application name." +msgstr "" + +#: ../../advanced.rst:35 +msgid "" +"You can select which application to access through the ``app`` URL " +"parameter (for example, visit ``http://host:port/?app=foo`` to access the" +" ``foo`` application), By default, the ``index`` application is opened " +"when no ``app`` URL parameter provided. When the ``index`` application " +"doesn't exist, PyWebIO will provide a default index application." +msgstr "" + +#: ../../advanced.rst:44 +msgid "Integration with web framework" +msgstr "" + +#: ../../advanced.rst:46 +msgid "" +"The PyWebIO application can be integrated into an existing Python Web " +"project, the PyWebIO application and the Web project share a web " +"framework. PyWebIO currently supports integration with Flask, Tornado, " +"Django, aiohttp and FastAPI(Starlette) web frameworks." +msgstr "" + +#: ../../advanced.rst:50 +msgid "The integration methods of those web frameworks are as follows:" +msgstr "" + +#: ../../advanced.rst:54 +msgid "Tornado" +msgstr "" + +#: ../../advanced.rst:58 +msgid "**Tornado**" +msgstr "" + +#: ../../advanced.rst:60 +msgid "" +"Use `pywebio.platform.tornado.webio_handler()` to get the " +"`WebSocketHandler " +"`_" +" class for running PyWebIO applications in Tornado::" +msgstr "" + +#: ../../advanced.rst:64 +msgid "" +"import tornado.ioloop\n" +"import tornado.web\n" +"from pywebio.platform.tornado import webio_handler\n" +"\n" +"class MainHandler(tornado.web.RequestHandler):\n" +" def get(self):\n" +" self.write(\"Hello, world\")\n" +"\n" +"if __name__ == \"__main__\":\n" +" application = tornado.web.Application([\n" +" (r\"/\", MainHandler),\n" +" (r\"/tool\", webio_handler(task_func)), # `task_func` is PyWebIO" +" task function\n" +" ])\n" +" application.listen(port=80, address='localhost')\n" +" tornado.ioloop.IOLoop.current().start()" +msgstr "" + +#: ../../advanced.rst:81 +msgid "" +"In above code, we add a routing rule to bind the ``WebSocketHandler`` of " +"the PyWebIO application to the ``/tool`` path. After starting the Tornado" +" server, you can visit ``http://localhost/tool`` to open the PyWebIO " +"application." +msgstr "" + +#: ../../advanced.rst:86 +msgid "" +"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 ` is an example of Nginx " +"WebSocket configuration." +msgstr "" + +#: ../../advanced.rst:90 +msgid "Flask" +msgstr "" + +#: ../../advanced.rst:94 +msgid "**Flask**" +msgstr "" + +#: ../../advanced.rst:96 +msgid "" +"Use `pywebio.platform.flask.webio_view()` to get the view function for " +"running PyWebIO applications in Flask::" +msgstr "" + +#: ../../advanced.rst:98 +msgid "" +"from pywebio.platform.flask import webio_view\n" +"from flask import Flask\n" +"\n" +"app = Flask(__name__)\n" +"\n" +"# `task_func` is PyWebIO task function\n" +"app.add_url_rule('/tool', 'webio_view', webio_view(task_func),\n" +" methods=['GET', 'POST', 'OPTIONS']) # need GET,POST and " +"OPTIONS methods\n" +"\n" +"app.run(host='localhost', port=80)" +msgstr "" + +#: ../../advanced.rst:110 +msgid "" +"In above code, we add a routing rule to bind the view function of the " +"PyWebIO application to the ``/tool`` path. After starting the Flask " +"application, visit ``http://localhost/tool`` to open the PyWebIO " +"application." +msgstr "" + +#: ../../advanced.rst:113 +msgid "Django" +msgstr "" + +#: ../../advanced.rst:117 +msgid "**Django**" +msgstr "" + +#: ../../advanced.rst:119 +msgid "" +"Use `pywebio.platform.django.webio_view()` to get the view function for " +"running PyWebIO applications in Django::" +msgstr "" + +#: ../../advanced.rst:121 +msgid "" +"# urls.py\n" +"\n" +"from django.urls import path\n" +"from pywebio.platform.django import webio_view\n" +"\n" +"# `task_func` is PyWebIO task function\n" +"webio_view_func = webio_view(task_func)\n" +"\n" +"urlpatterns = [\n" +" path(r\"tool\", webio_view_func),\n" +"]" +msgstr "" + +#: ../../advanced.rst:134 +msgid "" +"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" +msgstr "" + +#: ../../advanced.rst:137 +msgid "aiohttp" +msgstr "" + +#: ../../advanced.rst:141 +msgid "**aiohttp**" +msgstr "" + +#: ../../advanced.rst:143 +msgid "" +"Use `pywebio.platform.aiohttp.webio_handler()` to get the `Request " +"Handler `_ coroutine for running PyWebIO applications in aiohttp::" +msgstr "" + +#: ../../advanced.rst:147 +msgid "" +"from aiohttp import web\n" +"from pywebio.platform.aiohttp import webio_handler\n" +"\n" +"app = web.Application()\n" +"# `task_func` is PyWebIO task function\n" +"app.add_routes([web.get('/tool', webio_handler(task_func))])\n" +"\n" +"web.run_app(app, host='localhost', port=80)" +msgstr "" + +#: ../../advanced.rst:156 +msgid "" +"After starting the aiohttp server, visit ``http://localhost/tool`` to " +"open the PyWebIO application" +msgstr "" + +#: ../../advanced.rst:160 +msgid "" +"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 ` is an example of Nginx " +"WebSocket configuration." +msgstr "" + +#: ../../advanced.rst:165 +msgid "FastAPI/Starlette" +msgstr "" + +#: ../../advanced.rst:169 +msgid "**FastAPI/Starlette**" +msgstr "" + +#: ../../advanced.rst:171 +msgid "" +"Use `pywebio.platform.fastapi.webio_routes()` to get the " +"FastAPI/Starlette routes for running PyWebIO applications. You can mount " +"the routes to your FastAPI/Starlette app." +msgstr "" + +#: ../../advanced.rst:174 +msgid "FastAPI::" +msgstr "" + +#: ../../advanced.rst:176 +msgid "" +"from fastapi import FastAPI\n" +"from pywebio.platform.fastapi import webio_routes\n" +"\n" +"app = FastAPI()\n" +"\n" +"@app.get(\"/app\")\n" +"def read_main():\n" +" return {\"message\": \"Hello World from main app\"}\n" +"\n" +"# `task_func` is PyWebIO task function\n" +"app.mount(\"/tool\", FastAPI(routes=webio_routes(task_func)))" +msgstr "" + +#: ../../advanced.rst:188 +msgid "Starlette::" +msgstr "" + +#: ../../advanced.rst:190 +msgid "" +"from starlette.applications import Starlette\n" +"from starlette.responses import JSONResponse\n" +"from starlette.routing import Route, Mount\n" +"from pywebio.platform.fastapi import webio_routes\n" +"\n" +"async def homepage(request):\n" +" return JSONResponse({'hello': 'world'})\n" +"\n" +"app = Starlette(routes=[\n" +" Route('/', homepage),\n" +" Mount('/tool', routes=webio_routes(task_func)) # `task_func` is " +"PyWebIO task function\n" +"])" +msgstr "" + +#: ../../advanced.rst:203 +msgid "" +"After starting the server by using ``uvicorn :app`` , visit " +"``http://localhost:8000/tool/`` to open the PyWebIO application" +msgstr "" + +#: ../../advanced.rst:205 +msgid "" +"See also: `FastAPI doc `_ , `Starlette doc `_" +msgstr "" + +#: ../../advanced.rst:209 +msgid "" +"PyWebIO uses the WebSocket protocol to communicate with the browser in " +"FastAPI/Starlette. If your server is behind a reverse proxy (such as " +"Nginx), you may need to configure the reverse proxy to support the " +"WebSocket protocol. :ref:`Here ` is an example of Nginx " +"WebSocket configuration." +msgstr "" + +#: ../../advanced.rst:217 +msgid "Notes" +msgstr "" + +#: ../../advanced.rst:218 +msgid "**Deployment in production**" +msgstr "" + +#: ../../advanced.rst:220 +msgid "" +"In your production system, you may want to deploy the web applications " +"with some WSGI/ASGI servers such as uWSGI, Gunicorn, and Uvicorn. Since " +"PyWebIO applications store session state in memory of process, when you " +"use HTTP-based sessions (Flask and Django) and spawn multiple workers to " +"handle requests, the request may be dispatched to a process that does not" +" hold the session to which the request belongs. So you can only start one" +" worker to handle requests when using Flask or Django backend." +msgstr "" + +#: ../../advanced.rst:225 +msgid "" +"If you still want to use multiple processes to increase concurrency, one " +"way is to use Uvicorn+FastAPI, or you can also start multiple " +"Tornado/aiohttp processes and add external load balancer (such as HAProxy" +" or nginx) before them. Those backends use the WebSocket protocol to " +"communicate with the browser in PyWebIO, so there is no the issue as " +"described above." +msgstr "" + +#: ../../advanced.rst:229 +msgid "**Static resources Hosting**" +msgstr "" + +#: ../../advanced.rst:231 +msgid "" +"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``." +msgstr "" + +#: ../../advanced.rst:235 +msgid "" +"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 URL of PyWebIO " +"static resources directory." +msgstr "" + +#: ../../advanced.rst:238 +msgid "" +"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." +msgstr "" + +#: ../../advanced.rst:243 +msgid "" +"``start_server()`` and ``path_deploy()`` also support ``cdn`` parameter, " +"if it is set to ``False``, the static resource will be hosted in local " +"server automatically, without manual hosting." +msgstr "" + +#: ../../advanced.rst:250 +msgid "Coroutine-based session" +msgstr "" + +#: ../../advanced.rst:251 +msgid "" +"In most cases, you don’t need the coroutine-based session. All functions " +"or methods in PyWebIO that are only used for coroutine sessions are " +"specifically noted in the document." +msgstr "" + +#: ../../advanced.rst:254 +msgid "" +"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." +msgstr "" + +#: ../../advanced.rst:258 +msgid "" +"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." +msgstr "" + +#: ../../advanced.rst:264 +msgid "Using coroutine session" +msgstr "" + +#: ../../advanced.rst:266 +msgid "" +"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:" +msgstr "" + +#: ../../advanced.rst:269 +#, python-format +msgid "" +" from pywebio.input import *\n" +" from pywebio.output import *\n" +" from pywebio import start_server\n" +"\n" +" async def say_hello():\n" +" name = await input(\"what's your name?\")\n" +" put_text('Hello, %s' % name)\n" +"\n" +" start_server(say_hello, auto_open_webbrowser=True)" +msgstr "" + +#: ../../advanced.rst:283 +msgid "" +"In the coroutine task function, you can also use ``await`` to call other " +"coroutines or (`awaitable objects `_) in the standard library " +"`asyncio `_:" +msgstr "" + +#: ../../advanced.rst:287 +msgid "" +" import asyncio\n" +" from pywebio import start_server\n" +"\n" +" async def hello_word():\n" +" put_text('Hello ...')\n" +" await asyncio.sleep(1) # await awaitable objects in asyncio\n" +" put_text('... World!')\n" +"\n" +" async def main():\n" +" await hello_word() # await coroutine\n" +" put_text('Bye, bye')\n" +"\n" +" start_server(main, auto_open_webbrowser=True)" +msgstr "" + +#: ../../advanced.rst:306 +msgid "" +"In coroutine-based session, all input functions defined in the " +":doc:`pywebio.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." +msgstr "" + +#: ../../advanced.rst:309 +msgid "" +"Other functions that need to use ``await`` syntax in the coroutine " +"session are:" +msgstr "" + +#: ../../advanced.rst:311 +msgid "" +"`pywebio.session.run_asyncio_coroutine(coro_obj) " +"`" +msgstr "" + +#: ../../advanced.rst:312 +msgid "`pywebio.session.eval_js(expression) `" +msgstr "" + +#: ../../advanced.rst:316 +msgid "" +"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." +msgstr "" + +#: ../../advanced.rst:319 +msgid "" +"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** ::" +msgstr "" + +#: ../../advanced.rst:322 +msgid "" +"await asyncio.shield(pywebio.input())\n" +"await asyncio.gather(asyncio.sleep(1), pywebio.session.eval_js('1+1'))\n" +"task = asyncio.create_task(pywebio.input())" +msgstr "" + +#: ../../advanced.rst:329 +msgid "Concurrency in coroutine-based sessions" +msgstr "" + +#: ../../advanced.rst:331 +msgid "" +"In coroutine-based session, you can start new thread, but you cannot call" +" PyWebIO interactive functions in it (`register_thread() " +"` is not available in coroutine " +"session). But you can use `run_async(coro) ` " +"to execute a coroutine object asynchronously, and PyWebIO interactive " +"functions can be used in the new coroutine:" +msgstr "" + +#: ../../advanced.rst:336 +msgid "" +" from pywebio import start_server\n" +" from pywebio.session import run_async\n" +"\n" +" async def counter(n):\n" +" for i in range(n):\n" +" put_text(i)\n" +" await asyncio.sleep(1)\n" +"\n" +" async def main():\n" +" run_async(counter(10))\n" +" put_text('Main coroutine function exited.')\n" +"\n" +"\n" +" start_server(main, auto_open_webbrowser=True)" +msgstr "" + +#: ../../advanced.rst:355 +msgid "" +"`run_async(coro) ` returns a `TaskHandler " +"`, which can be used to query" +" the running status of the coroutine or close the coroutine." +msgstr "" + +#: ../../advanced.rst:359 +msgid "Close of session" +msgstr "" + +#: ../../advanced.rst:361 +msgid "" +"Similar to thread-based session, when user close the browser page, the " +"session will be closed." +msgstr "" + +#: ../../advanced.rst:363 +msgid "" +"After the browser page closed, PyWebIO input function calls that have not" +" yet returned in the current session will cause `SessionClosedException " +"`, and subsequent calls to " +"PyWebIO interactive functions will cause `SessionNotFoundException " +"` or `SessionClosedException" +" `." +msgstr "" + +#: ../../advanced.rst:368 +msgid "" +"`defer_call(func) ` also available in " +"coroutine session." +msgstr "" + +#: ../../advanced.rst:373 +msgid "Integration with Web Framework" +msgstr "" + +#: ../../advanced.rst:375 +msgid "" +"The PyWebIO application that using coroutine-based session can also be " +"integrated to the web framework." +msgstr "" + +#: ../../advanced.rst:377 +msgid "" +"However, there are some limitations when using coroutine-based sessions " +"to integrate into Flask or Django:" +msgstr "" + +#: ../../advanced.rst:379 +msgid "" +"First, when ``await`` the coroutine objects/awaitable objects in the " +"``asyncio`` module, you need to use `run_asyncio_coroutine() " +"` to wrap the coroutine object." +msgstr "" + +#: ../../advanced.rst:382 +msgid "" +"Secondly, you need to start a new thread to run the event loop before " +"starting a Flask/Django server." +msgstr "" + +#: ../../advanced.rst:384 +msgid "Example of coroutine-based session integration into Flask:" +msgstr "" + +#: ../../advanced.rst:386 +msgid "" +" import asyncio\n" +" import threading\n" +" from flask import Flask, send_from_directory\n" +" from pywebio import STATIC_PATH\n" +" from pywebio.output import *\n" +" from pywebio.platform.flask import webio_view\n" +" from pywebio.platform import run_event_loop\n" +" from pywebio.session import run_asyncio_coroutine\n" +"\n" +" async def hello_word():\n" +" put_text('Hello ...')\n" +" await run_asyncio_coroutine(asyncio.sleep(1)) # can't just \"await " +"asyncio.sleep(1)\"\n" +" put_text('... World!')\n" +"\n" +" app = Flask(__name__)\n" +" app.add_url_rule('/hello', 'webio_view', webio_view(hello_word),\n" +" methods=['GET', 'POST', 'OPTIONS'])\n" +"\n" +" # thread to run event loop\n" +" threading.Thread(target=run_event_loop, daemon=True).start()\n" +" app.run(host='localhost', port=80)" +msgstr "" + +#: ../../advanced.rst:411 +msgid "" +"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." +msgstr "" + diff --git a/docs/locales/fa/LC_MESSAGES/arch.po b/docs/locales/fa/LC_MESSAGES/arch.po new file mode 100644 index 00000000..2100fdb4 --- /dev/null +++ b/docs/locales/fa/LC_MESSAGES/arch.po @@ -0,0 +1,509 @@ +# Copyright (C) Weimin Wang +# This file is distributed under the same license as the PyWebIO package. +# +# FIRST AUTHOR , 2022. +# Pikhosh , 2022. +msgid "" +msgstr "" +"Project-Id-Version: PyWebIO 1.5.2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-02-26 16:35+0330\n" +"PO-Revision-Date: 2022-02-28 14:20+0330\n" +"Last-Translator: Pikhosh \n" +"Language-Team: Persian <>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.9.1\n" +"Language: fa\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Lokalize 21.12.2\n" + +#: ../../arch.rst:2 +msgid "Architecture" +msgstr "" + +#: ../../arch.rst:5 +msgid "概念" +msgstr "" + +#: ../../arch.rst:7 +msgid "``Session`` 表示浏览器与程序交互产生的一次会话。PyWebIO在会话中运行 ``Task`` ,任务是" +msgstr "" + +#: ../../arch.rst:9 +msgid "会话中除了起始的执行单元,也可以并发启动新的执行单元,在新的执行单元中也可以进行输入输出。" +msgstr "" + +#: ../../arch.rst:11 +msgid "在用户端,相同会话中的不同的执行单元的输入是独立的,共享输出空间,但输出域的栈结构各自独立。" +msgstr "" + +#: ../../arch.rst:13 +msgid "" +"若用户正在填写一个执行单元的表单,会话中的其他执行单元也开始向用户请求输入,此时用户正在填写的表单将会隐藏, " +"新的输入表单将会显示给用户,当用户填写完新表单并提交后,旧表单重新显示,之前在旧表单上的输入也会保留。" +msgstr "" + +#: ../../arch.rst:16 +msgid "在基于线程的会话中,会话中的每个执行单元都是一个线程" +msgstr "" + +#: ../../arch.rst:18 +msgid "在基于协程的会话中,会话中的每个执行单元都是一个协程" +msgstr "" + +#: ../../arch.rst:20 +msgid "除了并发执行的执行单元,会话中还有事件回调函数,目前就只有按钮控件可以绑定点击事件的回调函数。" +msgstr "" + +#: ../../arch.rst:23 +msgid "架构" +msgstr "" + +#: ../../arch.rst:25 +msgid "" +"会话内的每个执行单元使用唯一的task_id进行标识,由于会话内的输入需要区分执行单元,所以每个表单提交时, " +"除了表单的内容以外,还会携带表单所在的执行单元的task_id,这样,后台会话才可以知道该将表单数据传递给哪个执行单元。" +msgstr "" + +#: ../../arch.rst:31 +msgid "" +"PyWebIO会话是由事件驱动的,这些事件来自用户在页面上的操作,比如提交表单,点击按钮,这些事件会通过http请求或websocket连接发送到后端框架。" +msgstr "" + +#: ../../arch.rst:33 +msgid "" +"后端框架维护有当前在线的Session实例,后端框架在收到用户提交的事件后,回调用相关Session实例的 " +"``send_client_event()`` 方法将事件发送至会话;" +msgstr "" + +#: ../../arch.rst:35 +msgid "" +"一个会话内会拥有至少一个执行单元,执行单元在调用PyWebIO的输入函数后会临时挂起,当会话收到用户的输入提交后,会话便将执行单元恢复执行,并提供用户输入的" +"值。" +" 执行单元内,任何输入输出的调用都会转换成一些命令序列发送给会话." +msgstr "" + +#: ../../arch.rst:38 +msgid "" +"当后端框架通过HTTP与用户浏览器通信时,用户浏览器是以轮训的方式获取指令,会话会保存由执行单元生成的、还未发送到浏览器的命令序列,等待下次轮训时由后端框架" +"取走。" +msgstr "" + +#: ../../arch.rst:40 +msgid "" +"当后端框架通过WebSocket与用户建立连接时,任何由执行单元发送到会话的命令都会立即发送到后端,并由后端通过WebSocket连接通知用户浏览器。" +msgstr "" + +#: ../../arch.rst:43 +msgid "实现" +msgstr "" + +#: ../../arch.rst:46 +msgid "后端与Session的交互" +msgstr "" + +#: ../../arch.rst:48 +msgid "后端框架负责从Session会话中获取来自PyWebIO的指令,并发送给用户浏览器;同时后端框架接收用户提交的数据,并发送给相应的会话实例。" +msgstr "" + +#: ../../arch.rst:50 +msgid "" +"Session暴露给后端框架的方法仅有 `Session.send_client_event " +"` 、 " +"`Session.get_task_commands " +"` 和 `Session.close " +"` 。" +msgstr "" + +#: ../../arch.rst:54 +msgid "基于HTTP通信的后端的实现逻辑" +msgstr "" + +#: ../../arch.rst:56 +msgid "**基于HTTP的前后端通信约定**" +msgstr "" + +#: ../../arch.rst:58 +msgid "前端按照固定间隔使用GET请求轮训后端接口,在请求中使用 ``webio-session-id`` HTTP头来传递会话ID。" +msgstr "" + +#: ../../arch.rst:60 +msgid "" +"会话一开始时,会话ID由后端生成并通过响应中的 ``webio-session-id`` HTTP头返回给前端,后续前端的请求都会在请求头中使用 " +"``webio-session-id`` 字段传递会话ID。" +msgstr "" + +#: ../../arch.rst:62 +msgid "" +"前端产生的事件使用POST请求发送给后端。对于前端的每次轮训和事件提交请求,后端都会返回当前未执行的指令序列作为响应,前端收到响应后会依次执行指令。" +msgstr "" + +#: ../../arch.rst:64 ../../arch.rst:93 +msgid "**代码实现**" +msgstr "" + +#: ../../arch.rst:66 +msgid "" +"以Flask后端为例,Flask后端与Session的交互都在Flask视图函数中实现,视图函数通过调用 " +"`pywebio.platform.flask.webio_view " +"<./_modules/pywebio/platform/flask.html#webio_view>`_ 获取, 在 `webio_view` " +"中,先是实例化了一个 `pywebio.platform.httpbased.HttpHandler` " +",然后声明了一个内部函数,这个内部函数就是Flask视图函数, 在视图函数内,先是实例化了一个 " +"`pywebio.platform.flask.FlaskHttpContext` 对象,然后通过调用 " +"``HttpHandler.handle_request(FlaskHttpContext)`` 就获得了视图的响应。" +msgstr "" + +#: ../../arch.rst:70 +msgid "" +"这其中,FlaskHttpContext 的基类为 HttpContext ,HttpContext " +"接口各异的后端框架定义了一个统一的操作接口,用于从当前请求中获取请求相关的数据并设置请求的相应。 FlaskHttpContext " +"为HttpContext接口的Flask实现。" +msgstr "" + +#: ../../arch.rst:72 +msgid "" +"而 HttpHandle 负责维护Session实例并实现HTTP请求与Session之间的交互,HttpHandle " +"与后端框架相关的交互全都通过 HttpContext 操作。" +msgstr "" + +#: ../../arch.rst:74 +msgid "HttpContext的生命周期为一次HTTP请求,HttpHandle的生命周期和整个后端框架的生命周期一致。" +msgstr "" + +#: ../../arch.rst:76 +msgid "" +"HttpHandler.handle_request 负责处理前端发送给后端的每一次请求,HttpHandler.handle_request " +"的处理流程如下:" +msgstr "" + +#: ../../arch.rst:78 +msgid "检测当前HTTP请求是否满足跨域设置" +msgstr "" + +#: ../../arch.rst:79 +msgid "" +"根绝当前请求的 webio-session-id 头信息找到相应的Session实例,若不存在 webio-session-id " +"头则创建新会话并分配webio-session-id" +msgstr "" + +#: ../../arch.rst:80 +msgid "若当前请求为POST事件提交请求,则将提交的数据通过 Session.send_client_event 发送给Session" +msgstr "" + +#: ../../arch.rst:81 +msgid "通过调用 Session.get_task_commands 获取待执行的指令序列,并通过 HttpContext 向后端设置响应数据" +msgstr "" + +#: ../../arch.rst:83 +msgid "" +"此外,基于HTTP的会话,用户主动关闭会话时(比如关闭浏览器),后端无法立即感知,所以在HttpHandler.handle_request 中," +" 还会周期性地检测会话的最后活跃时间,将一段时间内不活跃的会话视为过期,所以在HttpHandler清理过期会话并调用 Session.close" +" 释放会话内的资源。" +msgstr "" + +#: ../../arch.rst:88 +msgid "基于WebSocket通信的后端的实现逻辑" +msgstr "" + +#: ../../arch.rst:89 +msgid "**基于WebSocket的前后端通信约定:**" +msgstr "" + +#: ../../arch.rst:91 +msgid "" +"浏览器与后端使用一个WebSocket连接来保持一个会话,后端的指令通过JSON序列化之后的消息实时发送给前端,前端用户触发的事件数据也通过JSON序列化之" +"后发送给后端。" +msgstr "" + +#: ../../arch.rst:95 +msgid "以Tornado后端为例" +msgstr "" + +#: ../../arch.rst:97 +msgid "" +"webio_handler用于获取Tornado与前端进行通信的WebSocketHandler子类,其逻辑实现在 _webio_handler " +"中,由于WebSocket的有状态性, " +"WebSocketHandler子类的实现比基于HTTP通信的HttpHandler要简单许多,关键部分如下:" +msgstr "" + +#: ../../arch.rst:100 +msgid "" +"在WebSocket连接创建的时候初始化Session实例,并向Session对象注册了 " +"on_task_command和on_session_close 回调,分别在新指令产生时和会话由执行单元关闭时由Session调用, " +"用于实现WebSocketHandler向前端实时发送指令" +msgstr "" + +#: ../../arch.rst:102 +msgid "" +"在收到前端浏览器发送来的消息后,WebSocketHandler将收到的数据通过 Session.send_client_event " +"发送给Session" +msgstr "" + +#: ../../arch.rst:103 +msgid "在WebSocket连接关闭时,调用 Session.close 释放会话内的资源。" +msgstr "" + +#: ../../arch.rst:106 +msgid "session与执行单元(输入/输出)的交互" +msgstr "" + +#: ../../arch.rst:108 +msgid "会话提供给执行单元的关键接口有:" +msgstr "" + +#: ../../arch.rst:110 +msgid "get_current_session : 静态方法,获取当前执行单元所属的会话实例" +msgstr "" + +#: ../../arch.rst:111 +msgid "get_current_task_id : 静态方法,获取当前执行单元所属的id" +msgstr "" + +#: ../../arch.rst:112 +msgid "send_task_command : 向会话发送指令" +msgstr "" + +#: ../../arch.rst:113 +msgid "next_client_event : 读取来自浏览器的属于当前执行单元的下一个事件" +msgstr "" + +#: ../../arch.rst:114 +msgid "register_callback : 向会话注册一个回调" +msgstr "" + +#: ../../arch.rst:116 +msgid "同时,会话根据实现方式不同,还分别提供了 register_thread 和 run_async 用于启动新的执行单元。" +msgstr "" + +#: ../../arch.rst:119 +msgid "**回调机制**" +msgstr "" + +#: ../../arch.rst:121 +msgid "" +"在会话中,为了能够响应用户在界面上的某些事件(比如点击了输出内容中的某个按钮),于是设计了回调机制,可以在执行单元中使用register_callback向" +"当前会话注册回调,然后执行单元会得到一个回调ID," +" 执行单元再通过相关指令让浏览器输出一些可以触发的控件,并向控件绑定回调ID,当用户触发控件后,前端将带有回调ID的 :ref:`回调事件 " +"` 发回会话,会话会在专门的执行单元中或启动新执行单元中运行回调。" +msgstr "" + +#: ../../arch.rst:125 +msgid "基于线程的会话实现" +msgstr "" + +#: ../../arch.rst:127 +msgid "" +"在基于线程的会话中,每个执行单元都是一个线程,每个执行单元通过一条消息队列从会话接收来自用户的事件消息,当执行单元所需要的事件用户还没有提交时,执行单元便会" +"挂起。" +msgstr "" + +#: ../../arch.rst:129 +msgid "" +"基于线程的会话使用线程ID作为执行单元的ID,在全局使用一个以线程id为key的字典来映射执行单元所属的会话实例,会话内不同执行单元的用户事件消息队列也通过" +"执行单元ID进行索引。" +msgstr "" + +#: ../../arch.rst:131 +msgid "使用 register_thread 启动新的执行单元时,也需要为新执行单元注册用户事件消息队列。" +msgstr "" + +#: ../../arch.rst:134 +msgid "基于协程的会话实现" +msgstr "" + +#: ../../arch.rst:135 +msgid "" +"在基于协程的会话中,每个执行单元都是一个由协程包装成的任务对象(Task),当会话接收来自用户的事件消息后,便激活相应的任务对象,使得协程恢复运行。" +msgstr "" + +#: ../../arch.rst:137 +msgid "" +"由于基于协程的会话是单线程的,所以会话在激活任务对象前是通过将上下文信息保存在全局变量中来实现 get_current_session 和 " +"get_current_task_id 方法,全局的上下文信息包含当前将要执行的会话的实例和执行单元的ID。" +msgstr "" + +#: ../../arch.rst:141 +msgid "Script mode的实现" +msgstr "" + +#: ../../arch.rst:142 +msgid "" +"Script mode " +"也是基于线程的,但由于全局仅存在一个会话,所有执行单元必定全部属于这个会话,所以也无需主动调用register_thread(thread)注册线程。" +msgstr "" + +#: ../../arch.rst:144 +msgid "当PyWebIO检测到用户代码在后端Server还未启动的情况下就调用了PyWebIO交互函数时,便会启动Script mode:" +msgstr "" + +#: ../../arch.rst:146 +msgid "在新线程中启动后端Server" +msgstr "" + +#: ../../arch.rst:147 +msgid "启动浏览器打开后端Server运行的地址" +msgstr "" + +#: ../../arch.rst:148 +msgid "在第一次与用户建立连接时初始化会话" +msgstr "" + +#: ../../arch.rst:150 +msgid "script mode的会话类继承了基于线程的会话类,并修改了部分方法:" +msgstr "" + +#: ../../arch.rst:152 +msgid "构造函数 : 仅允许script mode会话类被初始化一次" +msgstr "" + +#: ../../arch.rst:153 +msgid "get_current_session : 直接返回全局的会话对象" +msgstr "" + +#: ../../arch.rst:154 +msgid "get_current_task_id : 除了返回当前线程id,还会自动将当前线程使用 register_thread 注册到会话中" +msgstr "" + +#: ../../arch.rst:157 +msgid "相关对象的文档" +msgstr "" + +#: of pywebio.platform.httpbased.HttpHandler:1 +msgid "基于HTTP的后端Handler实现" +msgstr "" + +#: of pywebio.platform.httpbased.HttpHandler:4 +msgid "" +"Don't need a lock when access HttpHandler._webio_sessions, See: " +"https://stackoverflow.com/questions/1312331/using-a-global-dictionary-" +"with-threads-in-python" +msgstr "" + +#: of pywebio.platform.httpbased.HttpHandler.handle_request_context:1 +msgid "called when every http request" +msgstr "" + +#: of pywebio.session.base.Session:1 +msgid "会话对象,由Backend创建" +msgstr "" + +#: of pywebio.session.base.Session:5 +msgid "属性:" +msgstr "" + +#: of pywebio.session.base.Session:4 +msgid "info 表示会话信息的对象 save 会话的数据对象,提供用户在对象上保存一些会话相关数据" +msgstr "" + +#: of pywebio.session.base.Session:20 +msgid "由Task在当前Session上下文中调用:" +msgstr "" + +#: of pywebio.session.base.Session:8 +msgid "get_current_session get_current_task_id" +msgstr "" + +#: of pywebio.session.base.Session:11 +msgid "" +"get_scope_name pop_scope push_scope send_task_command next_client_event " +"on_task_exception register_callback need_keep_alive" +msgstr "" + +#: of pywebio.session.base.Session:20 +msgid "defer_call" +msgstr "" + +#: of pywebio.session.base.Session:25 +msgid "由Backend调用:" +msgstr "" + +#: of pywebio.session.base.Session:23 +msgid "send_client_event get_task_commands close" +msgstr "" + +#: of pywebio.session.base.Session:28 +msgid "Task和Backend都可调用:" +msgstr "" + +#: of pywebio.session.base.Session:28 +msgid "closed" +msgstr "" + +#: of pywebio.session.base.Session:33 +msgid "Session是不同的后端Backend与协程交互的桥梁:" +msgstr "" + +#: of pywebio.session.base.Session:31 +msgid "" +"后端Backend在接收到用户浏览器的数据后,会通过调用 ``send_client_event`` " +"来通知会话,进而由Session驱动协程的运行。 Task内在调用输入输出函数后,会调用 ``send_task_command`` " +"向会话发送输入输出消息指令, Session将其保存并留给后端Backend处理。" +msgstr "" + +#: of pywebio.session.base.Session.get_scope_name:1 +msgid "获取当前任务的scope栈检索scope名" +msgstr "" + +#: of pywebio.session.base.Session.close +#: pywebio.session.base.Session.defer_call +#: pywebio.session.base.Session.get_scope_name +msgid "Parameters" +msgstr "پارامتر ها" + +#: of pywebio.session.base.Session.get_scope_name:3 +msgid "scope栈的索引" +msgstr "" + +#: of pywebio.session.base.Session.get_scope_name +#: pywebio.session.base.Session.pop_scope +msgid "Returns" +msgstr "" + +#: of pywebio.session.base.Session.get_scope_name:4 +msgid "scope名,不存在时返回 None" +msgstr "" + +#: of pywebio.session.base.Session.pop_scope:1 +msgid "弹出当前scope" +msgstr "" + +#: of pywebio.session.base.Session.pop_scope:3 +msgid "当前scope名" +msgstr "" + +#: of pywebio.session.base.Session.push_scope:1 +msgid "进入新scope" +msgstr "" + +#: of pywebio.session.base.Session.next_client_event:1 +msgid "获取来自客户端的下一个事件。阻塞调用,若在等待过程中,会话被用户关闭,则抛出SessionClosedException异常" +msgstr "" + +#: of pywebio.session.base.Session.close:1 +msgid "Close current session" +msgstr "" + +#: of pywebio.session.base.Session.close:3 +msgid "Don't block thread. Used in closing from backend." +msgstr "" + +#: of pywebio.session.base.Session.register_callback:1 +msgid "向Session注册一个回调函数,返回回调id" +msgstr "" + +#: of pywebio.session.base.Session.register_callback:3 +msgid "" +"Session需要保证当收到前端发送的事件消息 ``{event: \"callback\",task_id: 回调id, data:...}``" +" 时, ``callback`` 回调函数被执行, 并传入事件消息中的 ``data`` 字段值作为参数" +msgstr "" + +#: of pywebio.session.base.Session.defer_call:1 +msgid "设置会话结束时调用的函数。可以用于资源清理。 在会话中可以多次调用 `defer_call()` ,会话结束后将会顺序执行设置的函数。" +msgstr "" + +#: of pywebio.session.base.Session.defer_call:4 +msgid "话结束时调用的函数" +msgstr "" + diff --git a/docs/locales/fa/LC_MESSAGES/cookbook.po b/docs/locales/fa/LC_MESSAGES/cookbook.po new file mode 100644 index 00000000..30e4e634 --- /dev/null +++ b/docs/locales/fa/LC_MESSAGES/cookbook.po @@ -0,0 +1,455 @@ +# Copyright (C) Weimin Wang +# This file is distributed under the same license as the PyWebIO package. +# +# FIRST AUTHOR , 2022. +# Pikhosh , 2022. +msgid "" +msgstr "" +"Project-Id-Version: PyWebIO 1.5.2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-02-26 16:35+0330\n" +"PO-Revision-Date: 2022-02-28 12:33+0330\n" +"Last-Translator: Pikhosh \n" +"Language-Team: Persian <>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.9.1\n" +"Language: fa\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Lokalize 21.12.2\n" + +#: ../../cookbook.rst:2 +msgid "Cookbook" +msgstr "دستور های پخت" + +#: ../../cookbook.rst:8 +msgid "Interaction related" +msgstr "" + +#: ../../cookbook.rst:11 +msgid "Equivalent to \"Press any key to continue\"" +msgstr "" + +#: ../../cookbook.rst:13 +msgid "" +"actions(buttons=[\"Continue\"])\n" +"put_text(\"Go next\") # ..demo-only" +msgstr "" + +#: ../../cookbook.rst:22 +msgid "Output pandas dataframe" +msgstr "" + +#: ../../cookbook.rst:24 +msgid "" +"import numpy as np\n" +"import pandas as pd\n" +"\n" +"df = pd.DataFrame(np.random.randn(6, 4), columns=list(\"ABCD\"))\n" +"put_html(df.to_html(border=0))" +msgstr "" + +#: ../../cookbook.rst:34 +msgid "" +"`pandas.DataFrame.to_html — pandas documentation " +"`_" +msgstr "" + +#: ../../cookbook.rst:37 +msgid "Output Matplotlib figure" +msgstr "" + +#: ../../cookbook.rst:39 +msgid "" +"Simply do not call ``matplotlib.pyplot.show``, directly save the figure " +"to in-memory buffer and output the buffer via " +":func:`pywebio.output.put_image`:" +msgstr "" + +#: ../../cookbook.rst:42 +msgid "" +"import matplotlib\n" +"import matplotlib.pyplot as plt\n" +"import io\n" +"import pywebio\n" +"\n" +"matplotlib.use('agg') # required, use a non-interactive backend\n" +"\n" +"fig, ax = plt.subplots() # Create a figure containing a single axes.\n" +"ax.plot([1, 2, 3, 4], [1, 4, 2, 3]) # Plot some data on the axes.\n" +"\n" +"buf = io.BytesIO()\n" +"fig.savefig(buf)\n" +"pywebio.output.put_image(buf.getvalue())" +msgstr "" + +#: ../../cookbook.rst:60 +msgid "" +"The ``matplotlib.use('agg')`` is required so that the server does not try" +" to create (and then destroy) GUI windows that will never be seen." +msgstr "" + +#: ../../cookbook.rst:63 +msgid "" +"When using Matplotlib in a web server (multiple threads environment), " +"pyplot may cause some conflicts in some cases, read the following " +"articles for more information:" +msgstr "" + +#: ../../cookbook.rst:66 +msgid "" +"`Multi Threading in Python and Pyplot | by Ranjitha Korrapati | Medium " +"`_" +msgstr "" + +#: ../../cookbook.rst:68 +msgid "" +"`Embedding in a web application server (Flask) — Matplotlib documentation" +" " +"`_" +msgstr "" + +#: ../../cookbook.rst:72 +msgid "Blocking confirm model" +msgstr "" + +#: ../../cookbook.rst:74 +msgid "" +"The following code uses the lock mechanism to make the button callback " +"function synchronous:" +msgstr "" + +#: ../../cookbook.rst:78 +msgid "" +"import threading\n" +"from pywebio import output\n" +"\n" +"def confirm(title, content=None, timeout=None):\n" +" \"\"\"Show a confirm model.\n" +"\n" +" :param str title: Model title.\n" +" :param list/put_xxx() content: Model content.\n" +" :param None/float timeout: Seconds for operation time out.\n" +" :return: Return `True` when the \"CONFIRM\" button is clicked,\n" +" return `False` when the \"CANCEL\" button is clicked,\n" +" return `None` when a timeout is given and the operation times " +"out.\n" +" \"\"\"\n" +" if not isinstance(content, list):\n" +" content = [content]\n" +"\n" +" event = threading.Event()\n" +" result = None\n" +"\n" +" def onclick(val):\n" +" nonlocal result\n" +" result = val\n" +" event.set()\n" +"\n" +" content.append(output.put_buttons([\n" +" {'label': 'CONFIRM', 'value': True},\n" +" {'label': 'CANCEL', 'value': False, 'color': 'danger'},\n" +" ], onclick=onclick))\n" +" output.popup(title=title, content=content, closable=False)\n" +"\n" +" event.wait(timeout=timeout) # wait the model buttons are clicked\n" +" output.close_popup()\n" +" return result\n" +"\n" +"\n" +"res = confirm('Confirm', 'You have 5 seconds to make s choice', " +"timeout=5)\n" +"output.put_text(\"Your choice is:\", res)" +msgstr "" + +#: ../../cookbook.rst:121 +msgid "Input in the popup" +msgstr "" + +#: ../../cookbook.rst:124 +msgid "" +"In the following code, we define a ``popup_input()`` function, which can " +"be used to get input in popup:" +msgstr "" + +#: ../../cookbook.rst:128 +msgid "" +"def popup_input(pins, names, title='Please fill out the form'):\n" +" \"\"\"Show a form in popup window.\n" +"\n" +" :param list pins: pin output list.\n" +" :param list pins: pin name list.\n" +" :param str title: model title.\n" +" :return: return the form as dict, return None when user cancel the " +"form.\n" +" \"\"\"\n" +" if not isinstance(pins, list):\n" +" pins = [pins]\n" +"\n" +" from pywebio.utils import random_str\n" +" action_name = 'action_' + random_str(10)\n" +"\n" +" pins.append(put_actions(action_name, buttons=[\n" +" {'label': 'Submit', 'value': True},\n" +" {'label': 'Cancel', 'value': False, 'color': 'danger'},\n" +" ]))\n" +" popup(title=title, content=pins, closable=False)\n" +"\n" +" change_info = pin_wait_change(action_name)\n" +" result = None\n" +" if change_info['name'] == action_name and change_info['value']:\n" +" result = {name: pin[name] for name in names}\n" +" close_popup()\n" +" return result\n" +"\n" +"\n" +"from pywebio.pin import put_input\n" +"\n" +"result = popup_input([\n" +" put_input('name', label='Input your name'),\n" +" put_input('age', label='Input your age', type=\"number\")\n" +"], names=['name', 'age'])\n" +"put_text(result)" +msgstr "" + +#: ../../cookbook.rst:168 +msgid "" +"The code uses :doc:`pin module ` to add input widgets to popup " +"window, and uses the lock mechanism to wait the form buttons to be " +"clicked." +msgstr "" + +#: ../../cookbook.rst:173 +msgid "Redirect stdout to PyWebIO application" +msgstr "" + +#: ../../cookbook.rst:176 +msgid "" +"The following code shows how to redirect stdout of python code and " +"subprocess to PyWebIO application:" +msgstr "" + +#: ../../cookbook.rst:180 +msgid "" +"import io\n" +"import time\n" +"import subprocess # ..doc-only\n" +"from contextlib import redirect_stdout\n" +"\n" +"# redirect `print()` to pywebio\n" +"class WebIO(io.IOBase):\n" +" def write(self, content):\n" +" put_text(content, inline=True)\n" +"\n" +"with redirect_stdout(WebIO()):\n" +" for i in range(10):\n" +" print(i, time.time())\n" +" time.sleep(0.2)\n" +"\n" +"## ----\n" +"import subprocess # ..demo-only\n" +"# redirect a subprocess' stdout to pywebio\n" +"process = subprocess.Popen(\"ls -ahl\", shell=True, " +"stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n" +"while True:\n" +" output = process.stdout.readline()\n" +" if output:\n" +" put_text(output.decode('utf8'), inline=True)\n" +"\n" +" if not output and process.poll() is not None:\n" +" break" +msgstr "" + +#: ../../cookbook.rst:213 +msgid "Add missing syntax highlight for code output" +msgstr "" + +#: ../../cookbook.rst:215 +msgid "" +"When output code via `put_markdown()` or `put_code()`, PyWebIO provides " +"syntax highlight for some common languages. If you find your code have no" +" syntax highlight, you can add the syntax highlighter by two following " +"steps:" +msgstr "" + +#: ../../cookbook.rst:218 +msgid "" +"Go to `prismjs CDN page " +"`_" +" to get your syntax highlighter link." +msgstr "" + +#: ../../cookbook.rst:219 +msgid "" +"Use :func:`config(js_file=...) ` to load the syntax " +"highlight module" +msgstr "" + +#: ../../cookbook.rst:223 +msgid "" +"@config(js_file=\"https://cdn.jsdelivr.net/npm/prismjs@1.23.0/components" +"/prism-diff.min.js\")\n" +"def main():\n" +" put_code(\"\"\"\n" +"+ AAA\n" +"- BBB\n" +"CCC\n" +" \"\"\".strip(), language='diff')\n" +"\n" +" put_markdown(\"\"\"\n" +" ```diff\n" +" + AAA\n" +" - BBB\n" +" CCC\n" +" ```\n" +" \"\"\", lstrip=True)" +msgstr "" + +#: ../../cookbook.rst:242 +msgid "Web application related" +msgstr "" + +#: ../../cookbook.rst:245 +msgid "Get URL parameters of current page" +msgstr "" + +#: ../../cookbook.rst:247 +msgid "" +"You can use URL parameter (known also as \"query strings\" or \"URL query" +" parameters\") to pass information to your web application. In PyWebIO " +"application, you can use the following code to get the URL parameters as " +"a Python dict." +msgstr "" + +#: ../../cookbook.rst:250 +msgid "" +"# `query` is a dict\n" +"query = eval_js(\"Object.fromEntries(new " +"URLSearchParams(window.location.search))\")\n" +"put_text(query)" +msgstr "" + +#: ../../cookbook.rst:260 +msgid "Add Google AdSense/Analytics code" +msgstr "" + +#: ../../cookbook.rst:262 +msgid "" +"When you setup Google AdSense/Analytics, you will get a javascript file " +"and a piece of code that needs to be inserted into your application page," +" you can use :func:`pywebio.config()` to inject js file and code to your " +"PyWebIO application::" +msgstr "" + +#: ../../cookbook.rst:265 +msgid "" +"from pywebio import start_server, output, config\n" +"\n" +"js_file = \"https://www.googletagmanager.com/gtag/js?id=G-xxxxxxx\"\n" +"js_code = \"\"\"\n" +"window.dataLayer = window.dataLayer || [];\n" +"function gtag(){dataLayer.push(arguments);}\n" +"gtag('js', new Date());\n" +"\n" +"gtag('config', 'G-xxxxxxx');\n" +"\"\"\"\n" +"\n" +"@config(js_file=js_file, js_code=js_code)\n" +"def main():\n" +" output.put_text(\"hello world\")\n" +"\n" +"start_server(main, port=8080)" +msgstr "" + +#: ../../cookbook.rst:284 +msgid "Refresh page on connection lost" +msgstr "" + +#: ../../cookbook.rst:286 +msgid "" +"Add the following code to the beginning of your PyWebIO application main " +"function::" +msgstr "" + +#: ../../cookbook.rst:288 +msgid "" +"session.run_js('WebIO._state.CurrentSession.on_session_close(()=" +">{setTimeout(()=>location.reload()," +" 4000})')" +msgstr "" + +#: ../../cookbook.rst:291 +msgid "Cookie and localStorage manipulation" +msgstr "" + +#: ../../cookbook.rst:294 +msgid "" +"You can use `pywebio.session.run_js()` and `pywebio.session.eval_js()` to" +" deal with cookies or localStorage with js." +msgstr "" + +#: ../../cookbook.rst:296 +msgid "``localStorage`` manipulation:" +msgstr "" + +#: ../../cookbook.rst:298 +msgid "" +"set_localstorage = lambda key, value: run_js(\"localStorage.setItem(key, " +"value)\", key=key, value=value)\n" +"get_localstorage = lambda key: eval_js(\"localStorage.getItem(key)\", " +"key=key)\n" +"\n" +"set_localstorage('hello', 'world')\n" +"val = get_localstorage('hello')\n" +"put_text(val)" +msgstr "" + +#: ../../cookbook.rst:310 +msgid "Cookie manipulation:" +msgstr "" + +#: ../../cookbook.rst:314 +msgid "" +"# https://stackoverflow.com/questions/14573223/set-cookie-and-get-cookie-" +"with-javascript\n" +"run_js(\"\"\"\n" +"window.setCookie = function(name,value,days) {\n" +" var expires = \"\";\n" +" if (days) {\n" +" var date = new Date();\n" +" date.setTime(date.getTime() + (days*24*60*60*1000));\n" +" expires = \"; expires=\" + date.toUTCString();\n" +" }\n" +" document.cookie = name + \"=\" + (value || \"\") + expires + \"; " +"path=/\";\n" +"}\n" +"window.getCookie = function(name) {\n" +" var nameEQ = name + \"=\";\n" +" var ca = document.cookie.split(';');\n" +" for(var i=0;i < ca.length;i++) {\n" +" var c = ca[i];\n" +" while (c.charAt(0)==' ') c = c.substring(1,c.length);\n" +" if (c.indexOf(nameEQ) == 0) return " +"c.substring(nameEQ.length,c.length);\n" +" }\n" +" return null;\n" +"}\n" +"\"\"\")\n" +"\n" +"def setcookie(key, value, days=0):\n" +" run_js(\"setCookie(key, value, days)\", key=key, value=value, " +"days=days)\n" +"\n" +"def getcookie(key):\n" +" return eval_js(\"getCookie(key)\", key=key)\n" +"\n" +"setcookie('hello', 'world')\n" +"val = getcookie('hello')\n" +"put_text(val)" +msgstr "" + diff --git a/docs/locales/fa/LC_MESSAGES/exceptions.po b/docs/locales/fa/LC_MESSAGES/exceptions.po new file mode 100644 index 00000000..9f9706f3 --- /dev/null +++ b/docs/locales/fa/LC_MESSAGES/exceptions.po @@ -0,0 +1,43 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) Weimin Wang +# This file is distributed under the same license as the PyWebIO package. +# FIRST AUTHOR , 2022. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PyWebIO 1.5.2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-02-26 16:35+0330\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.9.1\n" + +#: ../../exceptions.rst:2 +msgid "``pywebio.exceptions``" +msgstr "" + +#: of pywebio.exceptions:2 +msgid "pywebio.exceptions" +msgstr "" + +#: of pywebio.exceptions:4 +msgid "This module contains the set of PyWebIO's exceptions." +msgstr "" + +#: of pywebio.exceptions.SessionException:1 +msgid "Base class for PyWebIO session related exceptions" +msgstr "" + +#: of pywebio.exceptions.SessionClosedException:1 +msgid "The session has been closed abnormally" +msgstr "" + +#: of pywebio.exceptions.SessionNotFoundException:1 +msgid "Session not found" +msgstr "" + diff --git a/docs/locales/fa/LC_MESSAGES/guide.po b/docs/locales/fa/LC_MESSAGES/guide.po new file mode 100644 index 00000000..78c0ac63 --- /dev/null +++ b/docs/locales/fa/LC_MESSAGES/guide.po @@ -0,0 +1,1380 @@ +# Copyright (C) Weimin Wang +# This file is distributed under the same license as the PyWebIO package. +# +# FIRST AUTHOR , 2022. +# Pikhosh , 2022. +msgid "" +msgstr "" +"Project-Id-Version: PyWebIO 1.5.2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-02-26 16:35+0330\n" +"PO-Revision-Date: 2022-03-14 02:17+0330\n" +"Last-Translator: Pikhosh \n" +"Language-Team: Persian <>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.9.1\n" +"Language: fa\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Lokalize 21.12.2\n" + +#: ../../guide.rst:2 +msgid "User's guide" +msgstr "راهنمای کاربر" + +#: ../../guide.rst:4 +msgid "" +"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 pattern that backend implement api and " +"frontend display content. In PyWebIO, you only need to write code in " +"Python." +msgstr "" +"اگر شما با توسعه وب آشنایی دارید، ممکن است که به " +"استفاده از PyWebIO که در زیر توضیح داده شده عادت نداشته باشید، که از " +"الگو توسعه وب سنتی که بک اند API را پیاده سازی و " +"فرانت اند محتوا را نمایش می دهد متفاوت است. در PyWebIO، شما فقط نیاز دارید که" +" به " +"پایتون کد بنویسید." + +#: ../../guide.rst:8 +msgid "" +"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 interact " +"with the user and provide a good user experience as much as possible." +msgstr "" +"در واقع، نحوه نوشتن اپلیکیشن های PyWebIO بیشتر شبیه نوشتن یک " +"برنامه کنسول است، بجز اینکه ترمینال در اینجا تبدیل به یک مرورگر می شود. با" +" استفاده " +"از API دستوری ارائه شده توسط PyWebIO، شما می توانید به راحتی " +"``put_text()``, ``put_image()``, ``put_table()`` و توابع دیگر را برای " +"خروجی دادن متن، تصاویر، جداول و محتوا های دیگر به مرورگر فراخوانی کنید یا شما " +"می توانید برخی توابع مانند ``input()``, ``select()``, " +"``file_upload()`` را برای نمایش فرم های متفاوت روی مرورگر برای دریافت ورودی " +"کاربر فراخوانی کنید. علاوه بر این، PyWebIO همچنین پشتیبانی برای رویداد های" +" کلیک، " +"چیدمان، و... را ارائه می دهد. PyWebIO هدف دارد تا به شما اجازه دهد که از" +" کمترین کد برای تعامل " +"با کاربر استفاده کنید و یک تجربه کاربری خوب را تا حد امکان ارائه دهید." + +#: ../../guide.rst:15 +msgid "" +"This user guide introduces you the most of the features of PyWebIO. There" +" is a demo link at the top right of the example codes in this document, " +"where you can run the example code online and see what happens." +msgstr "" +"این راهنمای کاربر بیشتر ویژگی های PyWebIO را به شما معرفی می کند. یک" +" لینک دمو در بالا سمت راست کد های مثال در این مستندات وجود دارد، " +"جایی که شما می توانید کد مثال را به طور آنلاین اجرا کنید و ببینید که چه" +" اتفاقی می افتد." + +#: ../../guide.rst:19 +msgid "Input" +msgstr "ورودی" + +#: ../../guide.rst:21 +msgid "" +"The input functions are defined in the :doc:`pywebio.input ` " +"module and can be imported using ``from pywebio.input import *``." +msgstr "" + +#: ../../guide.rst:23 +msgid "" +"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." +msgstr "" + +#: ../../guide.rst:27 +msgid "Basic input" +msgstr "ورودی پایه" + +#: ../../guide.rst:29 +msgid "Here are some basic types of input." +msgstr "در اینجا برخی از انواع پایه ورودی آورده شده." + +#: ../../guide.rst:31 +msgid "Text input:" +msgstr "ورودی متن:" + +#: ../../guide.rst:33 +#, python-format +msgid "" +"age = input(\"How old are you?\", type=NUMBER)\n" +"put_text('age = %r' % age) # ..demo-only" +msgstr "" +"age = input(\"شما چند سال دارید؟\", type=NUMBER)\n" +"put_text('سن = %r' % age) # ..demo-only" + +#: ../../guide.rst:40 +msgid "" +"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." +msgstr "" + +#: ../../guide.rst:43 +msgid "Here are some other types of input functions:" +msgstr "در اینجا برخی از انواع دیگر توابع ورودی آورده شده:" + +#: ../../guide.rst:45 +#, python-format +msgid "" +"# Password input\n" +"password = input(\"Input password\", type=PASSWORD)\n" +"put_text('password = %r' % password) # ..demo-only\n" +"## ----\n" +"\n" +"# Drop-down selection\n" +"gift = select('Which gift you want?', ['keyboard', 'ipad'])\n" +"put_text('gift = %r' % gift) # ..demo-only\n" +"## ----\n" +"\n" +"# Checkbox\n" +"agree = checkbox(\"User Term\", options=['I agree to terms and " +"conditions'])\n" +"put_text('agree = %r' % agree) # ..demo-only\n" +"## ----\n" +"\n" +"# Single choice\n" +"answer = radio(\"Choose one\", options=['A', 'B', 'C', 'D'])\n" +"put_text('answer = %r' % answer) # ..demo-only\n" +"## ----\n" +"\n" +"# Multi-line text input\n" +"text = textarea('Text Area', rows=3, placeholder='Some text')\n" +"put_text('text = %r' % text) # ..demo-only\n" +"## ----\n" +"\n" +"# File Upload\n" +"img = file_upload(\"Select a image:\", accept=\"image/*\")\n" +"if img: # ..demo-only\n" +" put_image(img['content'], title=img['filename']) # ..demo-only" +msgstr "" +"# Password input\n" +"password = input(\"پسورد را وارد کنید\", type=PASSWORD)\n" +"put_text('پسورد = %r' % password) # ..demo-only\n" +"## ----\n" +"\n" +"# Drop-down selection\n" +"gift = select('شما چه هدیه ای را می خواهید؟', ['keyboard', 'ipad'])\n" +"put_text('هدیه = %r' % gift) # ..demo-only\n" +"## ----\n" +"\n" +"# Checkbox\n" +"agree = checkbox(\"شرط کاربر\", options=['من با شرایط و ضوابط موافقت می" +" کنم'])\n" +"put_text('موافقت = %r' % agree) # ..demo-only\n" +"## ----\n" +"\n" +"# Single choice\n" +"answer = radio(\"یکی را انتخاب کنید\", options=['A', 'B', 'C', 'D'])\n" +"put_text('پاسخ = %r' % answer) # ..demo-only\n" +"## ----\n" +"\n" +"# Multi-line text input\n" +"text = textarea('ناحیه متن', rows=3, placeholder='قدری متن')\n" +"put_text('متن = %r' % text) # ..demo-only\n" +"## ----\n" +"\n" +"# File Upload\n" +"img = file_upload(\"یک تصویر انتخاب کنید:\", accept=\"image/*\")\n" +"if img: # ..demo-only\n" +" put_image(img['content'], title=img['filename']) # ..demo-only" + +#: ../../guide.rst:81 +msgid "Parameter of input functions" +msgstr "پارامتر توابع ورودی" + +#: ../../guide.rst:83 +msgid "" +"There are many parameters that can be passed to the input function(for " +"complete parameters, please refer to the :doc:`function document " +"`):" +msgstr "" + +#: ../../guide.rst:86 +msgid "" +"input('This is label', type=TEXT, placeholder='This is placeholder',\n" +" help_text='This is help text', required=True)" +msgstr "" +"input('این لیبل است', type=TEXT, placeholder='این placeholder است',\n" +" help_text='این help text است', required=True)" + +#: ../../guide.rst:93 ../../guide.rst:129 ../../guide.rst:279 +#: ../../guide.rst:586 +msgid "The results of the above example are as follows:" +msgstr "نتایج مثال بالا به شرح زیر است:" + +#: ../../guide.rst:97 +msgid "" +"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:" +msgstr "" + +#: ../../guide.rst:100 +#, python-format +msgid "" +"def check_age(p): # return None when the check passes, otherwise return " +"the error message\n" +" if p < 10:\n" +" return 'Too young!!'\n" +" if p > 60:\n" +" return 'Too old!!'\n" +"\n" +"age = input(\"How old are you?\", type=NUMBER, validate=check_age)\n" +"put_text('age = %r' % age) # ..demo-only" +msgstr "" +"def check_age(p): # return None when the check passes, otherwise return " +"the error message\n" +" if p < 10:\n" +" return 'خیلی جوان!!'\n" +" if p > 60:\n" +" return 'خیلی پیر!!'\n" +"\n" +"age = input(\"شما چند سال دارید؟\", type=NUMBER, validate=check_age)\n" +"put_text('age = %r' % age) # ..demo-only" + +#: ../../guide.rst:113 +msgid "" +"When the user input an illegal value, the input field is displayed as " +"follows:" +msgstr "" + +#: ../../guide.rst:117 +msgid "" +"You can use ``code`` parameter in :func:`pywebio.input.textarea()` to " +"make a code editing textarea." +msgstr "" + +#: ../../guide.rst:119 +msgid "" +"code = textarea('Code Edit', code={\n" +" 'mode': \"python\",\n" +" 'theme': 'darcula',\n" +"}, value='import something\\n# Write your python code')\n" +"put_code(code, language='python') # ..demo-only" +msgstr "" +"code = textarea('ویرایش کد', code={\n" +" 'mode': \"python\",\n" +" 'theme': 'darcula',\n" +"}, value='import something\\n# کد پایتون خودتان را بنویسید')\n" +"put_code(code, language='python') # ..demo-only" + +#: ../../guide.rst:135 +msgid "Input Group" +msgstr "گروه ورودی" + +#: ../../guide.rst:137 +msgid "" +"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`` of the " +"single input as its key and the input data as its value:" +msgstr "" + +#: ../../guide.rst:142 +msgid "" +"def check_age(p): # ..demo-only\n" +" if p < 10: # ..demo-only\n" +" return 'Too young!!' # ..demo-only\n" +" if p > 60: # ..demo-only\n" +" return 'Too old!!' # ..demo-only\n" +" # ..demo-only\n" +"data = input_group(\"Basic info\",[\n" +" input('Input your name', name='name'),\n" +" input('Input your age', name='age', type=NUMBER, validate=check_age)\n" +"])\n" +"put_text(data['name'], data['age'])" +msgstr "" +"def check_age(p): # ..demo-only\n" +" if p < 10: # ..demo-only\n" +" return 'خیلی جوان!!' # ..demo-only\n" +" if p > 60: # ..demo-only\n" +" return 'خیلی پیر!!' # ..demo-only\n" +" # ..demo-only\n" +"data = input_group(\"اطلاعات پایه\",[\n" +" input('نام خود را وارد کنید', name='name'),\n" +" input('سن خود را وارد کنید', name='age', type=NUMBER, validate=check_age)\n" +"])\n" +"put_text(data['name'], data['age'])" + +#: ../../guide.rst:158 +msgid "" +"The input group also supports using ``validate`` parameter to set the " +"validation function, which accepts the entire form data as parameter:" +msgstr "" + +#: ../../guide.rst:160 +msgid "" +"def check_age(p): # single input item validation # ..demo-only\n" +" if p < 10: # ..demo-only\n" +" return 'Too young!!' # ..demo-only\n" +" if p > 60: # ..demo-only\n" +" return 'Too old!!' # ..demo-only\n" +" # ..demo-only\n" +"def check_form(data): # return (input name, error msg) when validation " +"fail\n" +" if len(data['name']) > 6:\n" +" return ('name', 'Name too long!')\n" +" if data['age'] <= 0:\n" +" return ('age', 'Age can not be negative!')\n" +"\n" +"data = input_group(\"Basic info\",[ # ..demo-only\n" +" input('Input your name', name='name'), # ..demo-only\n" +" input('Input your age', name='age', type=NUMBER, validate=check_age) " +"# ..demo-only\n" +"], validate=check_form) # ..demo-only\n" +"put_text(data['name'], data['age']) # ..demo-only" +msgstr "" +"def check_age(p): # single input item validation # ..demo-only\n" +" if p < 10: # ..demo-only\n" +" return 'خیلی جوان!!' # ..demo-only\n" +" if p > 60: # ..demo-only\n" +" return 'خیلی پیر!!' # ..demo-only\n" +" # ..demo-only\n" +"def check_form(data): # return (input name, error msg) when validation " +"fail\n" +" if len(data['name']) > 6:\n" +" return ('name', 'نام خیلی طولانی است!')\n" +" if data['age'] <= 0:\n" +" return ('age', 'سن نمی تواند منفی باشد!')\n" +"\n" +"data = input_group(\"اطلاعات پایه\",[ # ..demo-only\n" +" input('نام خود را وارد کنید', name='name'), # ..demo-only\n" +" input('سن خود را وارد کنید', name='age', type=NUMBER, validate=check_age) " +"# ..demo-only\n" +"], validate=check_form) # ..demo-only\n" +"put_text(data['name'], data['age']) # ..demo-only" + +#: ../../guide.rst:183 +msgid "" +"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." +msgstr "" + +#: ../../guide.rst:188 +msgid "Output" +msgstr "خروجی" + +#: ../../guide.rst:190 +msgid "" +"The output functions are all defined in the :doc:`pywebio.output " +"` module and can be imported using ``from pywebio.output import " +"*``." +msgstr "" + +#: ../../guide.rst:193 +msgid "" +"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." +msgstr "" + +#: ../../guide.rst:197 +msgid "Basic Output" +msgstr "خروجی پایه" + +#: ../../guide.rst:199 +msgid "" +"Using output functions, you can output a variety of content, such as " +"text, tables, images and so on:" +msgstr "" + +#: ../../guide.rst:201 +msgid "" +"# Text Output\n" +"put_text(\"Hello world!\")\n" +"## ----\n" +"\n" +"# Table Output\n" +"put_table([\n" +" ['Commodity', 'Price'],\n" +" ['Apple', '5.5'],\n" +" ['Banana', '7'],\n" +"])\n" +"## ----\n" +"\n" +"# Image Output\n" +"put_image(open('/path/to/some/image.png', 'rb').read()) # local image # " +"..doc-only\n" +"put_image('http://example.com/some-image.png') # internet image # ..doc-" +"only\n" +"put_image('https://www.python.org/static/img/python-logo.png') # ..demo-" +"only\n" +"## ----\n" +"\n" +"# Markdown Output\n" +"put_markdown('~~Strikethrough~~')\n" +"## ----\n" +"\n" +"# File Output\n" +"put_file('hello_word.txt', b'hello word!')\n" +"## ----\n" +"\n" +"# Show a PopUp\n" +"popup('popup title', 'popup text content')\n" +"\n" +"# Show a notification message\n" +"toast('New message 🔔')" +msgstr "" +"# Text Output\n" +"put_text(\"سلام دنیا!\")\n" +"## ----\n" +"\n" +"# Table Output\n" +"put_table([\n" +" ['کالا', 'قیمت'],\n" +" ['سیب', '5.5'],\n" +" ['موز', '7'],\n" +"])\n" +"## ----\n" +"\n" +"# Image Output\n" +"put_image(open('/path/to/some/image.png', 'rb').read()) # local image # " +"..doc-only\n" +"put_image('http://example.com/some-image.png') # internet image # ..doc-" +"only\n" +"put_image('https://www.python.org/static/img/python-logo.png') # ..demo-" +"only\n" +"## ----\n" +"\n" +"# Markdown Output\n" +"put_markdown('~~Strikethrough~~')\n" +"## ----\n" +"\n" +"# File Output\n" +"put_file('hello_word.txt', b'hello word!')\n" +"## ----\n" +"\n" +"# Show a PopUp\n" +"popup('popup title', 'popup text content')\n" +"\n" +"# Show a notification message\n" +"toast('New message 🔔')" + +#: ../../guide.rst:238 +msgid "" +"For all output functions provided by PyWebIO, please refer to the " +":doc:`pywebio.output ` module. In addition, PyWebIO also " +"supports data visualization with some third-party libraries, see :doc" +":`Third-party library ecology `." +msgstr "" + +#: ../../guide.rst:245 +msgid "" +"If you use PyWebIO in interactive execution environment of Python shell, " +"IPython or jupyter notebook, you need call `show()` method explicitly to " +"show output::" +msgstr "" + +#: ../../guide.rst:248 +msgid "" +">>> put_text(\"Hello world!\").show()\n" +">>> put_table([\n" +"... ['A', 'B'],\n" +"... [put_markdown(...), put_text('C')]\n" +"... ]).show()" +msgstr "" + +#: ../../guide.rst:258 +msgid "Combined Output" +msgstr "خروجی ترکیبی" + +#: ../../guide.rst:260 +msgid "" +"The output functions whose name starts with ``put_`` can be combined with" +" some output functions as part of the final output:" +msgstr "" + +#: ../../guide.rst:262 +msgid "" +"You can pass ``put_xxx()`` calls to `put_table() " +"` as cell content:" +msgstr "" + +#: ../../guide.rst:264 +msgid "" +"put_table([\n" +" ['Type', 'Content'],\n" +" ['html', put_html('X2')],\n" +" ['text', '
'], # equal to ['text', put_text('
')]\n" +" ['buttons', put_buttons(['A', 'B'], onclick=...)], # ..doc-only\n" +" ['buttons', put_buttons(['A', 'B'], onclick=put_text)], # ..demo-" +"only\n" +" ['markdown', put_markdown('`Awesome PyWebIO!`')],\n" +" ['file', put_file('hello.text', b'hello world')],\n" +" ['table', put_table([['A', 'B'], ['C', 'D']])]\n" +"])" +msgstr "" + +#: ../../guide.rst:283 +msgid "" +"Similarly, you can pass ``put_xxx()`` calls to `popup() " +"` as the popup content:" +msgstr "" + +#: ../../guide.rst:285 +msgid "" +"popup('Popup title', [\n" +" put_html('

Popup Content

'),\n" +" 'plain html:
', # Equivalent to: put_text('plain html:
')\n" +" put_table([['A', 'B'], ['C', 'D']]),\n" +" put_button('close_popup()', onclick=close_popup)\n" +"])" +msgstr "" + +#: ../../guide.rst:296 +msgid "" +"In addition, you can use `put_widget() ` to " +"make your own output widgets that can accept ``put_xxx()`` calls." +msgstr "" + +#: ../../guide.rst:298 +msgid "" +"For a full list of functions that accept ``put_xxx()`` calls as content, " +"see :ref:`Output functions list `" +msgstr "" + +#: ../../guide.rst:300 +msgid "**Context Manager**" +msgstr "" + +#: ../../guide.rst:302 +msgid "" +"Some output functions that accept ``put_xxx()`` calls as content can be " +"used as context manager:" +msgstr "" + +#: ../../guide.rst:304 +msgid "" +"with put_collapse('This is title'):\n" +" for i in range(4):\n" +" put_text(i)\n" +"\n" +" put_table([\n" +" ['Commodity', 'Price'],\n" +" ['Apple', '5.5'],\n" +" ['Banana', '7'],\n" +" ])" +msgstr "" + +#: ../../guide.rst:318 +msgid "" +"For a full list of functions that support context manager, see " +":ref:`Output functions list `" +msgstr "" + +#: ../../guide.rst:324 +msgid "Click Callback" +msgstr "فراخوانی کلیک" + +#: ../../guide.rst:326 +msgid "" +"As we can see from the above, the interaction of PyWebIO has two parts: " +"input and output. The input function of PyWebIO is blocking, a form will " +"be displayed on the user's web browser when calling input function, the " +"input function will not return until the user submits the form. The " +"output function is used to output content to the browser in real time. " +"The input and output behavior of PyWebIO 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 programming " +"way." +msgstr "" + +#: ../../guide.rst:332 +msgid "" +"In addition, PyWebIO also supports event callbacks: PyWebIO allows you to" +" output some buttons and bind callbacks to them. The provided callback " +"function will be executed when the button is clicked." +msgstr "" + +#: ../../guide.rst:335 +msgid "This is an example:" +msgstr "این یک مثال است:" + +#: ../../guide.rst:337 +#, python-format +msgid "" +"from functools import partial\n" +"\n" +"def edit_row(choice, row):\n" +" put_text(\"You click %s button ar row %s\" % (choice, row))\n" +"\n" +"put_table([\n" +" ['Idx', 'Actions'],\n" +" [1, put_buttons(['edit', 'delete'], onclick=partial(edit_row, " +"row=1))],\n" +" [2, put_buttons(['edit', 'delete'], onclick=partial(edit_row, " +"row=2))],\n" +" [3, put_buttons(['edit', 'delete'], onclick=partial(edit_row, " +"row=3))],\n" +"])" +msgstr "" + +#: ../../guide.rst:353 +msgid "" +"The call to `put_table() ` will not block. When" +" user clicks a button, the corresponding callback function will be " +"invoked:" +msgstr "" + +#: ../../guide.rst:358 +msgid "Of course, PyWebIO also supports outputting individual button:" +msgstr "" + +#: ../../guide.rst:360 +#, python-format +msgid "" +"def btn_click(btn_val):\n" +" put_text(\"You click %s button\" % btn_val)\n" +"\n" +"put_buttons(['A', 'B', 'C'], onclick=btn_click) # a group of buttons\n" +"\n" +"put_button(\"Click me\", onclick=lambda: toast(\"Clicked\")) # single " +"button" +msgstr "" + +#: ../../guide.rst:371 +msgid "" +"In fact, all output can be bound to click events, not just buttons. You " +"can call ``onclick()`` method after the output function (function name " +"like ``put_xxx()``) call:" +msgstr "" + +#: ../../guide.rst:374 +msgid "" +"put_image('some-image.png').onclick(lambda: toast('You click an image'))" +" # ..doc-only\n" +"put_image('https://www.python.org/static/img/python-" +"logo.png').onclick(lambda: toast('You click an image')) # ..demo-only\n" +"\n" +"# set onclick in combined output\n" +"put_table([\n" +" ['Commodity', 'Price'],\n" +" ['Apple', put_text('5.5').onclick(lambda: toast('You click the " +"text'))],\n" +"])" +msgstr "" + +#: ../../guide.rst:387 +msgid "" +"The return value of ``onclick()`` method is the object itself so it can " +"be used in combined output." +msgstr "" + +#: ../../guide.rst:392 +msgid "Output Scope" +msgstr "محدوده خروجی" + +#: ../../guide.rst:394 +msgid "" +"PyWebIO uses the scope model to give more control to the location of " +"content output. The output scope is a container of output content. You " +"can create a scope in somewhere and append content to it." +msgstr "" + +#: ../../guide.rst:397 +msgid "" +"Each output function (function name like ``put_xxx()``) will output its " +"content to a scope, the default is \"current scope\". The \"current " +"scope\" is set by `use_scope() `." +msgstr "" + +#: ../../guide.rst:402 +msgid "**use_scope()**" +msgstr "" + +#: ../../guide.rst:404 +msgid "" +"You can use `use_scope() ` to open and enter a " +"new output scope, or enter an existing output scope:" +msgstr "" + +#: ../../guide.rst:406 +msgid "" +"with use_scope('scope1'): # open and enter a new output: 'scope1'\n" +" put_text('text1 in scope1') # output text to scope1\n" +"\n" +"put_text('text in parent scope of scope1') # output text to ROOT scope\n" +"\n" +"with use_scope('scope1'): # enter an existing scope: 'scope1'\n" +" put_text('text2 in scope1') # output text to scope1" +msgstr "" + +#: ../../guide.rst:418 ../../guide.rst:439 +msgid "The results of the above code are as follows::" +msgstr "نتایج کد بالا به شرح زیر است::" + +#: ../../guide.rst:420 +msgid "" +"text1 in scope1\n" +"text2 in scope1\n" +"text in parent scope of scope1" +msgstr "" + +#: ../../guide.rst:424 +msgid "" +"You can use ``clear`` parameter in `use_scope() " +"` to clear the existing content before entering" +" the scope:" +msgstr "" + +#: ../../guide.rst:426 +msgid "" +"with use_scope('scope2'):\n" +" put_text('create scope2')\n" +"\n" +"put_text('text in parent scope of scope2')\n" +"## ----\n" +"\n" +"with use_scope('scope2', clear=True): # enter the existing scope and " +"clear the previous content\n" +" put_text('text in scope2')" +msgstr "" + +#: ../../guide.rst:441 +msgid "" +"text in scope2\n" +"text in parent scope of scope2" +msgstr "" + +#: ../../guide.rst:444 +msgid "`use_scope() ` can also be used as decorator:" +msgstr "" + +#: ../../guide.rst:446 +msgid "" +"import time # ..demo-only\n" +"from datetime import datetime\n" +"\n" +"@use_scope('time', clear=True)\n" +"def show_time():\n" +" put_text(datetime.now())\n" +"\n" +"while 1: # ..demo-only\n" +" show_time() # ..demo-only\n" +" time.sleep(1) # ..demo-only" +msgstr "" + +#: ../../guide.rst:461 +msgid "" +"When calling ``show_time()`` for the first time, a ``time`` scope will be" +" created, 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." +msgstr "" + +#: ../../guide.rst:464 +msgid "" +"Scopes can be nested. At the beginning, PyWebIO applications have only " +"one ``ROOT`` scope. You can create new scope in a scope. For example, the" +" following code will create 3 scopes:" +msgstr "" + +#: ../../guide.rst:467 +#, python-format +msgid "" +"with use_scope('A'):\n" +" put_text('Text in scope A')\n" +"\n" +" with use_scope('B'):\n" +" put_text('Text in scope B')\n" +"\n" +"with use_scope('C'):\n" +" put_text('Text in scope C')\n" +"\n" +"put_html(\"\"\"\"\"\") # ..demo-" +"only\n" +"put_text() # ..demo-" +"only\n" +"put_buttons([('Put text to %s' % i, i) for i in ('A', 'B', 'C')], lambda " +"s: put_text(s, scope=s)) # ..demo-only" +msgstr "" + +#: ../../guide.rst:489 +msgid "The above code will generate the following scope layout::" +msgstr "" + +#: ../../guide.rst:491 +msgid "" +"┌─ROOT────────────────────┐\n" +"│ │\n" +"│ ┌─A───────────────────┐ │\n" +"│ │ Text in scope A │ │\n" +"│ │ ┌─B───────────────┐ │ │\n" +"│ │ │ Text in scope B │ │ │\n" +"│ │ └─────────────────┘ │ │\n" +"│ └─────────────────────┘ │\n" +"│ │\n" +"│ ┌─C───────────────────┐ │\n" +"│ │ Text in scope C │ │\n" +"│ └─────────────────────┘ │\n" +"└─────────────────────────┘" +msgstr "" + +#: ../../guide.rst:507 +msgid "**put_scope()**" +msgstr "" + +#: ../../guide.rst:509 +msgid "" +"We already know that the scope is a container of output content. So can " +"we use this container as a sub-item of a output (like, set a cell in " +"table as a container)? Yes, you can use `put_scope() " +"` to create a scope explicitly. The function " +"name starts with ``put_``, which means it can be pass to the functions " +"that accept ``put_xxx()`` calls." +msgstr "" + +#: ../../guide.rst:514 +msgid "" +"put_table([\n" +" ['Name', 'Hobbies'],\n" +" ['Tom', put_scope('hobby', content=put_text('Coding'))] # hobby is " +"initialized to coding\n" +"])\n" +"\n" +"## ----\n" +"with use_scope('hobby', clear=True):\n" +" put_text('Movie') # hobby is reset to Movie\n" +"\n" +"## ----\n" +"# append Music, Drama to hobby\n" +"with use_scope('hobby'):\n" +" put_text('Music')\n" +" put_text('Drama')\n" +"\n" +"## ----\n" +"# insert the Coding into the top of the hobby\n" +"put_markdown('**Coding**', scope='hobby', position=0)" +msgstr "" + +#: ../../guide.rst:538 +msgid "" +"It is not allowed to have two scopes with the same name in the " +"application." +msgstr "" + +#: ../../guide.rst:540 +msgid "**Scope control**" +msgstr "" + +#: ../../guide.rst:542 +msgid "" +"In addition to `use_scope() ` and `put_scope() " +"`, PyWebIO also provides the following scope " +"control functions:" +msgstr "" + +#: ../../guide.rst:545 +msgid "`clear(scope) ` : Clear the contents of the scope" +msgstr "" + +#: ../../guide.rst:546 +msgid "`remove(scope) ` : Remove scope" +msgstr "" + +#: ../../guide.rst:547 +msgid "" +"`scroll_to(scope) ` : Scroll the page to the " +"scope" +msgstr "" + +#: ../../guide.rst:549 +msgid "" +"Also, all output functions (function name like ``put_xxx()``) support a " +"``scope`` parameter to specify the destination scope to output, and " +"support a ``position`` parameter to specify the insert position in target" +" scope. Refer :ref:`output module ` for more information." +msgstr "" + +#: ../../guide.rst:554 +msgid "Layout" +msgstr "چیدمان" + +#: ../../guide.rst:556 +msgid "" +"In general, using the output functions introduced above is enough to " +"output what you want, but these outputs are arranged vertically. If you " +"want to create 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." +msgstr "" + +#: ../../guide.rst:560 +msgid "" +"The ``pywebio.output`` module provides 3 layout functions, and you can " +"create complex layouts by combining them:" +msgstr "" + +#: ../../guide.rst:562 +msgid "" +"`put_row() ` : Use row layout to output content. " +"The content is arranged horizontally" +msgstr "" + +#: ../../guide.rst:563 +msgid "" +"`put_column() ` : Use column layout to output " +"content. The content is arranged vertically" +msgstr "" + +#: ../../guide.rst:564 +msgid "" +"`put_grid() ` : Output content using grid layout" +msgstr "" + +#: ../../guide.rst:566 +msgid "Here is an example by combining ``put_row()`` and ``put_column()``:" +msgstr "" + +#: ../../guide.rst:568 +msgid "" +"put_row([\n" +" put_column([\n" +" put_code('A'),\n" +" put_row([\n" +" put_code('B1'), None, # None represents the space between " +"the output\n" +" put_code('B2'), None,\n" +" put_code('B3'),\n" +" ]),\n" +" put_code('C'),\n" +" ]), None,\n" +" put_code('D'), None,\n" +" put_code('E')\n" +"])" +msgstr "" + +#: ../../guide.rst:591 +msgid "The layout function also supports customizing the size of each part::" +msgstr "" + +#: ../../guide.rst:593 +#, python-format +msgid "" +"put_row([put_image(...), put_image(...)], size='40% 60%') # The ratio of" +" the width of two images is 2:3" +msgstr "" + +#: ../../guide.rst:595 +msgid "" +"For more information, please refer to the :ref:`layout functions " +"documentation `." +msgstr "" + +#: ../../guide.rst:600 +msgid "Style" +msgstr "استایل" + +#: ../../guide.rst:602 +msgid "" +"If you are familiar with `CSS `_ " +"styles, you can use the ``style()`` method of output return to set a " +"custom style for the output." +msgstr "" + +#: ../../guide.rst:605 +msgid "You can set the CSS style for a single ``put_xxx()`` output:" +msgstr "" + +#: ../../guide.rst:607 +msgid "" +"put_text('hello').style('color: red; font-size: 20px')\n" +"\n" +"## ----\n" +"# in combined output\n" +"put_row([\n" +" put_text('hello').style('color: red'),\n" +" put_markdown('markdown')\n" +"]).style('margin-top: 20px')" +msgstr "" + +#: ../../guide.rst:620 +msgid "" +"The return value of ``style()`` method is the object itself so it can be " +"used in combined output." +msgstr "" + +#: ../../guide.rst:625 +msgid "Run application" +msgstr "اجرای اپلیکیشن" + +#: ../../guide.rst:627 +msgid "" +"In PyWebIO, there are two modes to run PyWebIO applications: running as a" +" script and using `pywebio.start_server() " +"` or " +"`pywebio.platform.path_deploy() ` to run as" +" a web service." +msgstr "" + +#: ../../guide.rst:632 +msgid "Overview" +msgstr "بررسی اجمالی" + +#: ../../guide.rst:636 ../../guide.rst:701 +msgid "**Server mode**" +msgstr "**حالت سرور**" + +#: ../../guide.rst:638 +msgid "" +"In server mode, PyWebIO will start a web server to continuously provide " +"services. When the user accesses the service address, PyWebIO will open a" +" new session and run PyWebIO application in it." +msgstr "" + +#: ../../guide.rst:641 +msgid "" +"`start_server() ` is the most " +"common way to start a web server to serve given PyWebIO applications::" +msgstr "" + +#: ../../guide.rst:644 +msgid "" +"from pywebio import *\n" +"\n" +"def main(): # PyWebIO application function\n" +" name = input.input(\"what's your name\")\n" +" output.put_text(\"hello\", name)\n" +"\n" +"start_server(main, port=8080, debug=True)" +msgstr "" + +#: ../../guide.rst:652 +msgid "" +"Now head over to http://127.0.0.1:8080/, and you should see your hello " +"greeting." +msgstr "" + +#: ../../guide.rst:654 +msgid "" +"By using ``debug=True`` to enable debug mode, the server will " +"automatically reload if code changes." +msgstr "" + +#: ../../guide.rst:656 +msgid "" +"The `start_server() ` provide a " +"remote access support, when enabled (by passing `remote_access=True` to " +"`start_server()`), you will get a public, shareable address for the " +"current application, others can access your application in their browser " +"via this address. Because the processing happens on your device (as long " +"as your device stays on!), you don't have to worry about any " +"dependencies. Using remote access makes it easy to temporarily share the " +"application with others." +msgstr "" + +#: ../../guide.rst:662 +msgid "" +"Another way to deploy PyWebIO application as web service is using " +"`path_deploy() `. `path_deploy() " +"` is used to deploy the PyWebIO " +"applications from a directory. Just define PyWebIO applications in python" +" files under this directory, and you can access them via the path in the " +"URL. Refer to :ref:`platform module ` for more information." +msgstr "" + +#: ../../guide.rst:669 +msgid "" +"Note that in Server mode, all functions from ``pywebio.input``, " +"``pywebio.output`` and ``pywebio.session`` modules can only be called in " +"the context of PyWebIO application functions. For example, the following " +"code is **not allowed**::" +msgstr "" + +#: ../../guide.rst:672 +msgid "" +"import pywebio\n" +"from pywebio.input import input\n" +"\n" +"port = input('Input port number:') # ❌ error\n" +"pywebio.start_server(my_task_func, port=int(port))" +msgstr "" + +#: ../../guide.rst:679 ../../guide.rst:696 +msgid "**Script mode**" +msgstr "**حالت اسکریپت**" + +#: ../../guide.rst:681 +msgid "" +"If you never call ``start_server()`` or ``path_deploy()`` in your code, " +"then you are running PyWebIO application as script mode." +msgstr "" + +#: ../../guide.rst:683 +msgid "" +"In script mode, a web browser page will be open automatically when " +"running to the first call to PyWebIO interactive functions, and all " +"subsequent PyWebIO interactions will take place on this page. When the " +"script exit, the page will be inactive." +msgstr "" + +#: ../../guide.rst:686 +msgid "" +"If the user closes the browser before the script exiting, then subsequent" +" calls to PyWebIO's interactive functions will cause a `SessionException " +"` exception." +msgstr "" + +#: ../../guide.rst:692 +msgid "Concurrent" +msgstr "هم زمان" + +#: ../../guide.rst:694 +msgid "PyWebIO can be used in a multi-threading environment." +msgstr "" + +#: ../../guide.rst:698 +msgid "" +"In script mode, you can freely start new thread and call PyWebIO " +"interactive functions in it. When all `non-daemonic " +"`_ " +"threads finish running, the script exits." +msgstr "" + +#: ../../guide.rst:703 +msgid "" +"In server mode, if you need to use PyWebIO interactive functions in new " +"thread, you need to use `pywebio.session.register_thread(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) " +"` calling PyWebIO's interactive " +"functions will cause `SessionNotFoundException " +"`." +msgstr "" + +#: ../../guide.rst:710 +msgid "Example of using multi-threading in Server mode::" +msgstr "" + +#: ../../guide.rst:712 +msgid "" +"def show_time():\n" +" while True:\n" +" with use_scope(name='time', clear=True):\n" +" put_text(datetime.datetime.now())\n" +" time.sleep(1)\n" +"\n" +"def app():\n" +" t = threading.Thread(target=show_time)\n" +" register_thread(t)\n" +" put_markdown('## Clock')\n" +" t.start() # run `show_time()` in background\n" +"\n" +" # ❌ this thread will cause `SessionNotFoundException`\n" +" threading.Thread(target=show_time).start()\n" +"\n" +" put_text('Background task started.')\n" +"\n" +"\n" +"start_server(app, port=8080, debug=True)" +msgstr "" + +#: ../../guide.rst:736 +msgid "Close of session" +msgstr "" + +#: ../../guide.rst:738 +msgid "" +"When user close the browser page, the session will be closed. After the " +"browser page is closed, PyWebIO input function calls that have not yet " +"returned in the current session will cause `SessionClosedException " +"`, and subsequent calls to " +"PyWebIO interactive functions will cause `SessionNotFoundException " +"` or `SessionClosedException" +" `." +msgstr "" + +#: ../../guide.rst:743 +msgid "" +"In most cases, you don't need to catch those exceptions, because let " +"those exceptions to abort the running is the right way to exit." +msgstr "" + +#: ../../guide.rst:745 +msgid "" +"You can use `pywebio.session.defer_call(func) " +"` to set the function to be called when the " +"session closes. `defer_call(func) ` can be " +"used for resource cleaning. You can call `defer_call(func) " +"` multiple times in the session, and the set " +"functions will be executed sequentially after the session closes." +msgstr "" + +#: ../../guide.rst:751 +msgid "More about PyWebIO" +msgstr "اطلاعات بیشتر درباره PyWebIO" + +#: ../../guide.rst:752 +msgid "" +"By now, you already get the most important features of PyWebIO and can " +"start to write awesome PyWebIO applications. However, there are some " +"other useful features we don't cover in the above. Here we just make a " +"briefly explain about them. When you need them in your application, you " +"can refer to their document." +msgstr "" + +#: ../../guide.rst:756 +msgid "" +"Also, :doc:`here ` is a cookbook where you can find some " +"useful code snippets for your PyWebIO application." +msgstr "" + +#: ../../guide.rst:759 +msgid "``session`` module" +msgstr "ماژول ``session``" + +#: ../../guide.rst:760 +msgid "" +"The :doc:`pywebio.session ` module give you more control to " +"session." +msgstr "" + +#: ../../guide.rst:762 +msgid "" +"Use `set_env() ` to configure the title, page " +"appearance, input panel and so on for current session." +msgstr "" + +#: ../../guide.rst:764 +msgid "" +"The `info ` object provides a lot information about" +" the current session, such as the user IP address, user language and user" +" browser information." +msgstr "" + +#: ../../guide.rst:767 +msgid "" +"`local ` is a session-local storage, it used to " +"save data whose values are session specific." +msgstr "" + +#: ../../guide.rst:769 +msgid "" +"`run_js() ` let you execute JavaScript code in " +"user's browser, and `eval_js() ` let you execute" +" JavaScript expression and get the value of it." +msgstr "" + +#: ../../guide.rst:773 +msgid "``pin`` module" +msgstr "ماژول ``pin``" + +#: ../../guide.rst:774 +msgid "" +"As you already know, the input function of PyWebIO is blocking and the " +"input form will be destroyed after successful submission. In some cases, " +"you may want to make the input form not disappear after submission, and " +"can continue to receive input. So PyWebIO provides the :doc:`pywebio.pin " +"` module to achieve persistent input by pinning input widgets to " +"the page." +msgstr "" + +#: ../../guide.rst:779 +msgid "``platform`` module" +msgstr "ماژول ``platform``" + +#: ../../guide.rst:781 +msgid "" +"The :doc:`pywebio.platform ` module provides support for " +"deploying PyWebIO applications in different ways." +msgstr "" + +#: ../../guide.rst:783 +msgid "" +"There are two protocols (WebSocket and HTTP) can be used in server to " +"communicates with the browser. The WebSocket is used by default. If you " +"want to use HTTP protocol, you can choose other ``start_server()`` " +"functions in this module." +msgstr "" + +#: ../../guide.rst:786 +msgid "" +"You might want to set some web page related configuration (such as SEO " +"information, js and css injection) for your PyWebIO application, " +"`pywebio.config() ` can be helpful." +msgstr "" + +#: ../../guide.rst:790 +msgid "Advanced features" +msgstr "ویژگی های پیشرفته" + +#: ../../guide.rst:792 +msgid "" +"The PyWebIO application can be integrated into an existing Python web " +"project, the PyWebIO application and the web project share a web " +"framework. Refer to :ref:`Advanced Topic: Integration with Web Framework " +"` for more information." +msgstr "" + +#: ../../guide.rst:796 +msgid "" +"PyWebIO also provides support for coroutine-based sessions. Refer to " +":ref:`Advanced Topic: Coroutine-based session ` " +"for more information." +msgstr "" + +#: ../../guide.rst:799 +msgid "" +"If you try to bundles your PyWebIO application into a stand-alone " +"executable file, to make users can run the application without installing" +" a Python interpreter or any modules, you might want to refer to " +":ref:`Libraries support: Build stand-alone App `" +msgstr "" + +#: ../../guide.rst:802 +msgid "" +"If you want to make some data visualization in your PyWebIO application, " +"you can't miss :ref:`Libraries support: Data visualization " +"`" +msgstr "" + +#: ../../guide.rst:805 +msgid "Last but not least" +msgstr "آخرین اما نه کم اهمیت ترین" + +#: ../../guide.rst:807 +msgid "" +"This is basically all features of PyWebIO, you can continue to read the " +"rest of the documents, or start writing your PyWebIO applications now." +msgstr "" + +#: ../../guide.rst:809 +msgid "" +"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" +" :ref:`callback mechanism ` or :doc:`pin <./pin>` module." +msgstr "" + +#: ../../guide.rst:814 +msgid "OK, Have fun with PyWebIO!" +msgstr "خیلی خب، با PyWebIO اوقات خوشی را داشته باشید!" + diff --git a/docs/locales/fa/LC_MESSAGES/index.po b/docs/locales/fa/LC_MESSAGES/index.po new file mode 100644 index 00000000..e49998e1 --- /dev/null +++ b/docs/locales/fa/LC_MESSAGES/index.po @@ -0,0 +1,261 @@ +# Copyright (C) Weimin Wang +# This file is distributed under the same license as the PyWebIO package. +# +# FIRST AUTHOR , 2022. +# Pikhosh , 2022. +msgid "" +msgstr "" +"Project-Id-Version: PyWebIO 1.5.2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-02-26 16:35+0330\n" +"PO-Revision-Date: 2022-03-14 01:55+0330\n" +"Last-Translator: Pikhosh \n" +"Language-Team: English <>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.9.1\n" +"Language: en_US\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 21.12.2\n" + +#: ../../index.rst:80 +msgid "Manual" +msgstr "کتابچه راهنما" + +#: ../../index.rst:99 +msgid "Implement Doc" +msgstr "مستندات پیاده سازی" + +#: ../../index.rst:2 +msgid "PyWebIO" +msgstr "" + +#: ../../index.rst:4 +msgid "" +"PyWebIO provides a diverse set of imperative functions to obtain user " +"input and output content 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 function), without the need to have knowledge of HTML and" +" JS. PyWebIO is ideal for quickly building interactive applications that " +"don't require a complicated user interface." +msgstr "" +"PyWebIO مجموعه ای از توابع دستوری را برای به دست آوردن ورودی " +"کاربر و خروجی دادن محتوا روی مرورگر را ارائه می کند، تبدیل مرورگر به یک " +"«ترمینال متن غنی»، و می تواند برای ساخت وب اپلیکیشن های ساده " +"یا اپلیکیشن های دارای رابط کاربری گرافیکی مبتنی بر مرورگر استفاده شود. با" +" استفاده از PyWebIO، توسعه دهندگان می توانند اپلیکیشن ها را درست " +"مثل نوشتن اسکریپت های ترمینال (تعامل بر پایه " +"تابع Input و Print) بنویسند، بدون نیاز به داشتن دانش HTML و" +" جاوا اسکریپت. PyWebIO برای ساخت سریع اپلیکیشن های تعاملی که " +"یک رابط کاربری پیچیده نیاز ندارند ایده آل است." + +#: ../../index.rst:11 +msgid "Features" +msgstr "ویژگی ها" + +#: ../../index.rst:13 +msgid "Use synchronization instead of callback-based method to get input" +msgstr "استفاده از همگام سازی بجای متد مبتنی بر فراخوانی برای دریافت ورودی" + +#: ../../index.rst:14 +msgid "Non-declarative layout, simple and efficient" +msgstr "چیدمان Non-declarative، ساده و کارآمد" + +#: ../../index.rst:15 +msgid "" +"Less intrusive: old script code can be transformed into a Web service " +"only by modifying the input and output operation" +msgstr "" +"کمتر مزاحم: کد اسکریپت قدیم می تواند به یک وب سرویس تبدیل شود فقط با اصلاح" +" عملیات ورودی و خروجی" + +#: ../../index.rst:16 +msgid "" +"Support integration into existing web services, currently supports Flask," +" Django, Tornado, aiohttp and FastAPI(Starlette) framework" +msgstr "" +"پشتیبانی از ادغام با وب سرویس های موجود، در حال حاضر پشتیبانی از Flask," +" Django, Tornado, aiohttp و فریم ورک FastAPI(Starlette)" + +#: ../../index.rst:17 +msgid "Support for ``asyncio`` and coroutine" +msgstr "پشتیبانی برای ``asyncio`` و coroutine" + +#: ../../index.rst:18 +msgid "Support data visualization with third-party libraries" +msgstr "پشتیبانی از بصری سازی داده با کتابخانه های شخص ثالث" + +#: ../../index.rst:21 +msgid "Installation" +msgstr "نصب" + +#: ../../index.rst:23 +msgid "Stable version::" +msgstr "نسخه پایدار::" + +#: ../../index.rst:25 +msgid "pip3 install -U pywebio" +msgstr "" + +#: ../../index.rst:27 +msgid "Development version::" +msgstr "نسخه توسعه::" + +#: ../../index.rst:29 +msgid "" +"pip3 install -U " +"https://code.aliyun.com/wang0618/pywebio/repository/archive.zip" +msgstr "" + +#: ../../index.rst:31 +msgid "**Prerequisites**: PyWebIO requires Python 3.5.2 or newer" +msgstr "**پیش نیاز ها**: PyWebIO به Python 3.5.2 یا جدید تر نیاز دارد" + +#: ../../index.rst:36 +msgid "Hello, world" +msgstr "سلام، دنیا" + +#: ../../index.rst:38 +msgid "" +"Here is a simple PyWebIO script to calculate the `BMI " +"`_ ::" +msgstr "" +"در اینجا یک اسکریپت PyWebIO ساده برای محاسبه `شاخص توده بدنی " +"`_ آورده شده است::" + +#: ../../index.rst:40 +#, python-format +msgid "" +"# A simple script to calculate BMI\n" +"from pywebio.input import input, FLOAT\n" +"from pywebio.output import put_text\n" +"\n" +"def bmi():\n" +" height = input(\"Input your height(cm):\", type=FLOAT)\n" +" weight = input(\"Input your weight(kg):\", type=FLOAT)\n" +"\n" +" BMI = weight / (height / 100) ** 2\n" +"\n" +" top_status = [(16, 'Severely underweight'), (18.5, 'Underweight'),\n" +" (25, 'Normal'), (30, 'Overweight'),\n" +" (35, 'Moderately obese'), (float('inf'), 'Severely " +"obese')]\n" +"\n" +" for top, status in top_status:\n" +" if BMI <= top:\n" +" put_text('Your BMI: %.1f. Category: %s' % (BMI, status))\n" +" break\n" +"\n" +"if __name__ == '__main__':\n" +" bmi()" +msgstr "" +"# یک اسکریپت ساده برای محاسبه شاخص توده بدنی\n" +"from pywebio.input import input, FLOAT\n" +"from pywebio.output import put_text\n" +"\n" +"def bmi():\n" +" height = input(\"قد خود را وارد کنید(سانتی متر):\", type=FLOAT)\n" +" weight = input(\"وزن خود را وارد کنید(کیلوگرم):\", type=FLOAT)\n" +"\n" +" BMI = weight / (height / 100) ** 2\n" +"\n" +" top_status = [(16, 'کمبود وزن شدید'), (18.5, 'کمبود وزن'),\n" +" (25, 'عادی'), (30, 'اضافه وزن'),\n" +" (35, 'چاق متوسط'), (float('inf'), 'چاق " +"شدید')]\n" +"\n" +" for top, status in top_status:\n" +" if BMI <= top:\n" +" put_text('شاخص توده بدنی شما: %.1f. دسته بندی: %s' % (BMI," +" status))\n" +" break\n" +"\n" +"if __name__ == '__main__':\n" +" bmi()" + +#: ../../index.rst:62 +msgid "" +"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:" +msgstr "" +"این فقط یک اسکریپت خیلی ساده است اگه شما PyWebIO را نادیده بگیرید، اما بعد از" +" استفاده " +"از توابع ورودی و خروجی ارائه شده توسط PyWebIO، شما می توانید با" +" کد در مرورگر تعامل برقرار کنید:" + +#: ../../index.rst:69 +msgid "" +"In the last line of the above code, changing the function call ``bmi()`` " +"to `pywebio.start_server(bmi, port=80) " +"` will start a bmi web service on " +"port 80 ( :demo_host:`online Demo ` )." +msgstr "" +"در آخرین خط کد بالا، تغییر فراخوانی تابع ``bmi()`` " +"به `pywebio.start_server(bmi, port=80) " +"` یک وب سرویس شاخص توده بدنی را روی " +"پورت 80 راه اندازی می کند ( :demo_host:`دمو آنلاین ` )." + +#: ../../index.rst:73 +msgid "" +"If you want to integrate the ``bmi()`` service into an existing web " +"framework, you can visit :ref:`Integration with a web framework " +"` section of this document." +msgstr "" +"اگر شما می خواهید که سرویس ``bmi()`` را با یک وب " +"فریم ورک موجود ادغام کنید، می توانید بخش :ref:`Integration with a web" +" framework " +"` این مستندات را ببینید." + +#: ../../index.rst:77 +msgid "Documentation" +msgstr "مستندات" + +#: ../../index.rst:78 +msgid "" +"This documentation is also available in `PDF and Epub formats " +"`_." +msgstr "" +"این مستندات همچنین در `فرمت های PDF و Epub " +"`_ در دسترس است." + +#: ../../index.rst:106 +msgid "Indices and tables" +msgstr "ایندکس ها و جداول" + +#: ../../index.rst:108 +msgid ":ref:`genindex`" +msgstr "" + +#: ../../index.rst:109 +msgid ":ref:`modindex`" +msgstr "" + +#: ../../index.rst:110 +msgid ":ref:`search`" +msgstr "" + +#: ../../index.rst:114 +msgid "Discussion and support" +msgstr "بحث و پشتیبانی" + +#: ../../index.rst:116 +msgid "" +"Need help when use PyWebIO? Make a new discussion on `Github Discussions " +"`_." +msgstr "" +"هنگام استفاده از PyWebIO نیاز به کمک دارید؟ یک بحث جدید در `Github" +" Discussions " +"`_ بسازید." + +#: ../../index.rst:118 +msgid "" +"Report bugs on the `GitHub issue " +"`_." +msgstr "" +"باگ ها را در `GitHub issue " +"`_ گزارش کنید." + diff --git a/docs/locales/fa/LC_MESSAGES/input.po b/docs/locales/fa/LC_MESSAGES/input.po new file mode 100644 index 00000000..831b2b69 --- /dev/null +++ b/docs/locales/fa/LC_MESSAGES/input.po @@ -0,0 +1,1120 @@ +# Copyright (C) Weimin Wang +# This file is distributed under the same license as the PyWebIO package. +# +# FIRST AUTHOR , 2022. +# Pikhosh , 2022. +msgid "" +msgstr "" +"Project-Id-Version: PyWebIO 1.5.2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-02-26 16:35+0330\n" +"PO-Revision-Date: 2022-02-28 14:19+0330\n" +"Last-Translator: Pikhosh \n" +"Language-Team: Persian <>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.9.1\n" +"Language: fa\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Lokalize 21.12.2\n" + +#: ../../input.rst:2 +msgid "``pywebio.input`` --- Get input from web browser" +msgstr "``pywebio.input`` --- دریافت ورودی از مرورگر وب" + +#: of pywebio.input:1 +msgid "" +"This module provides functions to get all kinds of input of user from the" +" browser" +msgstr "" + +#: of pywebio.input:3 +msgid "" +"There are two ways to use the input functions, one is to call the input " +"function alone to get a single input::" +msgstr "" + +#: of pywebio.input:5 +#, python-format +msgid "" +"name = input(\"What's your name\")\n" +"print(\"Your name is %s\" % name)" +msgstr "" + +#: of pywebio.input:8 +msgid "The other is to use `input_group` to get multiple inputs at once::" +msgstr "" + +#: of pywebio.input:10 +msgid "" +"info = input_group(\"User info\",[\n" +" input('Input your name', name='name'),\n" +" input('Input your age', name='age', type=NUMBER)\n" +"])\n" +"print(info['name'], info['age'])" +msgstr "" + +#: of pywebio.input:16 +msgid "" +"When use `input_group`, you needs to provide the ``name`` parameter in " +"each input function to identify the input items in the result." +msgstr "" + +#: of pywebio.input:20 +msgid "" +"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." +msgstr "" + +#: of pywebio.input:24 +msgid "" +"By default, the user can submit empty input 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)" +msgstr "" + +#: of pywebio.input:27 +msgid "" +"The input functions in this module is blocking, and the input form will " +"be destroyed after successful submission. If you want the form to always " +"be displayed on the page and receive input continuously, you can consider" +" the :doc:`pin <./pin>` module." +msgstr "" + +#: of pywebio.input:32 +msgid "Functions list" +msgstr "لیست توابع" + +#: of pywebio.input:36 +msgid "Function name" +msgstr "" + +#: of pywebio.input:37 +msgid "Description" +msgstr "" + +#: of pywebio.input:39 +msgid "`input `" +msgstr "" + +#: of pywebio.input:40 pywebio.input.input:1 +msgid "Text input" +msgstr "" + +#: of pywebio.input:42 +msgid "`textarea `" +msgstr "" + +#: of pywebio.input:43 +msgid "Multi-line text input" +msgstr "" + +#: of pywebio.input:45 +msgid "`select `" +msgstr "" + +#: of pywebio.input:46 pywebio.input.select:1 +msgid "Drop-down selection" +msgstr "" + +#: of pywebio.input:48 +msgid "`checkbox `" +msgstr "" + +#: of pywebio.input:49 +msgid "Checkbox" +msgstr "" + +#: of pywebio.input:51 +msgid "`radio `" +msgstr "" + +#: of pywebio.input:52 +msgid "Radio" +msgstr "" + +#: of pywebio.input:54 +msgid "`slider `" +msgstr "" + +#: of pywebio.input:55 +msgid "Slider" +msgstr "" + +#: of pywebio.input:57 +msgid "`actions `" +msgstr "" + +#: of pywebio.input:58 pywebio.input.actions:1 +msgid "Actions selection" +msgstr "" + +#: of pywebio.input:60 +msgid "`file_upload `" +msgstr "" + +#: of pywebio.input:61 pywebio.input.file_upload:1 +msgid "File uploading" +msgstr "" + +#: of pywebio.input:63 +msgid "`input_group `" +msgstr "" + +#: of pywebio.input:64 +msgid "Input group" +msgstr "" + +#: of pywebio.input:66 +msgid "`input_update `" +msgstr "" + +#: of pywebio.input:67 +msgid "Update input item" +msgstr "" + +#: of pywebio.input:71 +msgid "Functions doc" +msgstr "مستندات توابع" + +#: of pywebio.input.actions pywebio.input.checkbox pywebio.input.file_upload +#: pywebio.input.input pywebio.input.input_group pywebio.input.input_update +#: pywebio.input.radio pywebio.input.select pywebio.input.slider +#: pywebio.input.textarea +msgid "Parameters" +msgstr "پارامتر ها" + +#: of pywebio.input.input:3 +msgid "Label of input field." +msgstr "" + +#: of pywebio.input.input:4 +msgid "" +"Input type. Currently supported types are:`TEXT` , `NUMBER` , `FLOAT` , " +"`PASSWORD` , `URL` , `DATE` , `TIME` Note that `DATE` and `TIME` type " +"are not supported on some browsers, for details see " +"https://developer.mozilla.org/en-" +"US/docs/Web/HTML/Element/input#Browser_compatibility" +msgstr "" + +#: of pywebio.input.input:4 +msgid "" +"Input type. Currently supported types are:`TEXT` , `NUMBER` , `FLOAT` , " +"`PASSWORD` , `URL` , `DATE` , `TIME`" +msgstr "" + +#: of pywebio.input.input:6 +msgid "" +"Note that `DATE` and `TIME` type are not supported on some browsers, for " +"details see https://developer.mozilla.org/en-" +"US/docs/Web/HTML/Element/input#Browser_compatibility" +msgstr "" + +#: of pywebio.input.input:8 +msgid "" +"Input value validation function. If provided, the validation function " +"will be called when user completes the input field or submits the form. " +"``validate`` receives the input value as a parameter. When the input " +"value is valid, it returns ``None``. When the input value is invalid, it " +"returns an error message string. For example: .. exportable-codeblock::" +" :name: input-valid-func :summary: `input()` validation def " +"check_age(age): if age>30: return 'Too old' " +"elif age<10: return 'Too young' input('Input your age', " +"type=NUMBER, validate=check_age)" +msgstr "" + +#: of pywebio.input.input:8 +msgid "" +"Input value validation function. If provided, the validation function " +"will be called when user completes the input field or submits the form." +msgstr "" + +#: of pywebio.input.input:11 +msgid "" +"``validate`` receives the input value as a parameter. When the input " +"value is valid, it returns ``None``. When the input value is invalid, it " +"returns an error message string. For example:" +msgstr "" + +#: of pywebio.input.input:14 +msgid "" +"def check_age(age):\n" +" if age>30:\n" +" return 'Too old'\n" +" elif age<10:\n" +" return 'Too young'\n" +"input('Input your age', type=NUMBER, validate=check_age)" +msgstr "" + +#: of pywebio.input.input:25 +msgid "" +"A string specifying a name for the input. Used with `input_group()` to " +"identify different input items in the results of the input group. If call" +" the input function alone, this parameter can **not** be set!" +msgstr "" + +#: of pywebio.input.input:27 +msgid "The initial value of the input" +msgstr "" + +#: of pywebio.input.input:29 +msgid "" +"Put a button on the right side of the input field, and user can click the" +" button to set the value for the input. ``label`` is the label of the " +"button, and ``callback`` is the callback function to set the input value " +"when clicked. The callback is invoked with one argument, the " +"``set_value``. ``set_value`` is a callable object, which is invoked with " +"one or two arguments. You can use ``set_value`` to set the value for the " +"input. ``set_value`` can be invoked with one argument: " +"``set_value(value:str)``. The ``value`` parameter is the value to be set " +"for the input. ``set_value`` can be invoked with two arguments: " +"``set_value(value:any, label:str)``. Each arguments are described as " +"follows: * ``value`` : The real value of the input, can be any object. " +"it will not be passed to the user browser. * ``label`` : The text " +"displayed to the user When calling ``set_value`` with two arguments, the" +" input item in web page will become read-only. The usage scenario of " +"``set_value(value:any, label:str)`` is: You need to dynamically generate " +"the value of the input in the callback, and hope that the result " +"displayed to the user is different from the actual submitted data (for " +"example, result displayed to the user can be some user-friendly texts, " +"and the value of the input can be objects that are easier to process) " +"Usage example: .. exportable-codeblock:: :name: input-action " +":summary: `input()` action usage import time def " +"set_now_ts(set_value): set_value(int(time.time())) ts = " +"input('Timestamp', type=NUMBER, action=('Now', set_now_ts)) " +"put_text('Timestamp:', ts) # ..demo-only ## ---- from datetime " +"import date,timedelta def select_date(set_value): with " +"popup('Select Date'): put_buttons(['Today'], onclick=[lambda:" +" set_value(date.today(), 'Today')]) " +"put_buttons(['Yesterday'], onclick=[lambda: set_value(date.today() - " +"timedelta(days=1), 'Yesterday')]) d = input('Date', " +"action=('Select', select_date), readonly=True) put_text(type(d), d) " +"Note: When using :ref:`Coroutine-based session `" +" implementation, the ``callback`` function can be a coroutine function." +msgstr "" + +#: of pywebio.input.input:29 +msgid "" +"Put a button on the right side of the input field, and user can click the" +" button to set the value for the input." +msgstr "" + +#: of pywebio.input.input:31 +msgid "" +"``label`` is the label of the button, and ``callback`` is the callback " +"function to set the input value when clicked." +msgstr "" + +#: of pywebio.input.input:33 +msgid "" +"The callback is invoked with one argument, the ``set_value``. " +"``set_value`` is a callable object, which is invoked with one or two " +"arguments. You can use ``set_value`` to set the value for the input." +msgstr "" + +#: of pywebio.input.input:36 +msgid "" +"``set_value`` can be invoked with one argument: ``set_value(value:str)``." +" The ``value`` parameter is the value to be set for the input." +msgstr "" + +#: of pywebio.input.input:38 +msgid "" +"``set_value`` can be invoked with two arguments: ``set_value(value:any, " +"label:str)``. Each arguments are described as follows:" +msgstr "" + +#: of pywebio.input.input:40 +msgid "" +"``value`` : The real value of the input, can be any object. it will not " +"be passed to the user browser." +msgstr "" + +#: of pywebio.input.input:41 +msgid "``label`` : The text displayed to the user" +msgstr "" + +#: of pywebio.input.input:43 +msgid "" +"When calling ``set_value`` with two arguments, the input item in web page" +" will become read-only." +msgstr "" + +#: of pywebio.input.input:45 +msgid "" +"The usage scenario of ``set_value(value:any, label:str)`` is: You need to" +" dynamically generate the value of the input in the callback, and hope " +"that the result displayed to the user is different from the actual " +"submitted data (for example, result displayed to the user can be some " +"user-friendly texts, and the value of the input can be objects that are " +"easier to process)" +msgstr "" + +#: of pywebio.input.input:50 +msgid "Usage example:" +msgstr "" + +#: of pywebio.input.input:52 +msgid "" +"import time\n" +"def set_now_ts(set_value):\n" +" set_value(int(time.time()))\n" +"\n" +"ts = input('Timestamp', type=NUMBER, action=('Now', set_now_ts))\n" +"put_text('Timestamp:', ts) # ..demo-only\n" +"## ----\n" +"from datetime import date,timedelta\n" +"def select_date(set_value):\n" +" with popup('Select Date'):\n" +" put_buttons(['Today'], onclick=[lambda: set_value(date.today(), " +"'Today')])\n" +" put_buttons(['Yesterday'], onclick=[lambda: " +"set_value(date.today() - timedelta(days=1), 'Yesterday')])\n" +"\n" +"d = input('Date', action=('Select', select_date), readonly=True)\n" +"put_text(type(d), d)" +msgstr "" + +#: of pywebio.input.input:72 +msgid "" +"Note: When using :ref:`Coroutine-based session `" +" implementation, the ``callback`` function can be a coroutine function." +msgstr "" + +#: of pywebio.input.input:75 +msgid "" +"A callback function which will be called when the value of this input " +"field changed. The ``onchange`` callback is invoked with one argument, " +"the current value of input field. A typical usage scenario of " +"``onchange`` is to update other input item by using `input_update()`" +msgstr "" + +#: of pywebio.input.input:75 +msgid "" +"A callback function which will be called when the value of this input " +"field changed." +msgstr "" + +#: of pywebio.input.input:77 +msgid "" +"The ``onchange`` callback is invoked with one argument, the current value" +" of input field. A typical usage scenario of ``onchange`` is to update " +"other input item by using `input_update()`" +msgstr "" + +#: of pywebio.input.input:80 +msgid "" +"A hint to the user of what can be entered in the input. It will appear in" +" the input field when it has no value set." +msgstr "" + +#: of pywebio.input.input:81 +msgid "" +"Whether a value is required for the input to be submittable, default is " +"``False``" +msgstr "" + +#: of pywebio.input.input:82 +msgid "Whether the value is readonly(not editable)" +msgstr "" + +#: of pywebio.input.input:83 +msgid "" +"A list of predefined values to suggest to the user for this input. Can " +"only be used when ``type=TEXT``" +msgstr "" + +#: of pywebio.input.input:84 +msgid "" +"Help text for the input. The text will be displayed below the input field" +" with small font" +msgstr "" + +#: of pywebio.input.input:85 +#, python-format +msgid "" +"Additional html attributes added to the input element. reference: " +"https://developer.mozilla.org/zh-" +"CN/docs/Web/HTML/Element/input#%E5%B1%9E%E6%80%A7" +msgstr "" + +#: of pywebio.input.actions pywebio.input.checkbox pywebio.input.file_upload +#: pywebio.input.input pywebio.input.input_group pywebio.input.radio +#: pywebio.input.select pywebio.input.textarea +msgid "Returns" +msgstr "" + +#: of pywebio.input.input:87 +msgid "The value that user input." +msgstr "" + +#: of pywebio.input.textarea:1 +msgid "Text input area (multi-line text input)" +msgstr "" + +#: of pywebio.input.textarea:3 +msgid "" +"The number of visible text lines for the input area. Scroll bar will be " +"used when content exceeds." +msgstr "" + +#: of pywebio.input.textarea:4 +msgid "" +"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." +msgstr "" + +#: of pywebio.input.textarea:6 +msgid "" +"The minimum number of characters (UTF-16 code units) required that the " +"user should enter." +msgstr "" + +#: of pywebio.input.textarea:7 +msgid "" +"Enable a code style editor by providing the `Codemirror " +"`_ options: .. exportable-codeblock:: " +":name: textarea-code :summary: `textarea()` code editor style " +"res = textarea('Text area', code={ 'mode': \"python\", " +"'theme': 'darcula' }) put_code(res, language='python') # ..demo-" +"only You can simply use ``code={}`` or ``code=True`` to enable code " +"style editor. You can use ``Esc`` or ``F11`` to toggle fullscreen of code" +" style textarea. Some commonly used Codemirror options are listed " +":ref:`here `." +msgstr "" + +#: of pywebio.input.textarea:7 +msgid "" +"Enable a code style editor by providing the `Codemirror " +"`_ options:" +msgstr "" + +#: of pywebio.input.textarea:9 +msgid "" +"res = textarea('Text area', code={\n" +" 'mode': \"python\",\n" +" 'theme': 'darcula'\n" +"})\n" +"put_code(res, language='python') # ..demo-only" +msgstr "" + +#: of pywebio.input.textarea:19 +msgid "" +"You can simply use ``code={}`` or ``code=True`` to enable code style " +"editor. You can use ``Esc`` or ``F11`` to toggle fullscreen of code style" +" textarea." +msgstr "" + +#: of pywebio.input.textarea:22 +msgid "" +"Some commonly used Codemirror options are listed :ref:`here " +"`." +msgstr "" + +#: of pywebio.input.actions:39 pywebio.input.checkbox:7 +#: pywebio.input.file_upload:23 pywebio.input.radio:8 pywebio.input.select:29 +#: pywebio.input.slider:8 pywebio.input.textarea:24 +msgid "Those arguments have the same meaning as for `input()`" +msgstr "" + +#: of pywebio.input.textarea:26 +msgid "The string value that user input." +msgstr "" + +#: of pywebio.input.select:3 +msgid "" +"By default, only one option can be selected at a time, you can set " +"``multiple`` parameter to enable multiple selection." +msgstr "" + +#: of pywebio.input.select:5 +msgid "" +"list of options. The available formats of the list items are: * dict::" +" { \"label\":(str) option label, \"value\":(object) " +"option value, \"selected\":(bool, optional) whether the option is" +" initially selected, \"disabled\":(bool, optional) whether the " +"option is initially disabled } * tuple or list: ``(label, value, " +"[selected,] [disabled])`` * single value: label and value of option use " +"the same value Attention: 1. The ``value`` of option can be any JSON " +"serializable object 2. If the ``multiple`` is not ``True``, the list of " +"options can only have one ``selected`` item at most." +msgstr "" + +#: of pywebio.input.select:5 +msgid "list of options. The available formats of the list items are:" +msgstr "" + +#: of pywebio.input.actions:8 pywebio.input.select:7 +msgid "dict::" +msgstr "" + +#: of pywebio.input.select:9 +msgid "" +"{\n" +" \"label\":(str) option label,\n" +" \"value\":(object) option value,\n" +" \"selected\":(bool, optional) whether the option is initially " +"selected,\n" +" \"disabled\":(bool, optional) whether the option is initially " +"disabled\n" +"}" +msgstr "" + +#: of pywebio.input.select:16 +msgid "tuple or list: ``(label, value, [selected,] [disabled])``" +msgstr "" + +#: of pywebio.input.select:17 +msgid "single value: label and value of option use the same value" +msgstr "" + +#: of pywebio.input.select:19 +msgid "Attention:" +msgstr "" + +#: of pywebio.input.select:21 +msgid "The ``value`` of option can be any JSON serializable object" +msgstr "" + +#: of pywebio.input.select:22 +msgid "" +"If the ``multiple`` is not ``True``, the list of options can only have " +"one ``selected`` item at most." +msgstr "" + +#: of pywebio.input.select:24 +msgid "whether multiple options can be selected" +msgstr "" + +#: of pywebio.input.select:25 +msgid "" +"The value of the initial selected item. When ``multiple=True``, ``value``" +" must be a list. You can also set the initial selected option by setting " +"the ``selected`` field in the ``options`` list item." +msgstr "" + +#: of pywebio.input.select:28 +msgid "" +"Whether to select at least one item, only available when ``multiple=True``" +msgstr "" + +#: of pywebio.input.select:30 +msgid "" +"If ``multiple=True``, return a list of the values in the ``options`` " +"selected by the user; otherwise, return the single value selected by the " +"user." +msgstr "" + +#: of pywebio.input.checkbox:1 +msgid "" +"A group of check box that allowing single values to be " +"selected/deselected." +msgstr "" + +#: of pywebio.input.checkbox:3 pywebio.input.radio:3 +msgid "" +"List of options. The format is the same as the ``options`` parameter of " +"the `select()` function" +msgstr "" + +#: of pywebio.input.checkbox:4 pywebio.input.radio:4 +msgid "Whether to display the options on one line. Default is ``False``" +msgstr "" + +#: of pywebio.input.checkbox:5 +msgid "" +"The value list of the initial selected items. You can also set the " +"initial selected option by setting the ``selected`` field in the " +"``options`` list item." +msgstr "" + +#: of pywebio.input.checkbox:8 +msgid "A list of the values in the ``options`` selected by the user" +msgstr "" + +#: of pywebio.input.radio:1 +msgid "A group of radio button. Only a single button can be selected." +msgstr "" + +#: of pywebio.input.radio:5 +msgid "" +"The value of the initial selected items. You can also set the initial " +"selected option by setting the ``selected`` field in the ``options`` list" +" item." +msgstr "" + +#: of pywebio.input.radio:7 +msgid "" +"whether to must select one option. (the user can select nothing option by" +" default)" +msgstr "" + +#: of pywebio.input.radio:9 +msgid "" +"The value of the option selected by the user, if the user does not select" +" any value, return ``None``" +msgstr "" + +#: of pywebio.input.actions:3 +msgid "" +"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." +msgstr "" + +#: of pywebio.input.actions:6 +msgid "" +"list of buttons. The available formats of the list items are: * dict::" +" { \"label\":(str) button label, " +"\"value\":(object) button value, \"type\":(str, optional) button" +" type, \"disabled\":(bool, optional) whether the button is " +"disabled, \"color\":(str, optional) button color } " +"When ``type='reset'/'cancel'`` or ``disabled=True``, ``value`` can be " +"omitted * tuple or list: ``(label, value, [type], [disabled])`` * " +"single value: label and value of button use the same value The ``value``" +" of button can be any JSON serializable object. ``type`` can be: * " +"``'submit'`` : After clicking the button, the entire form is submitted " +"immediately, and the value of this input item in the final form is the" +" ``value`` of the button that was clicked. ``'submit'`` is the default" +" value of ``type`` * ``'cancel'`` : Cancel form. After clicking the " +"button, the entire form will be submitted immediately, and the form " +"value will return ``None`` * ``'reset'`` : Reset form. After clicking " +"the button, the entire form will be reset, and the input items will " +"become the initial state. Note: After clicking the ``type=reset`` " +"button, the form will not be submitted, and the ``actions()`` call " +"will not return The ``color`` of button can be one of: `primary`, " +"`secondary`, `success`, `danger`, `warning`, `info`, `light`, `dark`." +msgstr "" + +#: of pywebio.input.actions:6 +msgid "list of buttons. The available formats of the list items are:" +msgstr "" + +#: of pywebio.input.actions:10 +msgid "" +"{\n" +" \"label\":(str) button label,\n" +" \"value\":(object) button value,\n" +" \"type\":(str, optional) button type,\n" +" \"disabled\":(bool, optional) whether the button is disabled,\n" +" \"color\":(str, optional) button color\n" +"}" +msgstr "" + +#: of pywebio.input.actions:18 +msgid "" +"When ``type='reset'/'cancel'`` or ``disabled=True``, ``value`` can be " +"omitted" +msgstr "" + +#: of pywebio.input.actions:19 +msgid "tuple or list: ``(label, value, [type], [disabled])``" +msgstr "" + +#: of pywebio.input.actions:20 +msgid "single value: label and value of button use the same value" +msgstr "" + +#: of pywebio.input.actions:22 +msgid "The ``value`` of button can be any JSON serializable object." +msgstr "" + +#: of pywebio.input.actions:24 +msgid "``type`` can be:" +msgstr "" + +#: of pywebio.input.actions:26 +msgid "" +"``'submit'`` : After clicking the button, the entire form is submitted " +"immediately, and the value of this input item in the final form is the " +"``value`` of the button that was clicked. ``'submit'`` is the default " +"value of ``type``" +msgstr "" + +#: of pywebio.input.actions:29 +msgid "" +"``'cancel'`` : Cancel form. After clicking the button, the entire form " +"will be submitted immediately, and the form value will return ``None``" +msgstr "" + +#: of pywebio.input.actions:31 +msgid "" +"``'reset'`` : Reset form. After clicking the button, the entire form will" +" be reset, and the input items will become the initial state. Note: After" +" clicking the ``type=reset`` button, the form will not be submitted, and " +"the ``actions()`` call will not return" +msgstr "" + +#: of pywebio.input.actions:36 +msgid "" +"The ``color`` of button can be one of: `primary`, `secondary`, `success`," +" `danger`, `warning`, `info`, `light`, `dark`." +msgstr "" + +#: of pywebio.input.actions:40 +msgid "" +"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." +msgstr "" + +#: of pywebio.input.actions:44 +msgid "" +"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()``" +msgstr "" + +#: of pywebio.input.actions:47 +msgid "**usage scenes of actions() **" +msgstr "" + +#: of pywebio.input.actions:51 +msgid "Perform simple selection operations:" +msgstr "" + +#: of pywebio.input.actions:53 +#, python-format +msgid "" +"confirm = actions('Confirm to delete file?', ['confirm', 'cancel'],\n" +" help_text='Unrecoverable after file deletion')\n" +"if confirm=='confirm': # ..doc-only\n" +" ... # ..doc-only\n" +"put_markdown('You clicked the `%s` button' % confirm) # ..demo-only" +msgstr "" + +#: of pywebio.input.actions:63 +msgid "" +"Compared with other input items, when using `actions()`, the user only " +"needs to click once to complete the submission." +msgstr "" + +#: of pywebio.input.actions:65 +msgid "Replace the default submit button:" +msgstr "" + +#: of pywebio.input.actions:67 +msgid "" +"import json # ..demo-only\n" +" # ..demo-only\n" +"info = input_group('Add user', [\n" +" input('username', type=TEXT, name='username', required=True),\n" +" input('password', type=PASSWORD, name='password', required=True),\n" +" actions('actions', [\n" +" {'label': 'Save', 'value': 'save'},\n" +" {'label': 'Save and add next', 'value': 'save_and_continue'},\n" +" {'label': 'Reset', 'type': 'reset', 'color': 'warning'},\n" +" {'label': 'Cancel', 'type': 'cancel', 'color': 'danger'},\n" +" ], name='action', help_text='actions'),\n" +"])\n" +"put_code('info = ' + json.dumps(info, indent=4))\n" +"if info is not None:\n" +" save_user(info['username'], info['password']) # ..doc-only\n" +" if info['action'] == 'save_and_continue':\n" +" add_next() # ..doc-only\n" +" put_text('Save and add next...') # ..demo-only" +msgstr "" + +#: of pywebio.input.file_upload:3 +msgid "" +"Single value or list, indicating acceptable file types. The available " +"formats of file types are: * A valid case-insensitive filename " +"extension, starting with a period (\".\") character. For example: " +"``.jpg``, ``.pdf``, or ``.doc``. * A valid MIME type string, with no " +"extensions. For examples: ``application/pdf``, ``audio/*``, " +"``video/*``, ``image/*``. For more information, please visit: " +"https://developer.mozilla.org/en-" +"US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" +msgstr "" + +#: of pywebio.input.file_upload:3 +msgid "" +"Single value or list, indicating acceptable file types. The available " +"formats of file types are:" +msgstr "" + +#: of pywebio.input.file_upload:5 +msgid "" +"A valid case-insensitive filename extension, starting with a period " +"(\".\") character. For example: ``.jpg``, ``.pdf``, or ``.doc``." +msgstr "" + +#: of pywebio.input.file_upload:6 +msgid "" +"A valid MIME type string, with no extensions. For examples: " +"``application/pdf``, ``audio/*``, ``video/*``, ``image/*``. For more " +"information, please visit: https://developer.mozilla.org/en-" +"US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" +msgstr "" + +#: of pywebio.input.file_upload:11 +msgid "" +"A hint to the user of what to be uploaded. It will appear in the input " +"field when there is no file selected." +msgstr "" + +#: of pywebio.input.file_upload:12 +msgid "Whether to allow upload multiple files. Default is ``False``." +msgstr "" + +#: of pywebio.input.file_upload:13 +msgid "" +"The maximum size of a single file, exceeding the limit will prohibit " +"uploading. The default is 0, which means there is no limit to the size." +" ``max_size`` can be a integer indicating the number of bytes, or a " +"case-insensitive string ending with `K` / `M` / `G` (representing " +"kilobytes, megabytes, and gigabytes, respectively). E.g: " +"``max_size=500``, ``max_size='40K'``, ``max_size='3M'``" +msgstr "" + +#: of pywebio.input.file_upload:14 +msgid "" +"The maximum size of a single file, exceeding the limit will prohibit " +"uploading." +msgstr "" + +#: of pywebio.input.file_upload:14 +msgid "The default is 0, which means there is no limit to the size." +msgstr "" + +#: of pywebio.input.file_upload:16 +msgid "" +"``max_size`` can be a integer indicating the number of bytes, or a case-" +"insensitive string ending with `K` / `M` / `G` (representing kilobytes, " +"megabytes, and gigabytes, respectively). E.g: ``max_size=500``, " +"``max_size='40K'``, ``max_size='3M'``" +msgstr "" + +#: of pywebio.input.file_upload:20 +msgid "" +"The maximum size of all files. Only available when ``multiple=True``. The" +" default is 0, which means there is no limit to the size. The format is " +"the same as the ``max_size`` parameter" +msgstr "" + +#: of pywebio.input.file_upload:22 +msgid "" +"Indicates whether the user must specify a file for the input. Default is " +"``False``." +msgstr "" + +#: of pywebio.input.file_upload:24 +msgid "" +"When ``multiple=False``, a dict is returned:: { 'filename': file " +"name, 'content':content of the file (in bytes), 'mime_type': " +"MIME type of the file, 'last_modified': Last modified time " +"(timestamp) of the file } If there is no file uploaded, return " +"``None``. When ``multiple=True``, a list is returned. The format of the " +"list item is the same as the return value when ``multiple=False`` above. " +"If the user does not upload a file, an empty list is returned." +msgstr "" + +#: of pywebio.input.file_upload:24 +msgid "When ``multiple=False``, a dict is returned::" +msgstr "" + +#: of pywebio.input.file_upload:26 +msgid "" +"{\n" +" 'filename': file name,\n" +" 'content':content of the file (in bytes),\n" +" 'mime_type': MIME type of the file,\n" +" 'last_modified': Last modified time (timestamp) of the file\n" +"}" +msgstr "" + +#: of pywebio.input.file_upload:33 +msgid "If there is no file uploaded, return ``None``." +msgstr "" + +#: of pywebio.input.file_upload:35 +msgid "" +"When ``multiple=True``, a list is returned. The format of the list item " +"is the same as the return value when ``multiple=False`` above. If the " +"user does not upload a file, an empty list is returned." +msgstr "" + +#: of pywebio.input.file_upload:40 +msgid "" +"If uploading large files, please pay attention to the file upload size " +"limit setting of the web framework. When using :func:`start_server() " +"` or :func:`path_deploy() " +"` to start the PyWebIO application, the " +"maximum file size to be uploaded allowed by the web framework can be set " +"through the ``max_payload_size`` parameter." +msgstr "" + +#: of pywebio.input.file_upload:45 +msgid "" +"# Upload a file and save to server # ..doc-only\n" +"f = input.file_upload(\"Upload a file\") # ..doc-only\n" +"open('asset/'+f['filename'], 'wb').write(f['content']) # ..doc-only\n" +"\n" +"imgs = file_upload(\"Select some pictures:\", accept=\"image/*\", " +"multiple=True)\n" +"for img in imgs:\n" +" put_image(img['content'])" +msgstr "" + +#: of pywebio.input.slider:1 +msgid "Range input." +msgstr "" + +#: of pywebio.input.slider:3 +msgid "The initial value of the slider." +msgstr "" + +#: of pywebio.input.slider:4 +msgid "The minimum permitted value." +msgstr "" + +#: of pywebio.input.slider:5 +msgid "The maximum permitted value." +msgstr "" + +#: of pywebio.input.slider:6 +msgid "" +"The stepping interval. Only available when ``value``, ``min_value`` and " +"``max_value`` are all integer." +msgstr "" + +#: of pywebio.input.slider +msgid "return int/float" +msgstr "" + +#: of pywebio.input.slider:9 +msgid "" +"If one of ``value``, ``min_value`` and ``max_value`` is float, the return" +" value is a float, otherwise an int is returned." +msgstr "" + +#: of pywebio.input.input_group:1 +msgid "Input group. Request a set of inputs from the user at once." +msgstr "" + +#: of pywebio.input.input_group:3 +msgid "Label of input group." +msgstr "" + +#: of pywebio.input.input_group:4 +msgid "" +"Input items. The item of the list is the call to the single input " +"function, and the ``name`` parameter need to be passed in the single " +"input function." +msgstr "" + +#: of pywebio.input.input_group:6 +msgid "" +"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`` 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:" +msgstr "" + +#: of pywebio.input.input_group:6 +msgid "" +"validation function for the group. If provided, the validation function " +"will be called when the user submits the form." +msgstr "" + +#: of pywebio.input.input_group:8 +msgid "" +"Function signature: ``callback(data) -> (name, error_msg)``. ``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:" +msgstr "" + +#: of pywebio.input.input_group:13 +msgid "" +"def check_form(data):\n" +" if len(data['name']) > 6:\n" +" return ('name', 'Name to long!')\n" +" if data['age'] <= 0:\n" +" return ('age', 'Age cannot be negative!')\n" +"\n" +"data = input_group(\"Basic info\",[\n" +" input('Input your name', name='name'),\n" +" input('Repeat your age', name='age', type=NUMBER)\n" +"], validate=check_form)\n" +"\n" +"put_text(data['name'], data['age'])" +msgstr "" + +#: of pywebio.input.input_group:30 +msgid "" +"Whether the form can be cancelled. Default is ``False``. If " +"``cancelable=True``, a \"Cancel\" button will be displayed at the bottom " +"of the form. Note: If the last input item in the group is `actions()`, " +"``cancelable`` will be ignored." +msgstr "" + +#: of pywebio.input.input_group:30 +msgid "" +"Whether the form can be cancelled. Default is ``False``. If " +"``cancelable=True``, a \"Cancel\" button will be displayed at the bottom " +"of the form." +msgstr "" + +#: of pywebio.input.input_group:33 +msgid "" +"Note: If the last input item in the group is `actions()`, ``cancelable`` " +"will be ignored." +msgstr "" + +#: of pywebio.input.input_group:35 +msgid "" +"If the user cancels the form, return ``None``, otherwise a ``dict`` is " +"returned, whose key is the ``name`` of the input item, and whose value is" +" the value of the input item." +msgstr "" + +#: of pywebio.input.input_update:1 +msgid "" +"Update attributes of input field. This function can only be called in " +"``onchange`` callback of input functions." +msgstr "" + +#: of pywebio.input.input_update:4 +msgid "" +"The ``name`` of the target input item. Optional, default is the name of " +"input field which triggers ``onchange``" +msgstr "" + +#: of pywebio.input.input_update:6 +msgid "" +"The input parameters need to be updated. Note that those parameters can " +"not be updated: ``type``, ``name``, ``validate``, ``action``, ``code``, " +"``onchange``, ``multiple``" +msgstr "" + +#: of pywebio.input.input_update:10 +msgid "An example of implementing dependent input items in an input group:" +msgstr "" + +#: of pywebio.input.input_update:12 +msgid "" +"country2city = {\n" +" 'China': ['Beijing', 'Shanghai', 'Hong Kong'],\n" +" 'USA': ['New York', 'Los Angeles', 'San Francisco'],\n" +"}\n" +"countries = list(country2city.keys())\n" +"location = input_group(\"Select a location\", [\n" +" select('Country', options=countries, name='country',\n" +" onchange=lambda c: input_update('city', " +"options=country2city[c])),\n" +" select('City', options=country2city[countries[0]], name='city'),\n" +"])\n" +"put_text(location) # ..demo-only" +msgstr "" + diff --git a/docs/locales/fa/LC_MESSAGES/libraries_support.po b/docs/locales/fa/LC_MESSAGES/libraries_support.po new file mode 100644 index 00000000..cf18aaf5 --- /dev/null +++ b/docs/locales/fa/LC_MESSAGES/libraries_support.po @@ -0,0 +1,264 @@ +# Copyright (C) Weimin Wang +# This file is distributed under the same license as the PyWebIO package. +# +# FIRST AUTHOR , 2022. +# Pikhosh , 2022. +msgid "" +msgstr "" +"Project-Id-Version: PyWebIO 1.5.2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-02-26 16:35+0330\n" +"PO-Revision-Date: 2022-02-28 14:38+0330\n" +"Last-Translator: Pikhosh \n" +"Language-Team: Persian <>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.9.1\n" +"Language: fa\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Lokalize 21.12.2\n" + +#: ../../libraries_support.rst:2 +msgid "Libraries support" +msgstr "پشتیبانی کتابخانه ها" + +#: ../../libraries_support.rst:7 +msgid "Build stand-alone App" +msgstr "ساخت اپ مستقل" + +#: ../../libraries_support.rst:8 +msgid "" +"`PyInstaller `_ bundles a " +"Python application and all its dependencies into a folder or executable. " +"The user can run the packaged app without installing a Python interpreter" +" or any modules." +msgstr "" + +#: ../../libraries_support.rst:10 +msgid "" +"You can use PyInstaller to packages PyWebIO application into a stand-" +"alone executable or folder:" +msgstr "" + +#: ../../libraries_support.rst:12 +msgid "Create a pyinstaller spec (specification) file::" +msgstr "" + +#: ../../libraries_support.rst:14 +msgid "pyi-makespec app.py" +msgstr "" + +#: ../../libraries_support.rst:16 +msgid "You need replace ``app.py`` to your PyWebIO application file name." +msgstr "" + +#: ../../libraries_support.rst:18 +msgid "Edit the spec file, change the ``datas`` parameter of ``Analysis``::" +msgstr "" + +#: ../../libraries_support.rst:20 +msgid "" +"from pywebio.utils import pyinstaller_datas\n" +"\n" +"a = Analysis(\n" +" ...\n" +" datas=pyinstaller_datas(),\n" +" ..." +msgstr "" + +#: ../../libraries_support.rst:27 +msgid "" +"Build the application by passing the spec file to the pyinstaller " +"command::" +msgstr "" + +#: ../../libraries_support.rst:29 +msgid "pyinstaller app.spec" +msgstr "" + +#: ../../libraries_support.rst:32 +msgid "" +"If you want to create a one-file bundled executable, you need pass " +"``--onefile`` option in first step." +msgstr "" + +#: ../../libraries_support.rst:34 +msgid "" +"For more information, please visit: " +"https://pyinstaller.readthedocs.io/en/stable/spec-files.html" +msgstr "" + +#: ../../libraries_support.rst:40 +msgid "Data visualization" +msgstr "بصری سازی داده" + +#: ../../libraries_support.rst:41 +msgid "PyWebIO supports for data visualization with the third-party libraries." +msgstr "" + +#: ../../libraries_support.rst:44 +msgid "Bokeh" +msgstr "" + +#: ../../libraries_support.rst:46 +msgid "" +"`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." +msgstr "" + +#: ../../libraries_support.rst:48 +msgid "" +"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::" +msgstr "" + +#: ../../libraries_support.rst:51 +msgid "" +"from bokeh.io import output_notebook\n" +"from bokeh.io import show\n" +"\n" +"output_notebook(notebook_type='pywebio')\n" +"fig = figure(...)\n" +"...\n" +"show(fig)" +msgstr "" + +#: ../../libraries_support.rst:59 +msgid "See related demo on :charts_demo_host:`bokeh demo `" +msgstr "" + +#: ../../libraries_support.rst:61 +msgid "" +"In addition to creating ordinary charts, Bokeh can also build the Bokeh " +"applications by starting the `Bokeh server " +"`_. 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." +msgstr "" + +#: ../../libraries_support.rst:63 +msgid "" +"In PyWebIO, you can also use ``bokeh.io.show()`` to display a Bokeh App. " +"For the example, see `bokeh_app.py " +"`_." +msgstr "" + +#: ../../libraries_support.rst:65 +msgid "Bokeh App currently is only available in the default Tornado backend" +msgstr "" + +#: ../../libraries_support.rst:70 +msgid "pyecharts" +msgstr "" + +#: ../../libraries_support.rst:72 +msgid "" +"`pyecharts `_ is a python " +"plotting library which uses `Echarts " +"`_ as underlying implementation." +msgstr "" + +#: ../../libraries_support.rst:74 +msgid "" +"In PyWebIO, you can use the following code to output the pyecharts chart " +"instance::" +msgstr "" + +#: ../../libraries_support.rst:76 +msgid "" +"# `chart` is pyecharts chart instance\n" +"pywebio.output.put_html(chart.render_notebook())" +msgstr "" + +#: ../../libraries_support.rst:79 +msgid "" +"See related demo on :charts_demo_host:`pyecharts demo `" +msgstr "" + +#: ../../libraries_support.rst:86 +msgid "plotly" +msgstr "" + +#: ../../libraries_support.rst:88 +msgid "" +"`plotly.py `_ is an interactive, " +"open-source, and browser-based graphing library for Python." +msgstr "" + +#: ../../libraries_support.rst:90 +msgid "" +"In PyWebIO, you can use the following code to output the plotly chart " +"instance::" +msgstr "" + +#: ../../libraries_support.rst:92 +msgid "" +"# `fig` is plotly chart instance\n" +"html = fig.to_html(include_plotlyjs=\"require\", full_html=False)\n" +"pywebio.output.put_html(html)" +msgstr "" + +#: ../../libraries_support.rst:96 +msgid "See related demo on :charts_demo_host:`plotly demo `" +msgstr "" + +#: ../../libraries_support.rst:101 +msgid "pyg2plot" +msgstr "" + +#: ../../libraries_support.rst:103 +msgid "" +"`pyg2plot `_ is a python plotting " +"library which uses `G2Plot `_ as " +"underlying implementation." +msgstr "" + +#: ../../libraries_support.rst:105 +msgid "" +"In PyWebIO, you can use the following code to output the pyg2plot chart " +"instance::" +msgstr "" + +#: ../../libraries_support.rst:107 +msgid "" +"# `chart` is pyg2plot chart instance\n" +"pywebio.output.put_html(chart.render_notebook())" +msgstr "" + +#: ../../libraries_support.rst:110 +msgid "See related demo on :charts_demo_host:`plotly demo `" +msgstr "" + +#: ../../libraries_support.rst:113 +msgid "cutecharts.py" +msgstr "" + +#: ../../libraries_support.rst:115 +msgid "" +"`cutecharts.py `_ is a hand " +"drawing style charts library for Python which uses `chart.xkcd " +"`_ as underlying implementation." +msgstr "" + +#: ../../libraries_support.rst:117 +msgid "" +"In PyWebIO, you can use the following code to output the cutecharts.py " +"chart instance::" +msgstr "" + +#: ../../libraries_support.rst:119 +msgid "" +"# `chart` is cutecharts chart instance\n" +"pywebio.output.put_html(chart.render_notebook())" +msgstr "" + +#: ../../libraries_support.rst:122 +msgid "" +"See related demo on :charts_demo_host:`cutecharts demo `" +msgstr "" + diff --git a/docs/locales/fa/LC_MESSAGES/misc.po b/docs/locales/fa/LC_MESSAGES/misc.po new file mode 100644 index 00000000..f6531d3e --- /dev/null +++ b/docs/locales/fa/LC_MESSAGES/misc.po @@ -0,0 +1,122 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) Weimin Wang +# This file is distributed under the same license as the PyWebIO package. +# FIRST AUTHOR , 2022. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PyWebIO 1.5.2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-02-26 16:35+0330\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.9.1\n" + +#: ../../misc.rst:2 +msgid "Miscellaneous" +msgstr "" + +#: ../../misc.rst:7 +msgid "Commonly used Codemirror options" +msgstr "" + +#: ../../misc.rst:9 +msgid "" +"``mode`` (str): The language of code. For complete list, see " +"https://codemirror.net/mode/index.html" +msgstr "" + +#: ../../misc.rst:10 +msgid "" +"``theme`` (str): The theme to style the editor with. For all available " +"theme, see https://codemirror.net/demo/theme.html" +msgstr "" + +#: ../../misc.rst:11 +msgid "" +"``lineNumbers`` (bool): Whether to show line numbers to the left of the " +"editor." +msgstr "" + +#: ../../misc.rst:12 +msgid "" +"``indentUnit`` (int): How many spaces a block (whatever that means in the" +" edited language) should be indented. The default is 2." +msgstr "" + +#: ../../misc.rst:13 +msgid "``tabSize`` (int): The width of a tab character. Defaults to 4." +msgstr "" + +#: ../../misc.rst:14 +msgid "" +"``lineWrapping`` (bool): Whether CodeMirror should scroll or wrap for " +"long lines. Defaults to false (scroll)." +msgstr "" + +#: ../../misc.rst:16 +msgid "" +"For complete Codemirror options, please visit: " +"https://codemirror.net/doc/manual.html#config" +msgstr "" + +#: ../../misc.rst:21 +msgid "Nginx WebSocket Config Example" +msgstr "" + +#: ../../misc.rst:23 +msgid "" +"Assuming that the PyWebIO application is running at the " +"``localhost:5000`` address, if you want to access your PyWebIO " +"application via ``http://server_ip/some_path/tool``, a sample Nginx " +"configuration is as follows::" +msgstr "" + +#: ../../misc.rst:25 +msgid "" +"map $http_upgrade $connection_upgrade {\n" +" default upgrade;\n" +" '' close;\n" +"}\n" +"\n" +"server {\n" +" listen 80;\n" +"\n" +" location /some_path/ {\n" +" alias /path/to/pywebio/static/dir/;\n" +" }\n" +" location /some_path/tool {\n" +" proxy_read_timeout 300s;\n" +" proxy_send_timeout 300s;\n" +" proxy_http_version 1.1;\n" +" proxy_set_header Host $http_host;\n" +" proxy_set_header Upgrade $http_upgrade;\n" +" proxy_set_header Connection $connection_upgrade;\n" +" proxy_pass http://localhost:5000/;\n" +" }\n" +"}" +msgstr "" + +#: ../../misc.rst:48 +msgid "" +"The above configuration file hosts the static files of PyWebIO on the " +"``/some_path/`` path, and reverse proxy ``/some_path/tool`` to " +"``localhost:5000``." +msgstr "" + +#: ../../misc.rst:50 +msgid "" +"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::" +msgstr "" + +#: ../../misc.rst:52 +msgid "cp -r `python3 -c \"import pywebio; print(pywebio.STATIC_PATH)\"` ~/web" +msgstr "" + diff --git a/docs/locales/fa/LC_MESSAGES/outdate.po b/docs/locales/fa/LC_MESSAGES/outdate.po new file mode 100644 index 00000000..aaf7d608 --- /dev/null +++ b/docs/locales/fa/LC_MESSAGES/outdate.po @@ -0,0 +1,263 @@ +# Copyright (C) Weimin Wang +# This file is distributed under the same license as the PyWebIO package. +# +# FIRST AUTHOR , 2022. +# Pikhosh , 2022. +msgid "" +msgstr "" +"Project-Id-Version: PyWebIO 1.5.2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-02-26 16:35+0330\n" +"PO-Revision-Date: 2022-02-28 14:20+0330\n" +"Last-Translator: Pikhosh \n" +"Language-Team: Persian <>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.9.1\n" +"Language: fa\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Lokalize 21.12.2\n" + +#: ../../outdate.rst:2 +msgid "The outdated functions" +msgstr "" + +#: ../../outdate.rst:4 +msgid "" +"This section shows document of the deprecated functions in case you use " +"the previous version of PyWebIO." +msgstr "" + +#: ../../outdate.rst:6 +msgid "" +"Those functions still work in latest PyWebIO, however they may be removed" +" in future version." +msgstr "" + +#: ../../outdate.rst:9 +msgid "``output`` module" +msgstr "" + +#: of pywebio.output.style:1 +msgid "Customize the css style of output content" +msgstr "" + +#: of pywebio.output.style:3 +msgid "See :ref:`User Guide