Watch
1
0
Fork
You've already forked Seyyed_arc
0
forked from hesabix/arc
Seyyed_arc/docs/WORKFLOW_I18N_SYSTEM.md
2026-04-14 19:34:55 +03:30

800 lines
24 KiB
Markdown
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🌍 سیستم ترجمه (i18n) برای نودهای ورک‌فلو
## 📋 خلاصه اجرایی
این مستند یک سیستم جامع برای چند زبانه کردن نودهای ورک‌فلو ارائه می‌دهد. این سیستم امکان ترجمه تمام رشته‌های استفاده شده در:
- نام و توضیحات نودها
- نام فیلدها و توضیحات آن‌ها
- گزینه‌های enum
- پیام‌های کمکی (help texts)
- پیام‌های خطا (validation errors)
را فراهم می‌کند.
---
## 🏗️ معماری سیستم
### کامپوننت‌ها:
```
┌─────────────────────────────────────────────────────────────┐
│ Backend (Python) │
├─────────────────────────────────────────────────────────────┤
│ │
│ workflow_translations.py │
│ ├─ COMMON_TRANSLATIONS │
│ ├─ CREATE_INVOICE_TRANSLATIONS │
│ ├─ SEND_TELEGRAM_TRANSLATIONS │
│ ├─ SEND_EMAIL_TRANSLATIONS │
│ └─ OTHER_ACTIONS_TRANSLATIONS │
│ │
│ API Endpoints: │
│ ├─ GET /workflows/metadata/actions?lang=fa │
│ ├─ GET /workflows/metadata/triggers?lang=fa │
│ ├─ GET /workflows/translations?lang=fa │
│ └─ GET /workflows/translations/export?lang=fa │
│ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Frontend (Flutter) │
├─────────────────────────────────────────────────────────────┤
│ │
│ WorkflowTranslationService │
│ ├─ getTranslations(lang) │
│ ├─ getActionsMetadata(lang) │
│ ├─ getTriggersMetadata(lang) │
│ └─ getFieldTranslation(action, field, type) │
│ │
│ WorkflowLocalizations Extension │
│ ├─ workflowCreateInvoiceActionName │
│ ├─ workflowSendTelegramFieldMessage │
│ └─ ... (تمام ترجمه‌ها) │
│ │
│ UI Components: │
│ └─ WorkflowNodeConfigDialog │
│ ├─ استفاده از ترجمه‌ها در labels │
│ ├─ استفاده از ترجمه‌ها در descriptions │
│ ├─ استفاده از ترجمه‌ها در placeholders │
│ └─ استفاده از ترجمه‌ها در enum labels │
│ │
└─────────────────────────────────────────────────────────────┘
```
---
## 🔧 نحوه کار
### 1. Backend (Python)
#### ساختار ترجمه‌ها:
```python
CREATE_INVOICE_TRANSLATIONS = {
"fa": {
"action_name": "ایجاد فاکتور",
"action_description": "ایجاد فاکتور فروش، خرید یا...",
"group_basic_info": "اطلاعات پایه",
"group_items": "آیتم‌های فاکتور",
"field_invoice_type": "نوع فاکتور",
"field_invoice_type_desc": "نوع فاکتور",
"invoice_sales": "🛒 فاکتور فروش",
"invoice_purchase": "🛍️ فاکتور خرید",
"error_min_items": "حداقل یک آیتم باید وارد شود",
},
"en": {
"action_name": "Create Invoice",
"action_description": "Create sales, purchase or...",
"group_basic_info": "Basic Information",
"group_items": "Invoice Items",
"field_invoice_type": "Invoice Type",
"field_invoice_type_desc": "Invoice Type",
"invoice_sales": "🛒 Sales Invoice",
"invoice_purchase": "🛍️ Purchase Invoice",
"error_min_items": "At least one item is required",
}
}
```
#### API Endpoints:
**1. دریافت ترجمه‌ها:**
```http
GET /api/v1/workflows/translations?lang=fa
Response:
{
"language": "fa",
"translations": {
"settings": "تنظیمات",
"create_invoice": {
"action_name": "ایجاد فاکتور",
"field_invoice_type": "نوع فاکتور"
}
}
}
```
**2. دریافت metadata با ترجمه:**
```http
GET /api/v1/workflows/metadata/actions?lang=en
Response:
{
"data": [
{
"key": "create_invoice",
"name": "Create Invoice", // ترجمه شده
"description": "Create sales invoice...", // ترجمه شده
"config_schema": {
"invoice_type": {
"description": "Invoice Type", // ترجمه شده
"enum": ["invoice_sales", "invoice_purchase"],
"ui_config": {
"labels": {
"invoice_sales": "Sales Invoice", // ترجمه شده
"invoice_purchase": "Purchase Invoice" // ترجمه شده
}
}
}
}
}
]
}
```
**3. صادرات به فرمت arb:**
```http
GET /api/v1/workflows/translations/export?lang=fa
Response:
{
"format": "arb",
"translations": {
"workflowSettings": "تنظیمات",
"workflowCreateInvoiceActionName": "ایجاد فاکتور",
"workflowCreateInvoiceFieldInvoiceType": "نوع فاکتور"
}
}
```
---
### 2. Frontend (Flutter)
#### استفاده در UI:
```dart
import '../../services/workflow_translation_service.dart';
import '../../extensions/workflow_localizations_extension.dart';
class _WorkflowNodeConfigDialogState extends State<WorkflowNodeConfigDialog> {
final WorkflowTranslationService _translationService = WorkflowTranslationService();
Map<String, dynamic>? _translations;
@override
void initState() {
super.initState();
_loadTranslations();
}
Future<void> _loadTranslations() async {
final locale = Localizations.localeOf(context);
final translations = await _translationService.getTranslations(lang: locale.languageCode);
setState(() {
_translations = translations;
});
}
Widget build(BuildContext context) {
// استفاده از extension
final t = AppLocalizations.of(context);
final label = t.workflowCreateInvoiceFieldInvoiceType;
// یا استفاده از service
final description = _translationService.getFieldTranslation(
'create_invoice',
'invoice_type',
type: 'desc',
);
return TextFormField(
decoration: InputDecoration(
labelText: label,
helperText: description,
),
);
}
}
```
---
## 📝 نحوه افزودن ترجمه برای نود جدید
### مرحله 1: افزودن ترجمه‌ها در Python
**فایل:** `app/services/workflow/i18n/workflow_translations.py`
```python
# ترجمه‌های نود جدید
MY_NEW_ACTION_TRANSLATIONS = {
"fa": {
"action_name": "نام فارسی اکشن",
"action_description": "توضیحات فارسی اکشن",
"field_my_field": "نام فیلد",
"field_my_field_desc": "توضیحات فیلد",
"field_my_field_placeholder": "متن placeholder",
"field_my_field_help": "متن کمکی",
"my_enum_value": "لیبل فارسی",
"error_my_error": "پیام خطا",
},
"en": {
"action_name": "English Action Name",
"action_description": "English action description",
"field_my_field": "Field Name",
"field_my_field_desc": "Field description",
"field_my_field_placeholder": "Placeholder text",
"field_my_field_help": "Help text",
"my_enum_value": "English Label",
"error_my_error": "Error message",
}
}
```
### مرحله 2: اضافه کردن به exports
```python
# در همان فایل
__all__ = [
...,
"MY_NEW_ACTION_TRANSLATIONS",
]
# در تابع get_translation
translations_map = {
...,
"my_new_action": MY_NEW_ACTION_TRANSLATIONS,
}
```
### مرحله 3: استخراج و صادرات
```bash
cd /var/www/ark/hesabixAPI
source venv/bin/activate
python scripts/extract_workflow_translations.py
```
### مرحله 4: بازسازی Flutter
```bash
cd /var/www/ark/hesabixUI/hesabix_ui
flutter pub run build_runner build --delete-conflicting-outputs
```
---
## 🎨 الگوهای نام‌گذاری
### Backend (Python):
| نوع | الگو | مثال |
|-----|------|------|
| نام action | `action_name` | `"ایجاد فاکتور"` |
| توضیحات action | `action_description` | `"ایجاد فاکتور..."` |
| نام گروه | `group_{group_key}` | `group_basic_info` |
| نام فیلد | `field_{field_key}` | `field_invoice_type` |
| توضیحات فیلد | `field_{field_key}_desc` | `field_invoice_type_desc` |
| Placeholder فیلد | `field_{field_key}_placeholder` | `field_message_placeholder` |
| راهنمای فیلد | `field_{field_key}_help` | `field_items_help` |
| Enum value | `{enum_value}` | `invoice_sales` |
| پیام خطا | `error_{error_key}` | `error_min_items` |
### Frontend (Dart):
| نوع | الگو | مثال |
|-----|------|------|
| نام action | `workflow{Action}ActionName` | `workflowCreateInvoiceActionName` |
| توضیحات action | `workflow{Action}ActionDescription` | `workflowCreateInvoiceActionDescription` |
| نام فیلد | `workflow{Action}Field{Field}` | `workflowCreateInvoiceFieldInvoiceType` |
| Enum value | `workflow{Action}{EnumValue}` | `workflowCreateInvoiceInvoiceSales` |
---
## 📊 ساختار فایل‌ها
### Backend:
```
hesabixAPI/
├── app/
│ └── services/
│ └── workflow/
│ ├── i18n/
│ │ ├── __init__.py
│ │ └── workflow_translations.py ← ترجمه‌ها
│ └── actions/
│ ├── communication_actions.py ← استفاده از ترجمه
│ ├── document_actions.py ← استفاده از ترجمه
│ └── utility_actions.py ← استفاده از ترجمه
├── adapters/
│ └── api/
│ └── v1/
│ └── workflows.py ← API endpoints برای ترجمه
└── scripts/
└── extract_workflow_translations.py ← اسکریپت استخراج
```
### Frontend:
```
hesabixUI/hesabix_ui/
├── lib/
│ ├── services/
│ │ └── workflow_translation_service.dart ← سرویس ترجمه
│ ├── extensions/
│ │ └── workflow_localizations_extension.dart ← Extension
│ ├── widgets/
│ │ └── workflow/
│ │ └── workflow_node_config_dialog.dart ← استفاده از ترجمه
│ └── l10n/
│ ├── workflow_fa.arb ← ترجمه‌های فارسی (auto-generated)
│ └── workflow_en.arb ← ترجمه‌های انگلیسی (auto-generated)
```
---
## 🚀 نحوه استفاده
### 1. در Backend:
#### افزودن ترجمه به metadata:
```python
from app.services.workflow.i18n import translate_metadata
class MyAction(ActionHandler):
def get_metadata(self) -> Dict[str, Any]:
return {
"name": "نام پیش‌فرض", # این جایگزین می‌شود
"description": "توضیحات پیش‌فرض", # این جایگزین می‌شود
"config_schema": {
"my_field": {
"type": "string",
"description": "توضیحات فیلد", # این جایگزین می‌شود
"enum": ["value1", "value2"],
"ui_config": {
# labels جایگزین می‌شوند
}
}
}
}
```
#### استفاده در API endpoint:
```python
@router.get("/workflows/metadata/actions")
async def get_actions_metadata(lang: str = "fa"):
action_registry = ActionRegistry()
all_actions = action_registry.get_all_metadata()
translated_actions = []
for action in all_actions:
translated = translate_metadata(action, lang, action.get("key"))
translated_actions.append(translated)
return success_response(data=translated_actions)
```
### 2. در Frontend:
#### استفاده از Extension:
```dart
import '../../extensions/workflow_localizations_extension.dart';
@override
Widget build(BuildContext context) {
final t = AppLocalizations.of(context);
return Column(
children: [
Text(t.workflowCreateInvoiceActionName),
Text(t.workflowCreateInvoiceFieldInvoiceType),
Text(t.workflowSendTelegramFieldMessage),
],
);
}
```
#### استفاده از Service:
```dart
final translationService = WorkflowTranslationService();
// بارگذاری ترجمه‌ها
final translations = await translationService.getTranslations(lang: 'fa');
// دریافت metadata با ترجمه
final actionsMetadata = await translationService.getActionsMetadata(lang: 'fa');
// دریافت ترجمه یک فیلد خاص
final fieldLabel = translationService.getFieldTranslation(
'create_invoice',
'invoice_type',
type: 'name',
);
```
#### در Dialog تنظیمات نود:
```dart
class _WorkflowNodeConfigDialogState extends State<WorkflowNodeConfigDialog> {
Map<String, dynamic>? _translations;
@override
void initState() {
super.initState();
_loadTranslations();
}
Future<void> _loadTranslations() async {
final locale = Localizations.localeOf(context);
final translations = await _translationService.getTranslations(
lang: locale.languageCode
);
setState(() {
_translations = translations;
});
}
String _formatKey(String key) {
// استفاده از ترجمه (اگر موجود باشد)
if (_translations != null && widget.node.key != null) {
final actionKey = widget.node.key;
final fieldKey = 'field_$key';
if (_translations![actionKey]?[fieldKey] != null) {
return _translations![actionKey][fieldKey];
}
}
// Fallback
return _formatFieldName(key);
}
}
```
---
## 📚 مثال کامل: نود "ایجاد فاکتور"
### Backend:
```python
# در workflow_translations.py
CREATE_INVOICE_TRANSLATIONS = {
"fa": {
"action_name": "ایجاد فاکتور",
"field_invoice_type": "نوع فاکتور",
"invoice_sales": "🛒 فاکتور فروش",
"invoice_purchase": "🛍️ فاکتور خرید",
},
"en": {
"action_name": "Create Invoice",
"field_invoice_type": "Invoice Type",
"invoice_sales": "🛒 Sales Invoice",
"invoice_purchase": "🛍️ Purchase Invoice",
}
}
# در document_actions.py
class CreateInvoiceAction(ActionHandler):
def get_metadata(self) -> Dict[str, Any]:
return {
"name": "ایجاد فاکتور", # جایگزین می‌شود با ترجمه
"config_schema": {
"invoice_type": {
"enum": ["invoice_sales", "invoice_purchase"],
"ui_config": {
"labels": {
# این labels از ترجمه می‌آید
"invoice_sales": "فاکتور فروش",
"invoice_purchase": "فاکتور خرید"
}
}
}
}
}
```
### Frontend:
```dart
// استفاده از extension
final t = AppLocalizations.of(context);
DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText: t.workflowCreateInvoiceFieldInvoiceType,
),
items: [
DropdownMenuItem(
value: 'invoice_sales',
child: Text(t.workflowCreateInvoiceInvoiceSales),
),
DropdownMenuItem(
value: 'invoice_purchase',
child: Text(t.workflowCreateInvoiceInvoicePurchase),
),
],
)
```
---
## 🔄 فرآیند توسعه
### هنگام افزودن نود جدید:
```
1. ایجاد Action Handler
↓
2. افزودن ترجمه‌ها در workflow_translations.py
↓
3. اجرای extract_workflow_translations.py
↓
4. ری‌استارت API
↓
5. بازسازی Flutter (build_runner)
↓
6. استفاده در UI
```
### هنگام تغییر ترجمه:
```
1. ویرایش workflow_translations.py
↓
2. اجرای extract_workflow_translations.py
↓
3. بازسازی Flutter (اگر لازم باشد)
↓
4. ری‌استارت API
```
---
## 🧪 تست
### تست ترجمه‌ها در Backend:
```python
from app.services.workflow.i18n import get_translation, translate_metadata
# تست دریافت ترجمه
assert get_translation("action_name", "fa", "create_invoice") == "ایجاد فاکتور"
assert get_translation("action_name", "en", "create_invoice") == "Create Invoice"
# تست ترجمه metadata
metadata = {
"name": "default name",
"config_schema": {...}
}
translated_fa = translate_metadata(metadata, "fa", "create_invoice")
assert translated_fa["name"] == "ایجاد فاکتور"
translated_en = translate_metadata(metadata, "en", "create_invoice")
assert translated_en["name"] == "Create Invoice"
```
### تست در Frontend:
```dart
// تست extension
test('WorkflowLocalizations extension', () {
final t = AppLocalizations.delegate.load(Locale('fa'));
expect(t.workflowCreateInvoiceActionName, equals('ایجاد فاکتور'));
});
// تست service
test('WorkflowTranslationService', () async {
final service = WorkflowTranslationService();
final translations = await service.getTranslations(lang: 'fa');
expect(translations['create_invoice']['action_name'], equals('ایجاد فاکتور'));
});
```
---
## 📋 لیست کامل کلیدهای ترجمه
### نودهای فعلی:
#### 1. Create Invoice (17 فیلد + 20 ترجمه)
- ✅ action_name, action_description
- ✅ 6 group (basic_info, items, financial, payment, warehouse, advanced)
- ✅ 17 field (invoice_type, person_id, document_date, ...)
- ✅ 4 enum label (invoice_sales, invoice_purchase, ...)
- ✅ 4 help_text
- ✅ 3 error_message
**جمع کل: ~54 کلید ترجمه**
#### 2. Send Telegram (7 فیلد + 10 ترجمه)
- ✅ action_name, action_description
- ✅ 7 field (user_id, message, parse_mode, ...)
- ✅ 3 enum label (HTML, Markdown, None)
- ✅ 2 help_text
**جمع کل: ~22 کلید ترجمه**
#### 3. Send Email (8 فیلد + 10 ترجمه)
- ✅ action_name, action_description
- ✅ 8 field (to, cc, bcc, subject, body, ...)
- ✅ 2 help_text
**جمع کل: ~20 کلید ترجمه**
#### 4. سایر نودها (6 نود)
- Create Notification
- Set Variable
- Log
- HTTP Request
- Create Document
- Update Inventory
**جمع کل هر نود: ~10-15 کلید**
---
## 📊 آمار کلی
| زبان | تعداد کلیدهای مشترک | تعداد کلیدها per نود | جمع کل (تخمینی) |
|------|---------------------|---------------------|------------------|
| فارسی | 15 | ~20-50 | 200+ |
| انگلیسی | 15 | ~20-50 | 200+ |
---
## 💡 بهترین شیوه‌ها (Best Practices)
### 1. نام‌گذاری:
- ✅ از snake_case استفاده کنید
- ✅ نام‌های توصیفی و واضح
- ✅ پیشوند مناسب (`field_`, `group_`, `error_`)
### 2. سازماندهی:
- ✅ هر action یک dictionary جداگانه
- ✅ گروه‌بندی منطقی (basic, advanced, ...)
- ✅ ترتیب منطقی کلیدها
### 3. محتوا:
- ✅ متن‌های کوتاه و واضح
- ✅ از آیکون‌های Emoji در جای مناسب
- ✅ راهنماها و مثال‌ها
### 4. مدیریت:
- ✅ همیشه هر دو زبان را به‌روز نگه دارید
- ✅ از اسکریپت extract برای صادرات استفاده کنید
- ✅ Cache کردن در frontend
### 5. Testing:
- ✅ تست ترجمه‌ها در هر دو زبان
- ✅ بررسی کلیدهای گمشده
- ✅ مقایسه با UI واقعی
---
## 🔍 Debugging
### مشکل: ترجمه نمایش داده نمی‌شود
**چک‌لیست:**
1. ✅ آیا ترجمه در `workflow_translations.py` وجود دارد؟
2. ✅ آیا API ری‌استارت شده؟
3. ✅ آیا cache در frontend پاک شده؟
4. ✅ آیا زبان صحیح انتخاب شده؟
5. ✅ آیا کلید ترجمه صحیح است؟
### مشکل: ترجمه انگلیسی نمایش داده نمی‌شود
```dart
// بررسی locale
final locale = Localizations.localeOf(context);
print('Current locale: ${locale.languageCode}');
// بررسی ترجمه‌های دریافت شده
final translations = await _translationService.getTranslations(lang: 'en');
print('Translations: $translations');
```
### مشکل: کلید ترجمه یافت نمی‌شود
```python
# در Python
from app.services.workflow.i18n import get_all_translation_keys
keys = get_all_translation_keys("create_invoice")
print("Available keys (fa):", keys["fa"])
print("Available keys (en):", keys["en"])
```
---
## 🎯 مزایای این سیستم
### 1. مدیریت متمرکز:
- ✅ تمام ترجمه‌ها در یک مکان
- ✅ راحتی به‌روزرسانی
- ✅ کاهش تکرار
### 2. Type-Safe:
- ✅ Extension با type-safety کامل
- ✅ Autocomplete در IDE
- ✅ Compile-time checking
### 3. Performance:
- ✅ Cache در سمت client
- ✅ دریافت یک‌باره ترجمه‌ها
- ✅ Lazy loading
### 4. Scalability:
- ✅ افزودن زبان جدید آسان است
- ✅ افزودن نود جدید ساده است
- ✅ صادرات به فرمت‌های مختلف
### 5. Developer Experience:
- ✅ API ساده و واضح
- ✅ مستندات کامل
- ✅ اسکریپت‌های کمکی
- ✅ Fallback برای ترجمه‌های گمشده
---
## 📦 فایل‌های ایجاد شده
| فایل | نوع | توضیحات |
|------|-----|---------|
| `workflow_translations.py` | Backend | ترجمه‌های پایه |
| `workflows.py` (updated) | Backend | API endpoints |
| `extract_workflow_translations.py` | Script | استخراج و صادرات |
| `workflow_translation_service.dart` | Frontend | سرویس دریافت ترجمه |
| `workflow_localizations_extension.dart` | Frontend | Extension برای راحتی |
| `workflow_node_config_dialog.dart` (updated) | Frontend | استفاده از ترجمه در UI |
---
## ✅ نتیجه‌گیری
سیستم i18n کامل و حرفه‌ای برای نودهای ورک‌فلو پیاده‌سازی شد که:
✅ **200+ رشته** را پشتیبانی می‌کند
✅ **2 زبان** (فارسی و انگلیسی)
✅ **قابل توسعه** برای زبان‌های بیشتر
✅ **مدیریت آسان** با اسکریپت‌های کمکی
✅ **Type-Safe** در Flutter
✅ **Cache** برای performance بهتر
✅ **Fallback** برای ترجمه‌های گمشده
این سیستم امکان ایجاد یک تجربه کاربری یکپارچه و چند زبانه را فراهم می‌کند! 🌍🎉