بومی‌سازی (i18n)

فینچ دارای یک سیستم i18n داخلی است که از چندین زبان پشتیبانی می‌کند. رشته‌های زبان را می‌توان در فایل‌های JSON ذخیره کرد یا مستقیماً در Dart تعریف نمود.

پیکربندی

گزینه‌های زبان را در FinchConfigs تنظیم کنید:

FinchConfigs configs = FinchConfigs(
  // مسیر دایرکتوری حاوی فایل‌های JSON زبان
  languagePath: pathTo(env.get('LANGUAGE_PATH', './lib/languages')),

  // استفاده از فایل‌های JSON (LanguageSource.json) یا Mapهای Dart (LanguageSource.dart)
  languageSource: LanguageSource.json,

  // اگر از LanguageSource.dart استفاده می‌کنید، map را اینجا ارائه دهید:
  // dartLanguages: languageDart,
);

گزینه ۱: فایل‌های JSON

برای هر زبان، یک فایل JSON در دایرکتوری languagePath خود ایجاد کنید. نام فایل همان کد زبان است:

lib/languages/en.json

{
  "dir": "ltr",
  "logo.title": "My App",
  "greeting": "Hello, World!",
  "example.params": "My name is {name}, my age is {age}",
  "example.params.arr": "My name is {0}, my age is {1}"
}

lib/languages/fa.json

{
  "dir": "rtl",
  "logo.title": "برنامه من",
  "greeting": "سلام دنیا!",
  "example.params": "نام من {name} است، سن من {age} سال است"
}

کلید dir (ltr / rtl) در اینجا یک کلید ترجمه‌ی ساده مانند هر کلید دیگری است — آن را در یک قالب با {{ $t('dir') }} بخوانید (همان‌طور که مثال Templates این کار را انجام می‌دهد)، نه با {{ $e.dir }}. در عوض، $e.dir به‌دنبال کلیدی با نام متفاوت می‌گردد — برای این تفاوت به Template Events مراجعه کنید.

گزینه ۲: Map در Dart

زبان‌ها را به‌صورت یک Map<String, Map<String, String>> در Dart تعریف کنید و FinchConfigs را به آن اشاره دهید:

// lib/languages/language_dart.g.dart (یا هر نام دیگری)
const languageDart = <String, Map<String, String>>{
  'en': {
    'dir': 'ltr',
    'logo.title': 'My App',
    'greeting': 'Hello, World!',
    'example.params': 'My name is {name}, my age is {age}',
  },
  'fa': {
    'dir': 'rtl',
    'logo.title': 'برنامه من',
    'greeting': 'سلام دنیا!',
    'example.params': 'نام من {name} است، سن من {age} سال است',
  },
};
FinchConfigs configs = FinchConfigs(
  languageSource: LanguageSource.dart,
  dartLanguages: languageDart,
);

واچر finch serve می‌تواند فایل‌های JSON را به‌طور خودکار به یک Dart map تبدیل کند. فایل تولیدشده در language_dart.g.dart نوشته می‌شود.

Translating in Controllers

از extension به‌نام .tr روی هر رشته‌ی کلید استفاده کنید. .write() رشته‌ی ترجمه‌شده‌ی نهایی را رندر می‌کند:

// ترجمه‌ی ساده
String text = 'logo.title'.tr.write();

// با پارامترهای نام‌دار
String text = 'example.params'.tr.write({'name': 'Alice', 'age': 30});

// با پارامترهای موقعیتی (آرایه) — متد ساده‌ی `.writeArr()` وجود ندارد؛
// زبان جاری را به‌صورت صریح به `writeByLangArr` پاس دهید
String text = 'example.params.arr'.tr.writeByLangArr(rq.getLanguage(), ['Alice', 30]);

رشته‌های ترجمه‌شده را به قالب‌ها پاس دهید:

rq.addParams({
  'greeting': 'greeting'.tr.write(),
  'userLine': 'example.params'.tr.write({'name': 'Alice', 'age': 30}),
});
return rq.renderView(path: 'pages/home');

ترجمه در قالب‌ها

برای ترجمه‌ی درون‌خطی از {{ $t('key') }} استفاده کنید:

<h1>{{ $t('logo.title') }}</h1>
<p>{{ $t('example.params', {'name': user.name, 'age': user.age}) }}</p>
<p>{{ $t('example.params.arr', ['Alice', 30]) }}</p>

تغییر زبان

زبان به این ترتیب تعیین می‌شود:

  1. اولین بخش path، اگر با یک کد زبان شناخته‌شده مطابقت داشته باشد (مثلاً /fa/home)
  2. فیلد داده‌ی lang روی endpointهای API
  3. کوکی language
  4. کلید session به نام language
  5. مقدار پیش‌فرض از تنظیمات

هر مقداری که در نهایت به دست می‌آید همیشه در برابر FinchConfigs.languages اعتبارسنجی می‌شود؛ اگر جزو زبان‌های پیکربندی‌شده نباشد (مثلاً یک کوکی نامعتبر یا قدیمی)، فینچ به 'en' بازمی‌گردد.

تغییر زبان از یک controller:

rq.changeLanguege('fa');

در یک قالب، URLای تولید کنید که زبان را تغییر می‌دهد:

<a href="{{ $e.urlToLanguage('fa') }}">فارسی</a>
<a href="{{ $e.urlToLanguage('en') }}">English</a>

زبان‌های در دسترس در قالب‌ها

{% for lang in $e.langs %}
  <a href="{{ $e.urlToLanguage(lang.code) }}">{{ lang.label }}</a>
{% endfor %}

هر ورودی: { code: 'en', label: 'English', contry: 'United States' } — توجه کنید فیلدهای label/contry خالی/حل‌نشده باقی می‌مانند، مگر اینکه کلیدهای language.<code>_label/language.<code>_contry توضیح‌داده‌شده در Template Events را اضافه کرده باشید.

TString — اشیای ترجمه

TString یک کلید را wrap می‌کند و به شما امکان می‌دهد ترجمه را به تعویق بیندازید:

var ts = TString('example.params');
rq.addParam('exampleTString', ts.write());

// یا با استفاده از میان‌بر .tr:
rq.addParam('examplePathString', 'example.path'.tr.write());

پارامترهای موقعیتی (آرایه‌ای)

به‌جای placeholderهای نام‌دار مانند {name}، یک رشته‌ی ترجمه می‌تواند از placeholderهای موقعیتی {0}، {1}، … استفاده کند:

{
  "example.params.arr": "My name is {0}, my age is {1}"
}

آن‌ها را از یک قالب، با پاس دادن یک لیست به‌عنوان آرگومان به $t، پر کنید:

<p>{{ $t('example.params.arr', ['Alexandre', 30]) }}</p>

یا از Dart، با writeByLangArr (میان‌بر ساده‌ی .writeArr() وجود ندارد — به Translating in Controllers در بالا مراجعه کنید):

rq.renderString(text: 'example.params.arr'.tr.writeByLangArr(rq.getLanguage(), ['Alexandre', 30]));