mirror of
				https://github.com/yiisoft/yii2.git
				synced 2025-10-31 10:39:59 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			770 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			770 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| Internationalization
 | |
| ====================
 | |
| 
 | |
| Internationalization (I18N) refers to the process of designing a software application so that it can be adapted to
 | |
| various languages and regions without engineering changes. For Web applications, this is of particular importance
 | |
| because the potential users may be worldwide. Yii offers a full spectrum of I18N features that support message
 | |
| translation, view translation, date and number formatting.
 | |
| 
 | |
| 
 | |
| ## Locale and Language <span id="locale-language"></span>
 | |
| 
 | |
| ### Locale
 | |
| 
 | |
| Locale is a set of parameters that defines the user's language, country and any special variant preferences
 | |
| that the user wants to see in their user interface. It is usually identified by an ID consisting of a language
 | |
| ID and a region ID. 
 | |
| 
 | |
| For example, the ID `en-US` stands for the locale of "English and the United States".
 | |
| 
 | |
| For consistency reasons, all locale IDs used in Yii applications should be canonicalized to the format of
 | |
| `ll-CC`, where `ll` is a two- or three-letter lowercase language code according to
 | |
| [ISO-639](https://www.loc.gov/standards/iso639-2/) and `CC` is a two-letter country code according to
 | |
| [ISO-3166](https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes).
 | |
| More details about locale can be found in the
 | |
| [documentation of the ICU project](https://unicode-org.github.io/icu/userguide/locale/#the-locale-concept).
 | |
| 
 | |
| ### Language
 | |
| 
 | |
| In Yii, we often use the term "language" to refer to a locale.
 | |
| 
 | |
| A Yii application uses two kinds of languages: 
 | |
| * [[yii\base\Application::$sourceLanguage|source language]]: This refers to the language in which the text messages in the source code are written.
 | |
| * [[yii\base\Application::$language|target language]]: This is the language that should be used to display content to end users.
 | |
| 
 | |
| The so-called message translation service mainly translates a text message from source language to target language.
 | |
| 
 | |
| ### Configuration
 | |
| You can configure application languages in the "application configuration" like the following:
 | |
| 
 | |
| ```php
 | |
| return [
 | |
|     // set target language to be Russian
 | |
|     'language' => 'ru-RU',
 | |
|     
 | |
|     // set source language to be English
 | |
|     'sourceLanguage' => 'en-US',
 | |
|     
 | |
|     ......
 | |
| ];
 | |
| ```
 | |
| 
 | |
| The default value for the [[yii\base\Application::$sourceLanguage|source language]] is `en-US`, meaning
 | |
| US English. It is **recommended** that you keep this default value unchanged. Usually it is much easier
 | |
| to find people who can translate from "English to other languages" than from "non-English to non-English".
 | |
| 
 | |
| You often need to set the [[yii\base\Application::$language|target language]] dynamically based on different 
 | |
| factors, such as the language preference of end users. Instead of configuring it in the application configuration,
 | |
| you can use the following statement to change the target language:
 | |
| 
 | |
| ```php
 | |
| // change target language to Chinese
 | |
| \Yii::$app->language = 'zh-CN';
 | |
| ```
 | |
| 
 | |
| > Tip: If your source language varies among different parts of your code, you can
 | |
| > override the source language for different message sources, which are described in the next section.
 | |
| 
 | |
| ## Message Translation <span id="message-translation"></span>
 | |
| 
 | |
| ### From source language to target language
 | |
| The message translation service translates a text message from one language (usually the [[yii\base\Application::$sourceLanguage|source language]])
 | |
| to another (usually the [[yii\base\Application::$language|target language]]). 
 | |
| 
 | |
| It does the translation by looking up the message to be translated in a message source which stores the original messages and the translated messages. If the message is found, the corresponding translated message will be returned; otherwise the original message will be 
 | |
| returned untranslated.
 | |
| 
 | |
| ### How to implement
 | |
| To use the message translation service, you mainly need to do the following work:
 | |
| 
 | |
| 1. Wrap every text message that needs to be translated in a call to the [[Yii::t()]] method.
 | |
| 2. Configure one or multiple message sources in which the message translation service can look for translated messages.
 | |
| 3. Let the translators translate messages and store them in the message source(s).
 | |
| 
 | |
| 
 | |
| #### 1. Wrap a text message
 | |
| The method [[Yii::t()]] can be used like the following,
 | |
| 
 | |
| ```php
 | |
| echo \Yii::t('app', 'This is a string to translate!');
 | |
| ```
 | |
| 
 | |
| where the second parameter refers to the text message to be translated, while the first parameter refers to 
 | |
| the name of the category which is used to categorize the message. 
 | |
| 
 | |
| #### 2. Configure one or multiple message sources
 | |
| The [[Yii::t()]] method will call the `i18n` [application component](structure-application-components.md) `translate`
 | |
| method to perform the actual translation work. The component can be configured in the application configuration as follows,
 | |
| 
 | |
| ```php
 | |
| 'components' => [
 | |
|     // ...
 | |
|     'i18n' => [
 | |
|         'translations' => [
 | |
|             'app*' => [
 | |
|                 'class' => 'yii\i18n\PhpMessageSource',
 | |
|                 //'basePath' => '@app/messages',
 | |
|                 //'sourceLanguage' => 'en-US',
 | |
|                 'fileMap' => [
 | |
|                     'app' => 'app.php',
 | |
|                     'app/error' => 'error.php',
 | |
|                 ],
 | |
|             ],
 | |
|         ],
 | |
|     ],
 | |
| ],
 | |
| ```
 | |
| 
 | |
| In the above code, a message source supported by [[yii\i18n\PhpMessageSource]] is being configured. 
 | |
| 
 | |
| ##### Category wildcards with `*` symbol
 | |
| 
 | |
| The pattern `app*` indicates that all message categories whose names start with `app` should be translated using this
 | |
| message source. 
 | |
| 
 | |
| #### 3. Let the translators translate messages and store them in the message source(s)
 | |
| 
 | |
| The [[yii\i18n\PhpMessageSource]] class uses PHP files with a simple PHP array to store message translations. 
 | |
| These files contain a map of the messages in `source language` to the translation in the `target language`.
 | |
| 
 | |
| > Info: You can automatically generate these PHP files by using the [`message` command](#message-command),
 | |
| > which will be introduced later in this chapter.
 | |
| 
 | |
| Each PHP file corresponds to the messages of a single category. By default, the file name should be the same as
 | |
| the category name. Example for `app/messages/nl-NL/main.php:`
 | |
| 
 | |
| ```php
 | |
| <?php
 | |
| 
 | |
| /**
 | |
| * Translation map for nl-NL
 | |
| */
 | |
| return [
 | |
|     'welcome' => 'welkom'
 | |
| ];
 | |
| 
 | |
| ```
 | |
| 
 | |
| 
 | |
| ##### File mapping
 | |
| 
 | |
| You may configure [[yii\i18n\PhpMessageSource::fileMap|fileMap]] to map a category to a PHP file with a different naming approach. 
 | |
| 
 | |
| In the above example, the category `app/error` is mapped to the PHP file `@app/messages/ru-RU/error.php` 
 | |
| (assuming `ru-RU` is the target language). 
 | |
| However, without this configuration the category would be mapped to `@app/messages/ru-RU/app/error.php` instead.
 | |
| 
 | |
| #####  Other storage types
 | |
| 
 | |
| Besides, storing the messages in PHP files, you may also use the following message sources to store translated messages
 | |
| in different storage:
 | |
| 
 | |
| - [[yii\i18n\GettextMessageSource]] uses GNU Gettext MO or PO files to maintain translated messages.
 | |
| - [[yii\i18n\DbMessageSource]] uses a database table to store translated messages.
 | |
| 
 | |
| 
 | |
| ## Message Formatting <span id="message-formatting"></span>
 | |
| 
 | |
| When translating a message, you can embed some placeholders and have them replaced by dynamic parameter values.
 | |
| You can even use special placeholder syntax to have the parameter values formatted according to the target language.
 | |
| In this subsection, we will describe different ways of formatting messages.
 | |
| 
 | |
| ### Message Parameters <span id="message-parameters"></span>
 | |
| 
 | |
| In a message to be translated, you can embed one or multiple parameters (also called placeholders) so that they can be
 | |
| replaced by the given values. By giving different sets of values, you can variate the translated message dynamically.
 | |
| In the following example, the placeholder `{username}` in the message `'Hello, {username}!'` will be replaced
 | |
| by `'Alexander'` and `'Qiang'`, respectively.
 | |
| 
 | |
| ```php
 | |
| $username = 'Alexander';
 | |
| // display a translated message with username being "Alexander"
 | |
| echo \Yii::t('app', 'Hello, {username}!', [
 | |
|     'username' => $username,
 | |
| ]);
 | |
| 
 | |
| $username = 'Qiang';
 | |
| // display a translated message with username being "Qiang"
 | |
| echo \Yii::t('app', 'Hello, {username}!', [
 | |
|     'username' => $username,
 | |
| ]);
 | |
| ```
 | |
| 
 | |
| While translating a message containing placeholders, you should leave the placeholders as is. This is because the placeholders
 | |
| will be replaced with the actual values when you call `Yii::t()` to translate a message.
 | |
| 
 | |
| You can use either *named placeholders* or *positional placeholders*, but not both, in a single message.
 | |
|  
 | |
| The previous example shows how you can use named placeholders. That is, each placeholder is written in the format of 
 | |
| `{name}`, and you provide an associative array whose keys are the placeholder names
 | |
| (without the curly brackets) and whose values are the corresponding values' placeholder to be replaced with.
 | |
| 
 | |
| Positional placeholders use zero-based integer sequence as names which are replaced by the provided values
 | |
| according to their positions in the call of `Yii::t()`. In the following example, the positional placeholders
 | |
| `{0}`, `{1}` and `{2}` will be replaced by the values of `$price`, `$count` and `$subtotal`, respectively.
 | |
| 
 | |
| ```php
 | |
| $price = 100;
 | |
| $count = 2;
 | |
| $subtotal = 200;
 | |
| echo \Yii::t('app', 'Price: {0}, Count: {1}, Subtotal: {2}', [$price, $count, $subtotal]);
 | |
| ```
 | |
| 
 | |
| In case of a single positional parameter its value could be specified without wrapping it into array:
 | |
| 
 | |
| ```php
 | |
| echo \Yii::t('app', 'Price: {0}', $price);
 | |
| ```
 | |
| 
 | |
| > Tip: In most cases you should use named placeholders. This is because the names will make the translators
 | |
| > understand better the whole messages being translated.
 | |
| 
 | |
| 
 | |
| ### Parameter Formatting <span id="parameter-formatting"></span>
 | |
| 
 | |
| You can specify additional formatting rules in the placeholders of a message so that the parameter values can be 
 | |
| formatted properly before they replace the placeholders. In the following example, the price parameter value will be
 | |
| treated as a number and formatted as a currency value:
 | |
| 
 | |
| ```php
 | |
| $price = 100;
 | |
| echo \Yii::t('app', 'Price: {0,number,currency}', $price);
 | |
| ```
 | |
| 
 | |
| > Note: Parameter formatting requires the installation of the [intl PHP extension](https://www.php.net/manual/en/intro.intl.php).
 | |
| 
 | |
| You can use either the short form or the full form to specify a placeholder with formatting:
 | |
| 
 | |
| ```
 | |
| short form: {name,type}
 | |
| full form: {name,type,style}
 | |
| ```
 | |
| 
 | |
| > Note: If you need to use special characters such as `{`, `}`, `'`, `#`, wrap them in `'`:
 | |
| > 
 | |
| ```php
 | |
| echo Yii::t('app', "Example of string with ''-escaped characters'': '{' '}' '{test}' {count,plural,other{''count'' value is # '#{}'}}", ['count' => 3]);
 | |
| ```
 | |
| 
 | |
| Complete format is described in the [ICU documentation](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classMessageFormat.html).
 | |
| In the following we will show some common usages.
 | |
| 
 | |
| 
 | |
| #### Number <span id="number"></span>
 | |
| 
 | |
| The parameter value is treated as a number. For example,
 | |
| 
 | |
| ```php
 | |
| $sum = 42;
 | |
| echo \Yii::t('app', 'Balance: {0,number}', $sum);
 | |
| ```
 | |
| 
 | |
| You can specify an optional parameter style as `integer`, `currency`, or `percent`:
 | |
| 
 | |
| ```php
 | |
| $sum = 42;
 | |
| echo \Yii::t('app', 'Balance: {0,number,currency}', $sum);
 | |
| ```
 | |
| 
 | |
| You can also specify a custom pattern to format the number. For example,
 | |
| 
 | |
| ```php
 | |
| $sum = 42;
 | |
| echo \Yii::t('app', 'Balance: {0,number,,000,000000}', $sum);
 | |
| ```
 | |
| 
 | |
| Characters used in the custom format could be found in
 | |
| [ICU API reference](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classDecimalFormat.html) under "Special Pattern Characters"
 | |
| section.
 | |
|  
 | |
|  
 | |
| The value is always formatted according to the locale you are translating to i.e. you cannot change decimal or thousands
 | |
| separators, currency symbol etc. without changing translation locale. If you need to customize these you can
 | |
| use [[yii\i18n\Formatter::asDecimal()]] and [[yii\i18n\Formatter::asCurrency()]].
 | |
| 
 | |
| #### Date <span id="date"></span>
 | |
| 
 | |
| The parameter value should be formatted as a date. For example,
 | |
| 
 | |
| ```php
 | |
| echo \Yii::t('app', 'Today is {0,date}', time());
 | |
| ```
 | |
| 
 | |
| You can specify an optional parameter style as `short`, `medium`, `long`, or `full`:
 | |
| 
 | |
| ```php
 | |
| echo \Yii::t('app', 'Today is {0,date,short}', time());
 | |
| ```
 | |
| 
 | |
| You can also specify a custom pattern to format the date value:
 | |
| 
 | |
| ```php
 | |
| echo \Yii::t('app', 'Today is {0,date,yyyy-MM-dd}', time());
 | |
| ```
 | |
| 
 | |
| [Formatting reference](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1SimpleDateFormat.html#details).
 | |
| 
 | |
| 
 | |
| #### Time <span id="time"></span>
 | |
| 
 | |
| The parameter value should be formatted as a time. For example,
 | |
| 
 | |
| ```php
 | |
| echo \Yii::t('app', 'It is {0,time}', time());
 | |
| ```
 | |
| 
 | |
| You can specify an optional parameter style as `short`, `medium`, `long`, or `full`:
 | |
| 
 | |
| ```php
 | |
| echo \Yii::t('app', 'It is {0,time,short}', time());
 | |
| ```
 | |
| 
 | |
| You can also specify a custom pattern to format the time value:
 | |
| 
 | |
| ```php
 | |
| echo \Yii::t('app', 'It is {0,date,HH:mm}', time());
 | |
| ```
 | |
| 
 | |
| [Formatting reference](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1SimpleDateFormat.html#details).
 | |
| 
 | |
| 
 | |
| #### Spellout <span id="spellout"></span>
 | |
| 
 | |
| The parameter value should be treated as a number and formatted as a spellout. For example,
 | |
| 
 | |
| ```php
 | |
| // may produce "42 is spelled as forty-two"
 | |
| echo \Yii::t('app', '{n,number} is spelled as {n,spellout}', ['n' => 42]);
 | |
| ```
 | |
| 
 | |
| By default, the number is spelled out as cardinal. It could be changed:
 | |
| 
 | |
| ```php
 | |
| // may produce "I am forty-seventh agent"
 | |
| echo \Yii::t('app', 'I am {n,spellout,%spellout-ordinal} agent', ['n' => 47]);
 | |
| ```
 | |
| 
 | |
| Note that there should be no space after `spellout,` and before `%`.
 | |
| 
 | |
| To get a list of options available for locale you're using check 
 | |
| "Numbering schemas, Spellout" at [https://intl.rmcreative.ru/](https://intl.rmcreative.ru/).
 | |
| 
 | |
| #### Ordinal <span id="ordinal"></span>
 | |
| 
 | |
| The parameter value should be treated as a number and formatted as an ordinal name. For example,
 | |
| 
 | |
| ```php
 | |
| // may produce "You are the 42nd visitor here!"
 | |
| echo \Yii::t('app', 'You are the {n,ordinal} visitor here!', ['n' => 42]);
 | |
| ```
 | |
| 
 | |
| Ordinal supports more ways of formatting for languages such as Spanish:
 | |
| 
 | |
| ```php
 | |
| // may produce 471ª
 | |
| echo \Yii::t('app', '{n,ordinal,%digits-ordinal-feminine}', ['n' => 471]);
 | |
| ```
 | |
| 
 | |
| Note that there should be no space after `ordinal,` and before `%`.
 | |
| 
 | |
| To get a list of options available for locale you're using check 
 | |
| "Numbering schemas, Ordinal" at [https://intl.rmcreative.ru/](https://intl.rmcreative.ru/).
 | |
| 
 | |
| #### Duration <span id="duration"></span>
 | |
| 
 | |
| The parameter value should be treated as the number of seconds and formatted as a time duration string. For example,
 | |
| 
 | |
| ```php
 | |
| // may produce "You are here for 47 sec. already!"
 | |
| echo \Yii::t('app', 'You are here for {n,duration} already!', ['n' => 47]);
 | |
| ```
 | |
| 
 | |
| Duration supports more ways of formatting:
 | |
| 
 | |
| ```php
 | |
| // may produce 130:53:47
 | |
| echo \Yii::t('app', '{n,duration,%in-numerals}', ['n' => 471227]);
 | |
| ```
 | |
| 
 | |
| Note that there should be no space after `duration,` and before `%`.
 | |
| 
 | |
| To get a list of options available for locale you're using check 
 | |
| "Numbering schemas, Duration" at [https://intl.rmcreative.ru/](https://intl.rmcreative.ru/).
 | |
| 
 | |
| #### Plural <span id="plural"></span>
 | |
| 
 | |
| Different languages have different ways to inflect plurals. Yii provides a convenient way for translating messages in
 | |
| different plural forms that works well even for very complex rules. Instead of dealing with the inflection rules directly,
 | |
| it is sufficient to provide the translation of inflected words in certain situations only. For example,
 | |
| 
 | |
| ```php
 | |
| // When $n = 0, it may produce "There are no cats!"
 | |
| // When $n = 1, it may produce "There is one cat!"
 | |
| // When $n = 42, it may produce "There are 42 cats!"
 | |
| echo \Yii::t('app', 'There {n,plural,=0{are no cats} =1{is one cat} other{are # cats}}!', ['n' => $n]);
 | |
| ```
 | |
| 
 | |
| In the plural rule arguments above, `=` means explicit value. So `=0` means exactly zero, `=1` means exactly one.
 | |
| `other` stands for any other value. `#` is replaced with the value of `n` formatted according to target language.
 | |
| 
 | |
| Plural forms can be very complicated in some languages. In the following Russian example, `=1` matches exactly `n = 1` 
 | |
| while `one` matches `21` or `101`:
 | |
| 
 | |
| ```
 | |
| Здесь {n,plural,=0{котов нет} =1{есть один кот} one{# кот} few{# кота} many{# котов} other{# кота}}!
 | |
| ```
 | |
| 
 | |
| These `other`, `few`, `many` and other special argument names vary depending on language. To learn which ones you should
 | |
| specify for a particular locale, please refer to "Plural Rules, Cardinal" at [https://intl.rmcreative.ru/](https://intl.rmcreative.ru/). 
 | |
| Alternatively you can refer to [rules reference at unicode.org](https://cldr.unicode.org/index/cldr-spec/plural-rules).
 | |
| 
 | |
| > Note: The above example Russian message is mainly used as a translated message, not an original message, unless you set
 | |
| > the [[yii\base\Application::$sourceLanguage|source language]] of your application as `ru-RU` and translating from Russian.
 | |
| >
 | |
| > When a translation is not found for an original message specified in `Yii::t()` call, the plural rules for the
 | |
| > [[yii\base\Application::$sourceLanguage|source language]] will be applied to the original message.
 | |
| 
 | |
| There's an `offset` parameter for the cases when the string is like the following:
 | |
|  
 | |
| ```php
 | |
| $likeCount = 2;
 | |
| echo Yii::t('app', 'You {likeCount,plural,
 | |
|     offset: 1
 | |
|     =0{did not like this}
 | |
|     =1{liked this}
 | |
|     one{and one other person liked this}
 | |
|     other{and # others liked this}
 | |
| }', [
 | |
|     'likeCount' => $likeCount
 | |
| ]);
 | |
| 
 | |
| // You and one other person liked this
 | |
| ```
 | |
| 
 | |
| #### Ordinal selection <span id="ordinal-selection"></span>
 | |
| 
 | |
| The parameter type of `selectordinal` is meant to choose a string based on language rules for ordinals for the
 | |
| locale you are translating to:
 | |
| 
 | |
| ```php
 | |
| $n = 3;
 | |
| echo Yii::t('app', 'You are the {n,selectordinal,one{#st} two{#nd} few{#rd} other{#th}} visitor', ['n' => $n]);
 | |
| // For English it outputs:
 | |
| // You are the 3rd visitor
 | |
| 
 | |
| // Translation
 | |
| 'You are the {n,selectordinal,one{#st} two{#nd} few{#rd} other{#th}} visitor' => 'Вы {n,selectordinal,other{#-й}} посетитель',
 | |
| 
 | |
| // For Russian translation it outputs:
 | |
| // Вы 3-й посетитель
 | |
| ```
 | |
| 
 | |
| The format is very close to what's used for plurals. To learn which arguments you should specify for a particular locale,
 | |
| please refer to "Plural Rules, Ordinal" at [https://intl.rmcreative.ru/](https://intl.rmcreative.ru/). 
 | |
| Alternatively you can refer to [rules reference at unicode.org](https://unicode-org.github.io/cldr-staging/charts/37/supplemental/language_plural_rules.html).
 | |
| 
 | |
| #### Selection <span id="selection"></span>
 | |
| 
 | |
| You can use the `select` parameter type to choose a phrase based on the parameter value. For example, 
 | |
| 
 | |
| ```php
 | |
| // It may produce "Snoopy is a dog and it loves Yii!"
 | |
| echo \Yii::t('app', '{name} is a {gender} and {gender,select,female{she} male{he} other{it}} loves Yii!', [
 | |
|     'name' => 'Snoopy',
 | |
|     'gender' => 'dog',
 | |
| ]);
 | |
| ```
 | |
| 
 | |
| In the expression above, both `female` and `male` are possible parameter values, while `other` handles values that 
 | |
| do not match either one of them. Following each possible parameter value, you should specify a phrase and enclose
 | |
| it in a pair of curly brackets.
 | |
| 
 | |
| 
 | |
| ### Specifying default message source <span id="default-message-source"></span>
 | |
| 
 | |
| You can specify default message source that will be used as a fallback for category that doesn't match any
 | |
| configured category. You can do that by configuring a wildcard category `*`. In order to do that, add the following
 | |
| to the application config:
 | |
| 
 | |
| ```php
 | |
| //configure i18n component
 | |
| 
 | |
| 'i18n' => [
 | |
|     'translations' => [
 | |
|         '*' => [
 | |
|             'class' => 'yii\i18n\PhpMessageSource'
 | |
|         ],
 | |
|     ],
 | |
| ],
 | |
| ```
 | |
| 
 | |
| Now you can use categories without configuring each one, which is similar to Yii 1.1 behavior.
 | |
| Messages for the category will be loaded from a file under the default translation `basePath` that is `@app/messages`:
 | |
| 
 | |
| ```php
 | |
| echo Yii::t('not_specified_category', 'message from unspecified category');
 | |
| ```
 | |
| 
 | |
| The message will be loaded from `@app/messages/<LanguageCode>/not_specified_category.php`.
 | |
| 
 | |
| ### Translating module messages <span id="module-translation"></span>
 | |
| 
 | |
| If you want to translate the messages for a module and avoid using a single translation file for all the messages, you can do it like the following:
 | |
| 
 | |
| ```php
 | |
| <?php
 | |
| 
 | |
| namespace app\modules\users;
 | |
| 
 | |
| use Yii;
 | |
| 
 | |
| class Module extends \yii\base\Module
 | |
| {
 | |
|     public $controllerNamespace = 'app\modules\users\controllers';
 | |
| 
 | |
|     public function init()
 | |
|     {
 | |
|         parent::init();
 | |
|         $this->registerTranslations();
 | |
|     }
 | |
| 
 | |
|     public function registerTranslations()
 | |
|     {
 | |
|         Yii::$app->i18n->translations['modules/users/*'] = [
 | |
|             'class' => 'yii\i18n\PhpMessageSource',
 | |
|             'sourceLanguage' => 'en-US',
 | |
|             'basePath' => '@app/modules/users/messages',
 | |
|             'fileMap' => [
 | |
|                 'modules/users/validation' => 'validation.php',
 | |
|                 'modules/users/form' => 'form.php',
 | |
|                 ...
 | |
|             ],
 | |
|         ];
 | |
|     }
 | |
| 
 | |
|     public static function t($category, $message, $params = [], $language = null)
 | |
|     {
 | |
|         return Yii::t('modules/users/' . $category, $message, $params, $language);
 | |
|     }
 | |
| 
 | |
| }
 | |
| ```
 | |
| 
 | |
| In the example above we are using wildcard for matching and then filtering each category per needed file. Instead of using `fileMap`, you can simply
 | |
| use the convention of the category mapping to the same named file.
 | |
| Now you can use `Module::t('validation', 'your custom validation message')` or `Module::t('form', 'some form label')` directly.
 | |
| 
 | |
| ### Translating widgets messages <span id="widget-translation"></span>
 | |
| 
 | |
| The same rule as applied for Modules above can be applied for widgets too, for example:
 | |
| 
 | |
| ```php
 | |
| <?php
 | |
| 
 | |
| namespace app\widgets\menu;
 | |
| 
 | |
| use yii\base\Widget;
 | |
| use Yii;
 | |
| 
 | |
| class Menu extends Widget
 | |
| {
 | |
| 
 | |
|     public function init()
 | |
|     {
 | |
|         parent::init();
 | |
|         $this->registerTranslations();
 | |
|     }
 | |
| 
 | |
|     public function registerTranslations()
 | |
|     {
 | |
|         $i18n = Yii::$app->i18n;
 | |
|         $i18n->translations['widgets/menu/*'] = [
 | |
|             'class' => 'yii\i18n\PhpMessageSource',
 | |
|             'sourceLanguage' => 'en-US',
 | |
|             'basePath' => '@app/widgets/menu/messages',
 | |
|             'fileMap' => [
 | |
|                 'widgets/menu/messages' => 'messages.php',
 | |
|             ],
 | |
|         ];
 | |
|     }
 | |
| 
 | |
|     public function run()
 | |
|     {
 | |
|         echo $this->render('index');
 | |
|     }
 | |
| 
 | |
|     public static function t($category, $message, $params = [], $language = null)
 | |
|     {
 | |
|         return Yii::t('widgets/menu/' . $category, $message, $params, $language);
 | |
|     }
 | |
| 
 | |
| }
 | |
| ```
 | |
| 
 | |
| Instead of using `fileMap` you can simply use the convention of the category mapping to the same named file.
 | |
| Now you can use `Menu::t('messages', 'new messages {messages}', ['{messages}' => 10])` directly.
 | |
| 
 | |
| > Note: For widgets you also can use i18n views, with the same rules as for controllers being applied to them too.
 | |
| 
 | |
| 
 | |
| ### Translating framework messages <span id="framework-translation"></span>
 | |
| 
 | |
| Yii comes with the default translation messages for validation errors and some other strings. These messages are all
 | |
| in the category `yii`. Sometimes you want to correct the default framework message translation for your application.
 | |
| In order to do so, configure the `i18n` [application component](structure-application-components.md) like the following:
 | |
| 
 | |
| ```php
 | |
| 'i18n' => [
 | |
|     'translations' => [
 | |
|         'yii' => [
 | |
|             'class' => 'yii\i18n\PhpMessageSource',
 | |
|             'sourceLanguage' => 'en-US',
 | |
|             'basePath' => '@app/messages'
 | |
|         ],
 | |
|     ],
 | |
| ],
 | |
| ```
 | |
| 
 | |
| Now you can place your adjusted translations to `@app/messages/<language>/yii.php`.
 | |
| 
 | |
| ### Handling missing translations <span id="missing-translations"></span>
 | |
| 
 | |
| Even if the translation is missing from the source, Yii will display the requested message content. Such behavior is very convenient
 | |
| in case your raw message is a valid verbose text. However, sometimes it is not enough.
 | |
| You may need to perform some custom processing of the situation, when the requested translation is missing from the source.
 | |
| This can be achieved using the [[yii\i18n\MessageSource::EVENT_MISSING_TRANSLATION|missingTranslation]]-event of [[yii\i18n\MessageSource]].
 | |
| 
 | |
| For example, you may want to mark all the missing translations with something notable, so that they can be easily found at the page.
 | |
| First you need to setup an event handler. This can be done in the application configuration:
 | |
| 
 | |
| ```php
 | |
| 'components' => [
 | |
|     // ...
 | |
|     'i18n' => [
 | |
|         'translations' => [
 | |
|             'app*' => [
 | |
|                 'class' => 'yii\i18n\PhpMessageSource',
 | |
|                 'fileMap' => [
 | |
|                     'app' => 'app.php',
 | |
|                     'app/error' => 'error.php',
 | |
|                 ],
 | |
|                 'on missingTranslation' => ['app\components\TranslationEventHandler', 'handleMissingTranslation']
 | |
|             ],
 | |
|         ],
 | |
|     ],
 | |
| ],
 | |
| ```
 | |
| 
 | |
| Now you need to implement your own event handler:
 | |
| 
 | |
| ```php
 | |
| <?php
 | |
| 
 | |
| namespace app\components;
 | |
| 
 | |
| use yii\i18n\MissingTranslationEvent;
 | |
| 
 | |
| class TranslationEventHandler
 | |
| {
 | |
|     public static function handleMissingTranslation(MissingTranslationEvent $event)
 | |
|     {
 | |
|         $event->translatedMessage = "@MISSING: {$event->category}.{$event->message} FOR LANGUAGE {$event->language} @";
 | |
|     }
 | |
| }
 | |
| ```
 | |
| 
 | |
| If [[yii\i18n\MissingTranslationEvent::translatedMessage]] is set by the event handler it will be displayed as the translation result.
 | |
| 
 | |
| > Note: each message source handles its missing translations separately. If you are using several message sources
 | |
| > and wish them to treat the missing translations in the same way, you should assign the corresponding event handler to each of them.
 | |
| 
 | |
| 
 | |
| ### Using the `message` command <span id="message-command"></span>
 | |
| 
 | |
| Translations can be stored in [[yii\i18n\PhpMessageSource|php files]], [[yii\i18n\GettextMessageSource|.po files]] or in a [[yii\i18n\DbMessageSource|database]]. See specific classes for additional options.
 | |
| 
 | |
| First you need to create a configuration file. Decide where you want to store it and then issue the command 
 | |
| 
 | |
| ```bash
 | |
| ./yii message/config-template path/to/config.php
 | |
| ```
 | |
| 
 | |
| Open the created file and adjust the parameters to fit your needs. Pay special attention to:
 | |
| 
 | |
| * `languages`: an array representing what languages your app should be translated to;
 | |
| * `messagePath`: path where to store message files, which should match the `i18n`'s `basePath` parameter stated in config.
 | |
| 
 | |
| You may also use './yii message/config' command to dynamically generate configuration file with specified options via cli.
 | |
| For example, you can set `languages` and `messagePath` parameters like the following:
 | |
| 
 | |
| ```bash
 | |
| ./yii message/config --languages=de,ja --messagePath=messages path/to/config.php
 | |
| ```
 | |
| 
 | |
| To get list of available options execute next command:
 | |
| 
 | |
| ```bash
 | |
| ./yii help message/config
 | |
| ```
 | |
| 
 | |
| Once you're done with the configuration file you can finally extract your messages with the command:
 | |
| 
 | |
| ```bash
 | |
| ./yii message path/to/config.php
 | |
| ```
 | |
| 
 | |
| Also, you may use options to dynamically change parameters for extraction.
 | |
| 
 | |
| You will then find your files (if you've chosen file based translations) in your `messagePath` directory.
 | |
| 
 | |
| 
 | |
| ## View Translation <span id="view-translation"></span>
 | |
| 
 | |
| Instead of translating individual text messages, sometimes you may want to translate a whole view script.
 | |
| To achieve this goal, simply translate the view and save it under a subdirectory whose name is the same as 
 | |
| target language. For example, if you want to translate the view script `views/site/index.php` and the target
 | |
| language is `ru-RU`, you may translate the view and save it as  the file `views/site/ru-RU/index.php`. Now
 | |
| whenever you call [[yii\base\View::renderFile()]] or any method that invoke this method (e.g. [[yii\base\Controller::render()]])
 | |
| to render the view `views/site/index.php`, it will end up rendering the translated view `views/site/ru-RU/index.php`, instead. 
 | |
| 
 | |
| > Note: If the [[yii\base\Application::$language|target language]] is the same as [[yii\base\Application::$sourceLanguage|source language]]
 | |
| > original view will be rendered regardless of presence of translated view.
 | |
| 
 | |
| 
 | |
| ## Formatting Date and Number Values <span id="date-number"></span>
 | |
| 
 | |
| See the [Data Formatting](output-formatting.md) section for details.
 | |
| 
 | |
| 
 | |
| ## Setting Up PHP Environment <span id="setup-environment"></span>
 | |
| 
 | |
| Yii uses the [PHP intl extension](https://www.php.net/manual/en/book.intl.php) to provide most of its I18N features,
 | |
| such as the date and number formatting of the [[yii\i18n\Formatter]] class and the message formatting using [[yii\i18n\MessageFormatter]].
 | |
| Both classes provide a fallback mechanism when the `intl` extension is not installed. However, the fallback implementation
 | |
| only works well for English target language. So it is highly recommended that you install `intl` when I18N is needed.
 | |
| 
 | |
| The [PHP intl extension](https://www.php.net/manual/en/book.intl.php) is based on the [ICU library](https://icu.unicode.org/) which
 | |
| provides the knowledge and formatting rules for all different locales. Different versions of ICU may produce different
 | |
| formatting result of date and number values. To ensure your website produces the same results across all environments,
 | |
| it is recommended that you install the same version of the `intl` extension (and thus the same version of ICU)
 | |
| in all environments.
 | |
| 
 | |
| To find out which version of ICU is used by PHP, you can run the following script, which will give you the PHP and ICU version being used.
 | |
| 
 | |
| ```php
 | |
| <?php
 | |
| echo "PHP: " . PHP_VERSION . "\n";
 | |
| echo "ICU: " . INTL_ICU_VERSION . "\n";
 | |
| echo "ICU Data: " . INTL_ICU_DATA_VERSION . "\n";
 | |
| ```
 | |
| 
 | |
| It is also recommended that you use an ICU version equal or greater than version 49. This will ensure you can use all the features
 | |
| described in this document. For example, an ICU version below 49 does not support using `#` placeholders in plural rules.
 | |
| Please refer to <https://icu.unicode.org/download> for a complete list of available ICU versions. Note that the version 
 | |
| numbering has changed after the 4.8 release (e.g., ICU 4.8, ICU 49, ICU 50, etc.)
 | |
| 
 | |
| Additionally the information in the time zone database shipped with the ICU library may be outdated. Please refer
 | |
| to the [ICU manual](https://unicode-org.github.io/icu/userguide/datetime/timezone/#updating-the-time-zone-data) for details
 | |
| on updating the time zone database. While for output formatting the ICU timezone database is used, the time zone database
 | |
| used by PHP may be relevant too. You can update it by installing the latest version of the [pecl package `timezonedb`](https://pecl.php.net/package/timezonedb).
 | 
