`frappe._()` does not work inside a Builder Page Data Script, even though the function is included in the sandbox globals.
- Dominant language
- Python
- Stars
- 2.4k
- Forks
- 534
- Avg merge
- 1d 2h
- Merged PRs (30d)
- 45
Description
## Description
`frappe._()` does not work inside a Builder Page Data Script, even though the function is included in the sandbox globals.
## Steps to reproduce
1. Create a Builder Page
2. Add a **Page Data Script** containing: `data.update({"text": frappe._("Supplier")})`
3. Bind a text block's Data Key to `text`
4. Preview the page
## Expected behavior
The translated string appears (e.g. `"Lieferant"` for German).
## Actual behavior
`'str object' has no attribute 'get'` — or an empty string is rendered.
## Root cause
**File:** `builder/builder/utils.py` — function `get_safer_globals()`
The `_` function is only available inside the `frappe` namespace (line 241):
```python
frappe=NamespaceDict(
...
_=frappe._, # line 241 — only here
...
)
```
When the sandbox script calls `frappe._("text")`, RestrictedPython compiles the attribute access `frappe._` into `_getattr_(frappe, "_")`. The `_getattr_` guard (from `frappe.utils.safe_exec._validate_attribute_read`) blocks **all** attribute names starting with `_`:
```python
# frappe/utils/safe_exec.py line 571:
if name.startswith("_"):
raise AttributeError(f'"{name}" is an invalid attribute name because it starts with "_"')
```
This means `frappe._()` can never succeed — the guard kills it before the function is ever reached.
## Fix
Add `_=frappe._` to the **top-level** of the `out` NamespaceDict, matching how Frappe's own `get_safe_globals()` works:
## Environment
- Frappe/ERPNext version: v16
- Builder version: 1.24.7
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.