自定义Frappe应用中的翻译

如何在自定义 Frappe 应用中添加和管理翻译:分步指南


1. 创建 translations 文件夹

步骤:
在您的自定义应用目录中,于以下位置创建一个名为 translations 的文件夹:

apps/your-app/your-app/translations/

为什么?
Frappe 会自动检测此文件夹。它遵循“约定优于配置”的原则,因此将翻译文件放在此处可确保它们无需额外设置即可被识别。


2. 添加翻译 CSV 文件

步骤:
在 translations 文件夹中为每种语言创建一个 CSV 文件。例如:

  • ar.csv(阿拉伯语)
  • es.csv(西班牙语)

CSV 结构:

"source_string","translated_string","context"
"agent","توكيل",""
"continue","إستكمال",""

为什么?

  • 第 1 列(source_string):代码中使用的原始字符串(例如:_("continue"))。
  • 第 2 列(translated_string):该字符串的翻译版本。
  • 第 3 列(context):可选。用于澄清翻译的上下文。

第三列是可选的,可以留空。


3. 在代码中使用可翻译字符串

步骤:
在您的 Python、HTML 或 JavaScript 代码中使用 _() 包裹字符串:

from frappe import _

def my_function():
    message = _("continue")  # Will be replaced with "إستكمال" for Arabic users

为什么?
_() 函数将字符串标记为可翻译。在运行时,Frappe 会根据用户的语言偏好替换它们。


4. 构建站点

仅当您在自定义前端 JS 中使用 __() 并更改了 JS 文件时才需要。

步骤:
运行构建命令:

bench --site your-site build

5. 验证翻译

步骤:

  • 在 Frappe 中将用户语言切换为阿拉伯语(或目标语言)。
  • 检查 _("continue") 现在是否显示为 "إستكمال"。

为什么?
这确认了 Frappe 能正确地将源字符串映射到其对应的翻译版本。


关键说明

语言代码

  • CSV 文件名必须与 Frappe 的语言代码匹配(例如:阿拉伯语为 ar)。
  • 您可以在 Frappe > 语言设置 中找到这些代码。

文件夹位置

  • translations 文件夹必须位于应用包目录的根目录(不能在子模块内)。

性能

  • 翻译在构建期间会被缓存。
  • 编辑翻译文件后,务必重启 bench。

回退行为

  • 如果某个字符串未被翻译,Frappe 将使用原始(源)字符串。

我需要构建或迁移站点吗?

不需要,Frappe 会根据登录用户的语言偏好,在运行时动态从您的 translations/lang.csv 文件中加载翻译。
您只需刷新浏览器或在必要时清除缓存即可。

仅当您在自定义前端 JS 中使用 __() 并更改了 JS 文件时,才需要 bench build。


示例工作流程

  1. 创建:

    apps/my_app/my_app/translations/ar.csv
    
  2. 添加条目:

    "welcome_message","مرحبا بك!",""
    
  3. 在代码中使用:

    _("welcome_message")
    
  4. 清除缓存:

  • 如果翻译未立即生效,请使用它
    bench --site my-site clear-cache
    
  1. 构建:
  • 仅当您在自定义前端 JS 中使用 __() 并更改了 JS 文件时才需要
    bench --site my-site build
    
  1. 在阿拉伯语界面中进行测试。

解释上下文?

上下文本质上是一种元数据,
用于向翻译使用者说明该翻译应在何时何地使用。
因为有时同一个词会有不同的含义。

例如:

"charge","شحن",""
"charge","رسوم",""

这里我们有相同的词,但含义不同(使用上下文不同)
因此,为了区分它们,我们需要为其提供上下文。

"charge","شحن","mobile phone charge"
"charge","رسوم","invoice line"

在代码中:

_("charge") # here we don't know which meaning (context to use)
_("charge", context="mobile phone charge") # here we mean شحن
_("charge", context="invoice line") # here we mean رسوم

站点

站点目录

Frappe 是一个多租户平台,每个租户被称为一个站点。站点存在于
名为 sites 的目录中,在运行 frappe 命令或其他服务(如 Celery worker 或 WSGI 服务器)时,该目录被视为当前工作目录。

您可以通过环境变量 SITES_DIR 设置 sites_dir,或者向 frappe 命令传递
--sites_dir 选项。

除了站点之外,sites_dir 还应包含以下内容。

apps.txt

