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

3.8 KiB

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

// Pattern: app.resource_{name}
'resource_feedbacks' => 'Phản ánh',
'resource_products' => 'Sản phẩm',
'resource_customers' => 'Khách hàng',

2. Status Labels

// Pattern: app.status_{name}
'status_pending' => 'Chờ xử lý',
'status_processing' => 'Đang xử lý',
'status_resolved' => 'Đã xử lý',
'status_closed' => 'Đã đóng',

3. Form Labels

// Pattern: app.{field_name}
'name' => 'Tên',
'email' => 'Email',
'phone' => 'Điện thoại',

4. Enum Labels

// Pattern: enums.{enum_name}.{case_value}
'service.management_fee' => 'Phí quản lý',
'contract_status.active' => 'Đang hiệu lực',

5. Feedback Domain

// 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

// 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

// PHẢI thêm ->label() explicit
TextInput::make('name')->label(__('app.name'))
Select::make('status')->label(__('app.status'))

RelationManager Title

// 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

// 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

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

return [
    // ... existing keys ...
    'new_key' => 'Giá trị tiếng Việt',
];

Bước 2: Thêm vào lang/en/app.php

return [
    // ... existing keys ...
    'new_key' => 'English value',
];

Bước 3: Sử dụng trong code

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

# 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();"