mirror of
https://github.com/langflow-ai/langflow.git
synced 2026-07-24 22:14:11 +08:00
chore: remove temporary dev files from gp scripts directory
Remove BACKEND_STRINGS_STRATEGY.md (internal planning doc), test_auth.py (GP auth debugging script), and en.json (dev-time string snapshot). Also add venv/ to .gitignore to prevent accidental commits of the local virtualenv.
This commit is contained in:
1
scripts/gp/.gitignore
vendored
1
scripts/gp/.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
.env
|
||||
__pycache__/
|
||||
*.pyc
|
||||
venv/
|
||||
|
||||
@ -1,123 +0,0 @@
|
||||
# Backend Component Strings — i18n Strategy
|
||||
|
||||
## The Problem
|
||||
|
||||
Component names, descriptions, and category labels shown in the Langflow UI (sidebar, node headers, tooltips) come from **Python backend metadata**, not the frontend. Examples:
|
||||
|
||||
- `display_name = "Chat Input"` — shown in sidebar list and node title
|
||||
- `description = "Get chat inputs from the Playground."` — shown in tooltips
|
||||
- `category = "input_output"` — maps to a category group
|
||||
|
||||
Because these strings originate in Python and are served via the REST API, the frontend's `t()` approach cannot translate them — by the time React renders them, they're just API response strings.
|
||||
|
||||
---
|
||||
|
||||
## Where These Strings Live (Backend)
|
||||
|
||||
Each component is a Python class in `src/backend/base/langflow/components/`:
|
||||
|
||||
```python
|
||||
class ChatInput(Component):
|
||||
display_name = "Chat Input"
|
||||
description = "Get chat inputs from the Playground."
|
||||
icon = "MessageSquare"
|
||||
name = "ChatInput"
|
||||
```
|
||||
|
||||
The API endpoint `/api/v1/all` returns all component metadata, including `display_name` and `description`, to the frontend.
|
||||
|
||||
---
|
||||
|
||||
## Options
|
||||
|
||||
### Option A: Frontend key-based lookup (Recommended for Phase 1)
|
||||
|
||||
**How it works:**
|
||||
- Backend sends a stable machine key alongside display_name: e.g. `"i18n_key": "component.chatInput.displayName"`
|
||||
- Frontend uses `t(component.i18n_key, { defaultValue: component.display_name })`
|
||||
- If the key exists in the locale file → translated string shown
|
||||
- If not → falls back to the raw `display_name` from the API (graceful degradation)
|
||||
|
||||
**Backend change needed:**
|
||||
- Add `i18n_key` property to the Component base class, auto-derived from class name:
|
||||
```python
|
||||
@property
|
||||
def i18n_key(self) -> str:
|
||||
return f"component.{self.__class__.__name__}.displayName"
|
||||
```
|
||||
- Include it in the `/api/v1/all` response schema
|
||||
|
||||
**Frontend change needed:**
|
||||
- In `sidebarDraggableComponent.tsx` and `NodeName/index.tsx`, replace:
|
||||
```tsx
|
||||
{display_name}
|
||||
```
|
||||
with:
|
||||
```tsx
|
||||
{t(i18n_key, { defaultValue: display_name })}
|
||||
```
|
||||
|
||||
**New keys in en.json (example):**
|
||||
```json
|
||||
"component.ChatInput.displayName": "Chat Input",
|
||||
"component.ChatOutput.displayName": "Chat Output",
|
||||
"component.TextInput.displayName": "Text Input",
|
||||
"component.OpenAIModel.displayName": "OpenAI",
|
||||
...
|
||||
```
|
||||
|
||||
**Pros:** Graceful fallback, no big-bang migration, GP translates these like any other key.
|
||||
**Cons:** ~200+ keys to add; backend must expose i18n_key in API response.
|
||||
|
||||
---
|
||||
|
||||
### Option B: Accept-Language header on the API
|
||||
|
||||
**How it works:**
|
||||
- Frontend sends `Accept-Language: fr` header with every API request
|
||||
- Backend detects language and returns translated `display_name` / `description` directly
|
||||
- Frontend renders as-is, no key lookup needed
|
||||
|
||||
**Backend change needed:**
|
||||
- Add Python i18n library (e.g. `babel`, `python-i18n`) or call GP API server-side
|
||||
- Maintain translation files for Python strings separately from frontend locale files
|
||||
- Middleware to read `Accept-Language` and translate all component metadata before returning
|
||||
|
||||
**Pros:** Frontend doesn't change at all; translations fully server-side.
|
||||
**Cons:** Complex backend changes; two separate translation pipelines (frontend GP + backend); harder to keep in sync.
|
||||
|
||||
---
|
||||
|
||||
### Option C: Skip component names (pragmatic)
|
||||
|
||||
Component names like "Chat Input", "OpenAI", "FAISS" are semi-technical product names. Many localization projects treat these as untranslatable proper nouns. Translators would leave "Chat Input" as-is in French — it's an established product term.
|
||||
|
||||
**When to use:** If translators confirm these don't need localization, skip entirely.
|
||||
|
||||
---
|
||||
|
||||
## Recommendation
|
||||
|
||||
**Phase 1 (near-term):** Go with **Option A** — add `i18n_key` to the API response, update the 5 frontend render sites to use `t(i18n_key, { defaultValue: display_name })`, add ~200 keys to en.json, upload to GP.
|
||||
|
||||
**Phase 2 (later):** Evaluate whether `description` fields also need translation (they're longer, more expensive to translate).
|
||||
|
||||
---
|
||||
|
||||
## Frontend Files to Update (for Option A)
|
||||
|
||||
| File | What changes |
|
||||
|------|-------------|
|
||||
| `src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/sidebarDraggableComponent.tsx` | `{display_name}` → `{t(i18n_key, { defaultValue: display_name })}` |
|
||||
| `src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/sidebarItemsList.tsx` | tooltip display_name |
|
||||
| `src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/McpSidebarGroup.tsx` | mcp display_name |
|
||||
| `src/frontend/src/CustomNodes/GenericNode/components/NodeName/index.tsx` | node title display_name |
|
||||
| `src/frontend/src/pages/FlowPage/components/InspectionPanel/components/EditableHeaderContent.tsx` | inspection panel display_name |
|
||||
|
||||
## Backend Files to Update
|
||||
|
||||
| File | What changes |
|
||||
|------|-------------|
|
||||
| `src/backend/base/langflow/custom/custom_component/component.py` | Add `i18n_key` property |
|
||||
| `src/backend/base/langflow/api/v1/endpoints.py` | Include `i18n_key` in `/api/v1/all` response |
|
||||
| All component Python files | Optionally override `i18n_key` if auto-derived name isn't clean |
|
||||
@ -1,12 +0,0 @@
|
||||
{
|
||||
"save_button": "Save",
|
||||
"cancel_button": "Cancel",
|
||||
"delete_button": "Delete",
|
||||
"edit_button": "Edit",
|
||||
"submit_button": "Submit",
|
||||
"loading": "Loading...",
|
||||
"error_message": "Something went wrong. Please try again.",
|
||||
"success_message": "Operation completed successfully.",
|
||||
"confirm_delete": "Are you sure you want to delete this?",
|
||||
"welcome": "Welcome to Langflow"
|
||||
}
|
||||
@ -1,73 +0,0 @@
|
||||
"""Test GP authentication and basic API connectivity."""
|
||||
|
||||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import requests
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
|
||||
def calulate_hmacheader(endpoint, request_type, body):
|
||||
"""Calculate HMAC header dynamically."""
|
||||
date = datetime.now(timezone.utc)
|
||||
date_string = date.strftime("%a, %d %b %Y %H:%M:%S %Z").replace("UTC", "GMT")
|
||||
|
||||
user_id = os.getenv("GP_ADMIN_USER_ID")
|
||||
password = os.getenv("GP_ADMIN_PASSWORD")
|
||||
|
||||
if request_type.upper() == "GET":
|
||||
body = ""
|
||||
msg = "GET" + "\n" + endpoint + "\n" + date_string + "\n" + body
|
||||
else:
|
||||
msg = request_type.upper() + "\n" + endpoint + "\n" + date_string + "\n" + json.dumps(body)
|
||||
|
||||
print(f"[DEBUG] userId : {user_id}")
|
||||
print(f"[DEBUG] dateString: {date_string}")
|
||||
print(f"[DEBUG] endpoint : {endpoint}")
|
||||
print(f"[DEBUG] msg : {msg!r}")
|
||||
|
||||
message = bytes(msg, "ISO-8859-1")
|
||||
password = bytes(password, "ISO-8859-1")
|
||||
|
||||
signature = hmac.new(password, msg=message, digestmod=hashlib.sha1).digest()
|
||||
hmac_header = "GP-HMAC " + user_id + ":" + base64.b64encode(signature).decode()
|
||||
|
||||
print(f"[DEBUG] signature : {base64.b64encode(signature).decode()}")
|
||||
print(f"[DEBUG] auth : {hmac_header}")
|
||||
|
||||
if request_type.upper() == "PATCH":
|
||||
header = {
|
||||
"Authorization": hmac_header,
|
||||
"GP-Date": date_string,
|
||||
"accept": "application/json",
|
||||
"Content-Type": "application/merge-patch+json",
|
||||
}
|
||||
else:
|
||||
header = {
|
||||
"Authorization": hmac_header,
|
||||
"GP-Date": date_string,
|
||||
"accept": "application/json",
|
||||
}
|
||||
return header
|
||||
|
||||
|
||||
# Test: List bundles
|
||||
GP_INSTANCE = os.getenv("GP_INSTANCE", "langflow-test")
|
||||
BASE_URL = "https://g11n-pipeline-api.straker.global/translate/rest"
|
||||
endpoint = f"{BASE_URL}/{GP_INSTANCE}/v2/bundles"
|
||||
|
||||
print(f"[DEBUG] full URL : {endpoint}")
|
||||
print()
|
||||
|
||||
headers = calulate_hmacheader(endpoint, "GET", "")
|
||||
print()
|
||||
|
||||
response = requests.get(endpoint, headers=headers, verify=False, timeout=30) # noqa: S501
|
||||
print(f"[DEBUG] status : {response.status_code}")
|
||||
print(f"[DEBUG] response : {response.json()}")
|
||||
Reference in New Issue
Block a user