apps.txt 包含一个 Python 包列表,这些包将被视为 Frappe 应用。您打算在站点中使用的每个
frappe 应用都应在此文件中有一条记录。
此外,这些应用还应位于 PYTHONPATH 中。有关更多信息,请参阅
Frappe 应用。

common_site_config.json

common_site_config.json 是一个可选文件。所有站点通用的配置
可以放在此文件中。

assets

assets 包含需要提供给浏览器客户端使用的文件。
这些文件通常包括 *.js、*.css、*.png 文件。此目录是使用
bench build 命令自动生成的。

languages.txt

languages.txt 是一个自动生成的文件,它将每种语言映射到其对应的代码。

站点

站点是 sites_dir 中的一个目录,代表 Frappe 平台中的一个租户。

目录结构

site
├── locks
├── private
│   └── backups
├── public
│   └── files
│ └── testfile.txt
└── site_config.json

  • locks 目录由调度器使用,通过
    文件锁机制来同步各种任务。

  • private 目录包含需要认证才能访问的文件。
    目前,该目录仅限于备份文件。

  • public 目录包含可以直接提供的文件。在上述
    示例中,testfile.txt 可以通过 URL 访问,
    http://site/files/testfile.txt

  • site_config.json 包含站点特定的配置

站点配置

请参阅 site_config.json 的配置选项

站点解析

在响应 HTTP 请求时,系统会根据以下条件自动选择一个站点:

  • HTTP 请求中的 Host 头与某个站点匹配
  • HTTP 请求中的 X-Frappe-Site-Name 头与某个站点匹配

也可以通过以下命令启动开发服务器,强制其提供特定站点:
bench --site SITENAME serve

添加新站点

要添加新站点,请在您的 bench 实例中执行以下命令:

bench new-site SITENAME

将站点设置为当前站点

要强制将某个站点用作默认站点,请执行以下操作:

bench use SITENAME

为确保设置成功,请检查 currentsite.txt 的内容(位于 bench 实例的 sites 文件夹中),其中应包含 SITENAME。

如何启用备份加密

备份过程中创建的文件可以使用自动生成的密钥进行加密。

系统要求

对于 MacOS,请确保系统中已安装 gnupg。使用以下命令安装 gnupg:

brew install gnupg

大多数 Linux 发行版已经预装了 GnuPG,当前版本很可能默认使用 GnuPG 2.0。

加密备份选项

  1. 打开系统设置表单。
  2. 在备份部分中,勾选加密备份复选框。

系统使用由站点配置提供的自动生成的密钥。如果找不到此类密钥,则会生成一个新密钥。任何系统管理员之后都可以在下载备份页面查看该密钥。

它会对公共文件、私有文件以及部分备份文件进行加密。

备份加密状态

  1. 加密备份存储在常规备份的相同位置:YOUR_BENCH/sites/{site}/private/backups。
  2. 加密备份可以从下载备份页面下载。
  3. 加密备份通过 key icon 进行区分。

备份加密密钥

  1. 要获取备份加密密钥,请前往下载备份页面。
  2. 点击“获取加密密钥”按钮并验证您的密码。

复制该密钥以恢复加密的备份文件。

恢复加密的备份文件

  1. 可以使用 bench restore SQL_FILE_PATH 恢复文件,无需 --backup-encryption-key,因为它会自动从站点配置中获取。
  2. 如果因密钥错误导致恢复失败,可以使用 --backup-encryption-key 提供密钥来恢复文件。
  3. 用法:
    对于完整备份文件
    bench --site {site} restore --backup-encryption-key {key} [OPTIONS]
    对于部分备份文件
    bench --site {site} partial-restore --backup-encryption-key {key} [OPTIONS]

手动解密加密的备份文件

gpg --yes --passphrase $BACKUP_ENCRYPTION_KEY --pinentry-mode loopback -o $OUTPUT_FILE -d $INPUT_FILE

Frappe 异步请求

在 Frappe Framework 中,你可以通过 frappe.call 来管理 ajax 调用。frappe.call 以异步方式工作,即发送请求并通过回调机制处理响应。

frappe.call 结构

frappe.call({
 method: "",
 type: "POST",
 args: {},
 success: function(r) {},
 error: function(r) {},
 always: function(r) {},
 btn: opts.btn,
 freeze: false,
 freeze_message: "",
 async: true,
 url: "" || frappe.request.url,
});

