查看原文
其他

如何实现网站国际化 (i18n)? 超详细攻略来了丨舜禹技术派

John Curtis 舜禹环球通Transphere
2024-09-09


要拓展海外市场,有一个符合当地市场语言和文化的官方网站至关重要;而要实现这个目标,首先要确保网站符合国际化的要求。那么,什么是国际化?为什么要先符合国际化要求?又要如何判断呢?我们在这里编写了一份超详细攻略,搭配可以实操的源代码,大家亲自动手试一试吧。


在讨论了网站国际化后,我们又补充了一些本地化的内容,以期展现更为清晰的全局图景。


1  什么是国际化 (i18n)?


网站国际化指的是对网站代码进行开发或修改,以支持目标地的语言及书写习惯(如单复数、日期等),让针对目标市场的本地化工作得以顺利开展。如果不先完成网站国际化,网站的底层结构会对本地化造成阻碍,甚至需要重写代码,徒增工作量。换言之,国际化是本地化的基础,做好国际化,才能更为高效地进行本地化。


2  您的网站为什么需要本地化?


网站经过本地化后,能够贴合新客户的文化和语言偏好。一个针对中国客户设计的网站可能并非适用于美国客户。这两个客户群体不仅语言不同,浏览习惯也有很大差异,因此必须区别对待。这并非仅仅是经验之谈,还有以下统计数据作为事实依据:


●87% 的消费者从不在外文网站上购物。

●65% 的消费者更喜欢浏览使用其母语的网站。

●64% 的买家认为,经本地化的内容更可信。


在所有投资中,用于改善客户用户体验的投资能带来最高回报比。WebFX 调查显示,每向用户体验投资一美元,就会收获 100 美元的回报——这意味着投资回报率高达 9900%!


但在启动网站本地化这项工作之前,网站必须符合国际化的要求。


3  查看网站是否已经国际化


没有国际化的网站通常有如下特征:


•包含硬编码,即字符串与代码混在一起,没有任何标签加以区分。如下面的代码中,黄色高亮部分即为硬编码:


硬编码字符串


• 不支持阿拉伯语、希伯来语等从右到左的语言。

未国际化版本

已国际化版本


•仅支持一种时区、数字格式及货币。

•无法切换语言/区域。

•不支持Unicode字符,等等……


4  前期准备


要开展网站国际化,我们会用到 PyCharm IDE(只是建议)。如果您想直接用 Python,推荐 3.10 版👇🏻

https://www.python.org/ftp/python/3.10.7/python-3.10.7-amd64.exe


如需了解如何安装 Python,请点击👇🏻

https://realpython.com/installing-python/


我们还需要用到下面两个 Python 库:


Flask-Babel: 为 Flask (Python) Web 应用提供 i18n 和 l10n 支持的库。

Flask: Python 编写的轻量级 Web 应用框架。


虽然编程不是必备能力,但却是加分项——许多难题将迎刃而解。


