来自客户端的 Ajax
因此,现在服务器能够通过 /translate URL 提供翻译,当用户单击我上面添加的“翻译”链接时,我需要调用此 URL,传递需要翻译的文本、源语言和目标语言。 如果你不熟悉在浏览器中使用 JavaScript,这将是一个很好的学习机会。
在浏览器中使用 JavaScript 时,当前显示的页面在内部被表示为文档对象模型(DOM)。 这是一个引用页面中所有元素的层次结构。 在此上下文中运行的 JavaScript 代码可以更改 DOM 以触发页面中的更改。
我们首先需要讨论的是,在浏览器中运行的 JavaScript 代码如何获取需要发送到服务器中运行的翻译函数的三个参数。 为了获得文本,我需要找到包含用户动态正文的 DOM 内的节点并获取它的内容。 为了便于识别包含用户动态的 DOM 节点,我将为它们附加一个唯一的 ID。 如果你查看 _post.html 模板,则呈现用户动态正文的行只会读取 {{post.body}}
。 我要做的是将这些内容包装在一个 <span>
元素中。 这不会在视觉上改变任何东西,但它给了我一个可以插入标识符的地方:
app/templates/_post.html :给每条用户动态添加 ID。
<span id="post{{ post.id }}">{{ post.body }}</span>
这将为每条用户动态分配一个唯一标识符,格式为 post1
, post2
等,其中数字与每条用户动态的数据库标识符相匹配。 现在每条用户动态都有一个唯一的标识符,给定一个 ID 值,我可以使用 jQuery 定位 <span>
元素并提取其中的文本。 例如,如果我想获得 ID 为 123 的用户动态的文本,我可以这样做:
$('#post123').text()
这里的$符号是 jQuery 库提供的函数的名称。 这个库被 Bootstrap 使用,所以它已经被 Flask-Bootstrap 包含。 #
是 jQuery 使用的“选择器”语法的一部分,这意味着接下来是元素的 ID。
我也希望有一个地方可以在我从服务器收到翻译文本后插入翻译文本。 我要做的是将“翻译”链接替换为翻译文本,因此我还需要为该节点提供唯一标识符:
app/templates/_post.html :为翻译链接添加 ID。
<span id="translation{{ post.id }}">
<a href="#">{{ _('Translate') }}</a>
</span>
因此,现在对于一个给定的用户动态 ID,我有一个用于用户动态的 post <ID>
节点和一个对应的 translation <ID>
节点,我可以在用翻译后的文本替换翻译链接时用到它们。
下一步是编写一个可以完成所有翻译工作的函数。 该函数将利用输入和输出 DOM 节点以及源语言和目标语言,向服务器发出携带必须的三个参数的异步请求,并在服务器响应后用翻译后的文本替换翻译链接。 这听起来像很多工作,但实现相当简单:
app/templates/base.html :客户端翻译函数。
{% block scripts %}
...
<script>
function translate(sourceElem, destElem, sourceLang, destLang) {
$(destElem).html('<img src="{{ url_for('static', filename='loading.gif') }}">');
$.post('/translate', {
text: $(sourceElem).text(),
source_language: sourceLang,
dest_language: destLang
}).done(function(response) {
$(destElem).text(response['text'])
}).fail(function() {
$(destElem).text("{{ _('Error: Could not contact server.') }}");
});
}
</script>
{% endblock %}
前两个参数是用户动态和翻译链接节点的唯一 ID,后两个参数是源语言和目标语言代码。
该函数从一个很好的接触开始:它添加一个 加载器 替换翻译链接,以便用户知道翻译正在进行中。 这是通过使用 $(destElem).html()
函数完成的,它用基于 <img>
元素的新 HTML 内容替换定义为翻译链接的原始 HTML。 对于加载器,我将使用一个小的动画 GIF,它已添加到 Flask 为静态文件保留的 app/static 目录中。 为了生成引用这个图像的 URL,我使用 url_for()
函数,传递特殊的路由名称 static
并给出图像的文件名作为参数。 你可以在本章的 下载包 中找到 loading.gif 图像。
现在我用一个优雅的加载器代替了翻译链接,以便用户知道要等待翻译出现。 下一步是将 POST 请求发送到我在前一节中定义的 /translate URL。 为此,我也将使用 jQuery,本处使用 $ .post()
函数。 这个函数以一种类似于浏览器提交 Web 表单的格式向服务器提交数据,这很方便,因为它允许 Flask 将这些数据合并到 request.form
字典中。 $ .post()
的参数是两个,第一个是发送请求的 URL,第二个是包含服务器期望的三个数据项的字典(或者称之为对象,因为这些是在 JavaScript 中调用的)。
你可能知道 JavaScript 对回调函数(或者称为 promises 的更高级的回调形式)友好。 现在要做的就是说明一旦这个请求完成并且浏览器接收到响应,我想完成的事情。 在 JavaScript 中没有需要等待的事情,一切都是 异步 。 我需要做的是提供一个回调函数,浏览器在接收到响应时调用它。 而且,为了使所有内容尽可能健壮,我想指出在出现错误的情况下该怎么做,以作为处理错误的第二个回调函数。 有几种方法可以指定这些回调,但在这种情况下,使用 promises 可以使代码更加清晰。 语法如下:
$.post(<url>, <data>).done(function(response) {
// success callback
}).fail(function() {
// error callback
})
promise 语法允许将 $ .post()
调用的返回值“传入”回调函数作为参数。 在成功回调中,我所需要做的就是使用翻译后的文本调用 $(destElem).text()
,该文本在字典中 text
键下。 在出现错误的情况下,我也是这样做的,但是我显示的文本是一条通用的错误消息,我会确保它会作为可翻译的文本编入基础模板中。
所以现在唯一剩下的就是通过用户点击翻译链接来触发具有正确参数的 translate()
函数。 存在若干方法可以做到这一点,我要做的是将该函数的调用嵌入链接的 href
属性中:
app/templates/_post.html :翻译链接处理器。
<span id="translation{{ post.id }}">
<a href="javascript:translate(
'#post{{ post.id }}',
'#translation{{ post.id }}',
'{{ post.language }}',
'{{ g.locale }}');">{{ _('Translate') }}</a>
</span>
链接的 href
元素可以接受任何 JavaScript 代码,如果它带有 javascript:
前缀的话,那么这是一种方便的方式来调用翻译函数。 因为这个链接将在客户端请求页面时在服务器端渲染,所以我可以使用 {{}}
表达式来为函数生成四个参数。 每条用户动态都有自己的翻译链接,以及其唯一生成的参数。 post <ID>
和 translation <ID>
需要渲染具体的 ID,它们都需要在被使用时加上 #
前缀。
现在实时翻译功能已经完成! 如果你在环境中设置了有效的 Microsoft Translator API Key,则现在应该能够触发翻译。 假设你的浏览器设置为偏好英语,则需要使用其他语言撰写文章以查看“翻译”链接。 下面你可以看到一个例子:
在本章中,我介绍了一些需要翻译成应用支持的所有语言的新文本,因此有必要更新翻译目录:
(venv) $ flask translate update
对于你自己的项目,需要编辑每个语言存储库中的 messages.po 文件以包含这些新测试的翻译,不过我已经在本章的下载包或 GitHub 存储库中创建了西班牙语翻译。
要完成新的翻译,还需要执行编译:
(venv) $ flask translate compile
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论