参数说明

  • method:白名单后端方法的点分路径
  • type:字符串参数,HTTP 请求类型 “GET”、”POST”、”PUT”、”DELETE”。默认设置为 “POST”。
  • args:关联数组,随请求传递的参数。
  • success:函数参数,代码片段,在请求成功执行后运行
  • error:函数参数,代码片段,在请求失败后执行
  • always:函数参数,代码片段,无论成功或失败都会执行
  • btn:对象参数,触发对象
  • freeze:布尔参数,如果设置为 true,则在收到响应前冻结实例
  • freeze_message:字符串参数,屏幕处于冻结状态时显示的消息。
  • async:布尔参数,默认设置为 true。因此每次 frappe.call 都是异步的。若要使调用同步,请将参数值设置为 false
  • url:字符串参数,发起请求的位置

如何使用 frappe.call?

调用标准 API

frappe.call({
 method: 'frappe.client.get_value',
 args: {
 'doctype': 'Item',
 'filters': {'name': item_code},
 'fieldname': [
 'item_name',
 'web_long_description',
 'description',
 'image',
 'thumbnail'
 ]
 },
 callback: function(r) {
 if (!r.exc) {
 // code snippet
 }
 }
});
  • 参数说明:

  • doctype:你要获取信息的 DocType 名称

  • filters:条件限定符

  • fieldname:你可以在数组中指定希望在响应中返回的字段

调用白名单方法

  • 在客户端,我们指定要调用的服务端 method。这是通过服务端 Python 模块的点分路径,最后一部分是方法名。
frappe.call({
method: "frappe.core.doctype.user.user.get_all_roles", //dotted path to server method
callback: function(r) {
// code snippet
}
});
  • 上述请求调用服务端方法 get_all_roles,该方法位于文件 $MY_BENCH/apps/frappe/frappe/core/doctype/user/user.py 中:
@frappe.whitelist()
def get_all_roles():
// business logic
return value

注意:任何需要通过 frappe.call() 访问的服务端方法都必须使用装饰器 @frappe.whitelist() 进行白名单授权。

Frappe 应用

Frappe 应用是使用 Frappe 平台的 Python 包。它们可以存放在 Python 路径
中的任何位置,
并且必须在 apps.txt 文件中有一个条目。

创建应用

Frappe 自带一个新应用的样板。命令 bench new-app app-name 通过启动一个交互式 shell 来帮助你开始创建新应用。

 % bench new-app sample_app
 App Name: sample_app
 App Title: Sample App
 App Description: This is a sample app.
 App Publisher: Acme Inc.
 App Icon: icon-linux
 App Color: #6DAFC9
 App Email: [email protected]
 App URL: http://example.com
 App License: MIT

上述命令将创建一个具有以下目录结构的应用。

 sample_app
 ├── license.txt
 ├── MANIFEST.in
 ├── README.md
 ├── sample_app
 │   ├── __init__.py
 │   ├── sample_app
 │   │   └── __init__.py
 │   ├── config
 │   │   ├── desktop.py
 │   │   └── __init__.py
 │   ├── hooks.py
 │   ├── modules.txt
 │   ├── patches.txt
 │   └── templates
 │   ├── generators
 │   │   └── __init__.py
 │   ├── __init__.py
 │   ├── pages
 │   │   └── __init__.py
 │   └── statics
 └── setup.py

该样板包含的文件刚好足以在 [工作台] 上显示你的应用图标。

应用中的文件

hooks.py

hooks.py 文件定义了你的应用的元数据以及它与 Frappe 或 Frappe 应用
其他部分的集成点。这些部分的示例包括任务调度或监听系统中不同文档的更新。
目前,它只包含你在创建应用时输入的详细信息。

 app_name = "sample-app"
 app_title = "Sample App"
 app_publisher = "Acme Inc."
 app_description = "This is a sample app."
 app_icon = "fa-linux"
 app_color = "black"
 app_email = "[email protected]"
 app_url = "http://example.com"
 app_version = 0.0.1

modules.txt

Frappe 中的模块帮助你组织 Frappe 中的文档,它们定义在
你的应用的 modules.txt 文件中。每个 [DocType] 都必须
归属于一个模块。默认情况下,会添加一个以你的应用名称命名的模块。
此外,每个模块在 [工作台] 上都会有一个图标。例如,[ERPNext] 应用
按以下模块进行组织。