要练习如何实现网站国际化,首先要有个网站。您可以建一个,也可以从我们的GitHub仓库(https://github.com/Transphere-Sunyu/i18n-python) clone:


git clone https://github.com/Transphere-Sunyu/i18n-python.git


5  项目配置


新建i18n-python文件夹,并在这个文件夹下另外新建三个文件夹,即 static、localestemplates,以及一个 app.py 文件。


UNIX/Linux 系统:

mkdir i18n-python && cd i18n-pythonmkdir static locales templates && touch app.py


Windows 系统:

mkdir i18n-python && cd i18n-pythonmkdir static locales templates && type nul > app.py


运行以下命令,指向项目文件夹路径,将 Flask Flask-Babel 安装到项目中。


pip3 install Flask_Babel Flask


新建一个 babel.cfg 文件,向 Babel 指示在哪里查找翻译并添加以下代码:


[python: **.py][jinja2: **/templates/**.html]


前两行分别定义了 Python 和 Jinja2 模板文件的文件名模式。https://pypi.org/project/Jinja2/是一个可扩展的模板引擎,支持使用类似于 Python 语法的代码。它用传递过来的数据来生成最终文档。


项目文件夹结构如下所示:



6  后端设置


在 app.py 文件的开头导入以下模块:


from flask import Flask, render_template, request, sessionfrom flask_babel import Babelimport os


将下列代码添加到同一文件中:


app = Flask(__name__)
babel = Babel(app)
app.config['BABEL_DEFAULT_LOCALE'] = 'en'app.config['LANGUAGES'] = { 'en': 'English', 'zh': 'Chinese(Simplified)', 'ar': 'Arabic'}
app.config['SECRET_KEY'] = 'your secret key'
app.config["BABEL_TRANSLATION_DIRECTORIES"] = os.path.abspath('locales/')

# Make languages and current_languages variables# accessible in all the templates@app.context_processordef inject_conf_var(): return dict(languages=app.config['LANGUAGES'], current_language=session.get('lang', request.accept_languages.best_match(app.config['LANGUAGES'].keys())))

@babel.localeselectordef get_locale(): if request.args.get('lang'): session['lang'] = request.args.get('lang')
return session.get('lang', request.accept_languages.best_match(app.config['LANGUAGES'].keys()))

@app.route('/')def index(): get_locale() return render_template('index.html')

if __name__ == '__main__':    app.run()


请务必将“BABEL_TRANSLATION_DIRECTORIES”的值替换为翻译文件夹的路径。


借助👇🏻https://flask.palletsprojects.com/en/2.2.x/templating/#context-processorslanguagecurrent_language 变量能够以字典形式在每个模板中使用,如下所示。


{'languages': {'en': 'English', 'zh': 'Chinese(Simplified)'}, 'current_language': 'en'}


7  替换硬编码字符串


硬编码字符串是嵌在HTML代码中的文本。如果不处理硬编码,增加语言时会非常麻烦。有一种处理方法是用 _() 文本标记将 HTML 代码中的字符串(即要翻译的文本)括号括起来,向 Flask Babel 表明待译字符串,即 {{ _("HTML string!")}},如下所示:

 

<div class="ui-section-hero--content"> <h1>{{ _('Design better.') }}</h1> <p class="ui-text-intro"> {{ _('Design Mobile UI faster and better with our product and produce professional designs for your business') }} </p></div>


这样,以上这段代码已经符合国际化的要求,因为其中的待译文字可以方便提取、翻译并和地区关联,用户可通过选择地区,让系统呈现相应的文字。


8  生成待译文件


运行以下命令,从 html 文件中提取字符串。


pybabel extract -F babel.cfg -o messages.pot .


如果您的代码是从咱们的GitHub仓库clone的,就会看到以下提示:


extracting messages from app.pyextracting messages from templates\index.html


pybabel extract 命令会读取 -F 选项中指定的配置文件,然后扫描目录中与配置源相匹配的所有文件。默认情况下,pybabel 会查找作为文本标记的 _()-o 选项确定了输出 .pot 文件的名称。


pybabel init -i messages.pot -d locales -l zh


pybabel init 命令对 messages.pot 进行初始化,指定其译文为中文,并生成 translation.po 文件,如下所示。


#: templates/index.html:62 templates/next.html:62msgid "Design better."msgstr ""
#: templates/index.html:63 templates/next.html:63msgid """Design Mobile UI faster and better with our product and produce ""professional designs for your business"msgstr ""


msgid 为源语言字符串,而 msgstr 为目标语言字符串。


9  翻译字符串


可以用Trados来翻译刚刚生成的 translation.po 文件。新建项目,导入该文件:



Trados内嵌的解析器已经将待译文字提取出来,打开文件直接翻译即可:



翻译完成后,将文件导出到locales文件夹(locales/zh/LC_MESSAGES)。此时,messages.po 文件中的 msgstr会被译文填充,如下所示:


#: templates/index.html:71 templates/next.html:71msgid "Available on Android and iOS."msgstr "可在 Android 和 iOS 上使用。"
#: templates/index.html:86 templates/next.html:86msgid "Features"msgstr "功能"


运行下列命令,将区域语言 (locales) 文件夹中的翻译文件编译为 .mo 文件,而 flask babel 会用这些文件来加载网站翻译。


pybabel compile -d locales


10  添加语言选择器


添加语言选择器后,用户可以选择不同语言。


为实现这个功能,先在 body 标签底部添加👇🏻https://getbootstrap.com/docs/5.2/getting-started/download/#cdn-via-jsdelivr代码:


<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-u1OknCvxWvY5kfmNBILK2hRnQC3Pr17a+RTT6rIHI7NnikvbZlHgTPOOmMi466C8" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js" integrity="sha384-oBqDVmMz9ATKxIep9tiCxS/Z9fNfEXiDAYTujMAeBAsjFuCZSmKbSSUnQlmh/jp3"        crossorigin="anonymous"></script>


然后将下面的代码添加到 header 标签中:


 <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT" crossorigin="anonymous">


通过以下命令创建一个下拉菜单,其中包含网站支持的所有语言:


<!-- MENU --> <div class="dropdown"> <button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"> {{ current_language }} </button> <ul class="dropdown-menu"> {% for language in languages.items() %} <li><a class="dropdown-item" href="{{url_for('index',lang=language[0]) }}"> {{ language[1] }}</a></li> {% endfor %}
</ul>            </div>


下拉菜单截图:


用了上文提到的👇🏻

https://flask.palletsprojects.com/en/2.2.x/templating/#context-processors装饰器,便可在 html 文件中访问 current_languagelanguage 变量。


.items() 方法以列表返回元组形式的语言,其经过循环访问后生成语言列表,以下拉列表显示。


运行下列命令,在浏览器上查看网站并切换语言。


flask run


以下是一些翻译成简体中文 (zh) 的网页截图。


11 更新待译字符串


若要在网页上新增文本,先按步骤7替换硬编码字符串;再在index.html中添加段落标签,标签间放入新的待译字符串。


<p class="ui-text-intro">{{ _('Free for 3 months') }}</p>


运行以下命令提取待译字符串。


pybabel extract -F babel.cfg -o messages.pot .


messages.pot 文件会更新,其中新增待译字符串。

再运行 update 命令,更新 message.po 文件:


pybabel update -i messages.pot -d locales


在 Trados或其他 CAT 工具中翻译 message.po 文件,完成后导回,并运行 compile 命令:


pybabel compile -d locales


12  向网站添加多语种内容


若您按照以上步骤操作,会发现用代码在网站上添加一种新的语言并不难,真正的难点在于如何呈现符合目标地语言文化习惯的内容。有些内容若直接从中文翻译,往往无法让目标读者产生共鸣,纯属白花钱;而若译文违反了当地的法律法规或者触碰了当地人的禁忌,引起舆论声讨,就更得不偿失了。


鉴于此,您可以考虑和成熟的语言服务商合作,以专业的方式开展网站本地化。语言服务商不仅能确保多语言内容的地道性和合规性,还可以提供技术支持,让整个本地化流程更为自动化和高效。并且,有些语言服务商还可以省略翻译环节,让当地写手或艺术家直接创作内容,这样更能打动人心、获得认同,是打开或拓展当地市场不可或缺的助力。


舜禹环球通的母语内容创作团队为多家知名公司提供服务,可从语言质量、设计及搜索引擎优化 (SEO) 等维度出具专业的网站内容分析报告,助力您的网站发挥出最大价值。




欢迎关注 舜禹环球通Transphere 微信公众号,回复关键字网站 获取本文英文版文档。


Scan or long-press the QR Code above to follow our Official Account. Reply with "website" to receive the English version.


本文作者/John Curtis

审核/Leo


往期

推荐

年度热门岗位放出!三大城市30名+译员招募!专业不限!

游戏本地化需要关注的七大挑战丨舜禹技术派

做一个有温度的企业 用行动彰显舜禹担当

继续滑动看下一个
舜禹环球通Transphere
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存