How to Get Translated Field Names and Field Values in Frappe API Response?

Hi everyone,

I’m working on a multilingual Frappe/ERPNext setup and facing a challenge with API responses. When I make API calls (e.g., frappe.client.get_list or /api/resource/{doctype}), the field names (labels) and field values (like options in Select fields, Link field display names, etc.) are returned in English, regardless of the user’s language preference set in settings.

What I’m trying to achieve:

  • Get field labels (not just field keys) in the translated language in the API response.

  • Get translatable field values (e.g., Select options like “Draft”, “Cancelled”, or standard print formats) returned in the user’s preferred language.

Has anyone found a clean way to get fully translated API responses from Frappe? Is there a built-in parameter, or recommended approach to handle this — especially for mobile apps or frontend clients that consume the REST API?

Any guidance, workarounds would be greatly appreciated. Thanks!

@milan-greycube Frappe’s REST API does not natively return translated labels or values. It’s not a bug, it’s a design choice. The API returns raw data; translation is a frontend concern in Frappe’s worldview. So you’re not missing a magic parameter.

:white_check_mark: Option 1: Use frappe._() via a Custom Whitelisted API (Recommended)

Write a custom Python endpoint that translates on the server side before returning the response.

# your_app/api.py

import frappe

@frappe.whitelist()
def get_translated_list(doctype, lang=None):
    if lang:
        frappe.local.lang = lang  # Override lang for this request

    meta = frappe.get_meta(doctype)
    docs = frappe.get_list(doctype, fields=["*"])

    # Translate field labels
    translated_meta = {
        field.fieldname: frappe._(field.label)
        for field in meta.fields
    }

    # Translate select values in each doc
    select_fields = {
        field.fieldname: field.options
        for field in meta.fields
        if field.fieldtype == "Select" and field.options
    }

    for doc in docs:
        for fieldname in select_fields:
            if doc.get(fieldname):
                doc[fieldname] = frappe._(doc[fieldname])

    return {
        "labels": translated_meta,
        "data": docs
    }

Call it via:

GET /api/method/your_app.api.get_translated_list?doctype=Sales Order&lang=ar

:white_check_mark: Option 2: Pass Accept-Language Header + Force Lang in Hook

If you control the API client (mobile app etc.), you can set the lang via a before_request hook:

# hooks.py
before_request = ["your_app.utils.set_lang_from_header"]

# your_app/utils.py
import frappe

def set_lang_from_header():
    lang = frappe.get_request_header("Accept-Language")
    if lang:
        frappe.local.lang = lang.split(",")[0].strip()  # e.g., "ar", "hi"

This forces ALL API responses in that request to use that language context frappe._() calls inside Frappe itself will now translate. Select field values won’t auto-translate though you still need custom handling for those.