accounts(账户)
buying(采购)
home(首页)
hr(人力资源)
manufacturing(制造)
projects(项目)
selling(销售)
setup(设置)
stock(库存)
support(支持)
utilities(工具)
contacts(联系人)

将应用添加到站点

一旦你有了一个应用,无论是你刚刚创建的还是你下载的其他应用,
你都需要执行以下操作。

通过 git 下载应用

bench get-app https://github.com/org/app_name

将应用安装到你的站点

bench --site site_name install-app app_name

指南

Frappe 是一个全栈式“开箱即用”的框架。它提供了从身份验证、定时任务到管理不同货币、报表以及构建表单等所有功能的库和 API。

在本节中,我们将尝试涵盖客户端和服务器端最常用的 API,这些 API 对应用开发非常有用。

  1. 基础知识
  2. 应用开发
  3. 部署
  4. 报表与打印
  5. 门户开发
  6. 数据
  7. 集成
  8. 数据库设置
  9. 自动化测试
  10. 工作台

脚本编写

Frappe 框架允许您直接在框架内对标准模型和视图进行脚本编写,无需额外代码。

脚本编写的不同方式:

  1. 客户端脚本
  2. 服务器端脚本
  3. 脚本报表
  4. 系统控制台

附件

Frappe 允许将文件附加到文档中。对特定文档拥有读取权限的用户也可以访问附加到该文档的文件。用户还可以从侧边栏访问文件管理器。

如何附加新文件

有几种方法可以将文件附加到文档中。

选择文件

拖放

已上传的文件

将之前上传的文件附加到另一个文档中。

如果您使用独立的文件服务器或使用 Dropbox、Docs 等在线服务,您可以通过提供文件链接来附加文件。

相机

使用设备相机拍照来附加图片。

文件管理器

所有附加的文件都会列在文件管理器中。您可以通过以下路径访问它们:

首页 > 工具 > 文件

导入 Zip 压缩包

您还可以使用“导入 Zip”功能一次批量导入多个文件。

  1. 转到 文件列表 > 菜单 > 导入 Zip。
  2. 上传一个 zip 压缩包文件。
  3. zip 文件上传后,其内容将被解压,每个文件将作为一条新的文件记录创建。

注意:从 zip 文件导入时,不会解压隐藏文件(以 . 开头的文件)。

导出为 Zip 压缩包

您还可以使用“导出为 Zip”功能一次批量导出多个文件。

  1. 转到 文件列表。
  2. 选择多个文件。
  3. 点击“操作 > 导出为 zip”。
  4. zip 文件下载后,您可以使用“导入 Zip”功能将其导入到另一个站点,或通过电子邮件发送。

裁剪图片

您可以通过点击裁剪图标来裁剪 .jpeg 和 .png 图片。

优化图片

可以优化图片以减小其文件大小。目前,优化图片会执行以下操作:

  1. 将其大小调整为最大宽度 1920 像素、最大高度 1080 像素,同时保持宽高比
  2. 使用最佳编码器设置
  3. 将质量降低至 85%

上传时切换优化

优化已上传的图片

限制

默认情况下,每个附件的文件大小限制为 10MB。对于自托管用户,可以通过在站点配置文件中设置 max_file_size 来更改此限制。

每个文档的附件数

您可以限制特定文档可以附加的文件数量。

步骤 1:导航至“自定义表单”

首页 > 自定义 > 自定义表单

步骤 2:选择文档类型

选择您要为其设置此限制的文档类型。

步骤 3:设置限制

将最大附件数的值设置为允许此文档类型附加的最大附件数量。

对更改满意后,点击更新按钮。就这样!现在,每次向此类型的文档添加新附件时,都会验证每个文档的最大附件数。

打印

Frappe 框架对为文档生成打印格式并将其转换为 PDF 提供了一流的支持。Frappe 使用 Jinja 作为打印格式的模板语言。

可以从任何文档的表单视图中访问打印视图。系统会根据表单布局和其中的必填字段,为所有 DocType 生成标准打印格式。 打印视图

要自定义打印格式,您需要创建标准打印格式的副本,并使用打印格式构建器对其进行自定义。这些打印格式可由用户编辑,并且不会作为文件与应用捆绑在一起。

打印格式构建器

自定义 HTML

您还可以向打印格式中添加自定义 HTML。只需将左侧边栏中的“自定义 HTML”按钮拖放到您的打印格式编辑器中即可。

