Files
minicrm/docs/I18N_GUIDE.md
phuongtc efa97b6c71
Some checks failed
Tests / PHP 8.3 (push) Has been cancelled
Tests / PHP 8.4 (push) Has been cancelled
Tests / PHP 8.5 (push) Has been cancelled
them log, chinh upload
2026-05-09 11:00:59 +00:00

163 lines
3.8 KiB
Markdown

# Hướng dẫn Đa ngôn ngữ (i18n)
## Tổng quan
Hệ thống hỗ trợ 2 ngôn ngữ:
- **Tiếng Việt (vi)** - Ngôn ngữ chính
- **Tiếng Anh (en)** - Ngôn ngữ dự phòng
Cấu hình trong `.env`:
```
APP_LOCALE=vi
APP_FALLBACK_LOCALE=en
```
## Cấu trúc thư mục
```
lang/
├── en/
│ ├── app.php # UI chung: navigation, labels, status, widgets
│ ├── feedback.php # Domain feedback: services, notifications, interactions
│ └── enums.php # Labels cho enums
└── vi/
├── app.php
├── feedback.php
└── enums.php
```
## Quy tắc đặt tên Translation Keys
### 1. Resource Labels
```php
// Pattern: app.resource_{name}
'resource_feedbacks' => 'Phản ánh',
'resource_products' => 'Sản phẩm',
'resource_customers' => 'Khách hàng',
```
### 2. Status Labels
```php
// Pattern: app.status_{name}
'status_pending' => 'Chờ xử lý',
'status_processing' => 'Đang xử lý',
'status_resolved' => 'Đã xử lý',
'status_closed' => 'Đã đóng',
```
### 3. Form Labels
```php
// Pattern: app.{field_name}
'name' => 'Tên',
'email' => 'Email',
'phone' => 'Điện thoại',
```
### 4. Enum Labels
```php
// Pattern: enums.{enum_name}.{case_value}
'service.management_fee' => 'Phí quản lý',
'contract_status.active' => 'Đang hiệu lực',
```
### 5. Feedback Domain
```php
// Pattern: feedback.{action}_{context}
'already_closed' => 'Phiếu này đã được đóng.',
'close_permission_denied' => 'Chỉ lãnh đạo cấp phòng mới có quyền đóng phiếu.',
```
## Cách sử dụng trong code
### Resource Labels
```php
// Phải override getPluralLabel() - KHÔNG tự dịch
public static function getPluralLabel(): ?string
{
return __('app.resource_feedbacks');
}
// Phải override getNavigationGroup() - KHÔNG tự dịch
public static function getNavigationGroup(): ?string
{
return __('app.nav_customer_care');
}
```
### Form Fields
```php
// PHẢI thêm ->label() explicit
TextInput::make('name')->label(__('app.name'))
Select::make('status')->label(__('app.status'))
```
### RelationManager Title
```php
// Phải override getTitle() - KHÔNG dùng $title property
public static function getTitle(Model $ownerRecord, string $pageClass): string
{
return __('app.services');
}
```
### Widget Heading/Description
```php
// Phải override getHeading()/getDescription() - KHÔNG dùng property
public function getHeading(): string | Htmlable | null
{
return __('app.widget_avg_time_by_handler');
}
```
### Enum Labels
```php
public function label(): string
{
return match ($this) {
self::ACTIVE => __('enums.contract_status.active'),
};
}
```
## Cách thêm Translation Key mới
### Bước 1: Thêm vào `lang/vi/app.php`
```php
return [
// ... existing keys ...
'new_key' => 'Giá trị tiếng Việt',
];
```
### Bước 2: Thêm vào `lang/en/app.php`
```php
return [
// ... existing keys ...
'new_key' => 'English value',
];
```
### Bước 3: Sử dụng trong code
```php
echo __('app.new_key');
```
## Lưu ý quan trọng
1. **`$pluralLabel` property** - KHÔNG tự dịch, phải override `getPluralLabel()`
2. **`getNavigationGroup()`** - KHÔNG tự dịch, phải gọi `__()`
3. **`$heading`/`$description`** trong ChartWidget - KHÔNG tự dịch, phải override methods
4. **Form fields** - PHẢI thêm `->label()` explicit
5. **`$title`** trong RelationManager - KHÔNG tự dịch, phải override `getTitle()`
6. **Filament vendor** - Có sẵn 57 file dịch tiếng Việt, tự kích hoạt khi `APP_LOCALE=vi`
## Kiểm tra Translation
```bash
# Kiểm tra key có tồn tại không
php artisan tinker --execute="echo __('app.new_key');"
# Kiểm tra locale hiện tại
php artisan tinker --execute="echo app()->getLocale();"
```