在“自定义 HTML”字段中,您可以使用任何有效的 HTML,并使用 Bootstrap 3 类进行样式设置。您还可以使用 Jinja 模板为 HTML 添加动态内容。请参阅可在 Jinja 模板中使用的方法列表。

自定义 HTML

自定义 CSS

要更改打印格式的样式,您还可以添加自定义 CSS。

点击“自定义”> “编辑属性”以添加自定义 CSS

自定义 CSS

自定义 CSS 预览

高级打印格式

如果您想完全更改打印格式的布局,打印格式构建器的功能就会受到限制。您还可以从头开始编写自己的 HTML,并构建您想要的打印布局。

要创建新的打印格式,请在 AwesomeBar 中输入“new print format”并按回车键。

  1. 为您的格式选择一个唯一的名称。
  2. 将“标准”设置为“否”。
  3. 勾选“自定义格式”。
  4. 将打印格式类型选择为“Jinja”。
  5. 编写您的自定义 HTML。

如果您将“标准”设置为“是”并且启用了开发者模式,那么系统将为您的打印格式生成一个 JSON 文件,并且您必须将其与您的应用一起检入到版本控制中。

打印格式中的自定义 HTML

Frappe 允许您为查询和脚本报表创建自定义打印格式。这些打印格式无法通过用户界面创建。

要为报表创建打印格式,请在报表文件夹中创建一个名为 {report-name}.html 的 HTML 文件。

例如,请查看总账。

JS 模板

这些打印格式是在客户端生成的,因此我们不能使用 Jinja。我们使用 John Resig 模板的改编版本。它看起来与 Jinja 类似,因此您无需学习任何新内容。

以下是 JS 模板的片段。

{% for(var i=0, l=data.length; i<l i>
    {% if(data[i].posting_date) { %}
        {%= frappe.datetime.str_to_user(data[i].posting_date) %}

            {% if(!(filters.party || filters.account)) { %}
                {%= data[i].party || data[i].account %}
                <br>
            {% } %}

            {{ __("Against") }}: {%= data[i].against %}
            <br>{%= __("Remarks") %}: {%= data[i].remarks %}

    {% } else { %}
        <b>{%= frappe.format(data[i].account, {fieldtype: "Link"}) || " " %}</b>

 {%= data[i].account && format_currency(data[i].debit, filters.presentation_currency) %}

 {% } %}

{% } %}
</l>

简介

什么是 Frappe 框架?

Frappe,发音为 fra-pay,是一个全栈式、功能完备的 Web 框架,使用 Python 和 Javascript 编写,并以 MariaDB 作为数据库。它是驱动 ERPNext 的底层框架,具有很好的通用性,可用于构建数据库驱动的应用程序。

为什么选择 Frappe?

Frappe 与其他框架的关键区别在于,元数据也被视为数据。这使得您可以非常轻松地构建前端。我们信奉单体架构,因此 Frappe 几乎包含了构建现代 Web 应用所需的一切。它拥有一个功能齐全的管理界面,称为 Desk,开箱即用地处理表单、导航、列表、菜单、权限、文件附件等众多功能。更多信息请点击此处阅读。

主要特性

  1. 全栈框架:Frappe 同时涵盖前端和后端开发,使开发人员能够使用单一框架构建完整的应用程序。
  2. 内置管理界面:提供预构建、可自定义的管理仪表板,用于管理应用程序数据,减少开发时间和工作量。
  3. 基于角色的权限:全面的用户和角色管理系统,用于控制应用程序内的访问和权限。
  4. REST API:为所有模型自动生成 RESTful API,便于与其他系统和服务的集成。
  5. 可自定义的表单和视图:通过服务器端脚本和客户端 JavaScript 实现灵活的表单和视图定制。
  6. 报表生成器:强大的报表工具,允许用户无需编写任何代码即可创建自定义报表。

安装

在使用 Frappe 之前,您需要先安装它。我们有一份完整的安装指南,涵盖了所有可能的情况,本指南还将帮助您了解后端技术栈。

学习与社区

  1. Frappe School – 通过维护者或社区提供的各种课程学习 Frappe 框架和 ERPNext。
  2. GitHub – 探索源代码、贡献代码,并与 Frappe 社区协作。
  3. 讨论论坛 – 在我们的论坛上与不断壮大的社区互动,提问、帮助他人并成为社区的一员。
  4. buildwithhussain.dev – 观看 Frappe 框架在实际项目中如何被用于构建世界级的 Web 应用。