github.com/System-Glitch/goyave/v2@v2.10.3-0.20200819142921-51011e75d504/docs_src/src/guide/advanced/localization.md (about)

     1  ---
     2  meta:
     3    - name: "og:title"
     4      content: "Localization - Goyave"
     5    - name: "twitter:title"
     6      content: "Localization - Goyave"
     7    - name: "title"
     8      content: "Localization - Goyave"
     9  ---
    10  
    11  # Localization
    12  
    13  [[toc]]
    14  
    15  ## Introduction
    16  
    17  The Goyave framework provides a convenient way to support multiple languages within your application. Out of the box, Goyave only provides the `en-US` language.
    18  
    19  ## Writing language files
    20  
    21  Language files are stored in the `resources/lang` directory.
    22  
    23  :::vue
    24  .
    25  └── resources
    26      └── lang
    27          └── en-US (*language name*)
    28              ├── fields.json (*optional*)
    29              ├── locale.json (*optional*)
    30              └── rules.json (*optional*)
    31  :::
    32  
    33  Each language has its own directory and should be named with an [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) language code. You can also append a variant to your languages: `en-US`, `en-UK`, `fr-FR`, `fr-CA`, ... **Case is important.**
    34  
    35  Each language directory contains three files. Each file is **optional**.
    36  - `fields.json`: field names translations and field-specific rule messages.
    37  - `locale.json`: all other language lines.
    38  - `rules.json`: validation rules messages.
    39  
    40  ::: tip
    41  All directories in the `resources/lang` directory are automatically loaded when the server starts.
    42  :::
    43  
    44  ### Fields
    45  
    46  The `fields.json` file contains the field names translations and their rule-specific messages. Translating field names helps making more expressive messages instead of showing the technical field name to the user. Rule-specific messages let you override a validation rule message for a specific field.
    47  
    48  **Example:**
    49  ``` json
    50  {
    51      "email": {
    52          "name": "email address",
    53          "rules": {
    54              "required": "You must provide an :field."
    55          }
    56      }
    57  }
    58  ```
    59  
    60  This `fields.json` file will change the validation message of the `required` validation rule to `You must provide an email address`.
    61  
    62  ::: tip
    63  Learn more about validation messages placeholders in the [validation](../basics/validation.html) section.
    64  :::
    65  
    66  ### Locale
    67  
    68  The `locale.json` file contains all language lines that are not related to validation. This is the place where you should write the language lines for your user interface or for the messages returned by your controllers.
    69  
    70  **Example:**
    71  ``` json
    72  {
    73      "product.created": "The product have been created with success.",
    74      "product.deleted": "The product have been deleted with success."
    75  }
    76  ```
    77  ::: tip
    78  It is a good practice to use **dot-separated** names for language lines to help making them clearer and more expressive.
    79  :::
    80  
    81  ### Rules
    82  
    83  The `rules.json` file contains the validation rules messages. These messages can have **[placeholders](../basics/validation.html#placeholders)**, which will be automatically replaced by the validator with dynamic values. If you write custom validation rules, their messages shall be written in this file.
    84  
    85  **Example:**
    86  
    87  ``` json
    88  {
    89      "integer": "The :field must be an integer.",
    90      "starts_with": "The :field must start with one of the following values: :values.",
    91      "same": "The :field and the :other must match."
    92  }
    93  ```
    94  
    95  #### Type-dependent rules
    96  
    97  The following rules have **type-dependent** messages. That means that their message is different depending on the type of the validated data.
    98  
    99  - `min`
   100  - `max`
   101  - `size`
   102  - `greater_than`
   103  - `greater_than_equal`
   104  - `lower_than`
   105  - `lower_than_equal`
   106  
   107  Type-dependent rules must have a language line for the four following types:
   108  - `string`
   109  - `numeric`
   110  - `array`
   111  - `file` 
   112  
   113  **Example:**
   114  ```json
   115  {
   116      "min.string": "The :field must be at least :min characters.",
   117      "min.numeric": "The :field must be at least :min.",
   118      "min.array": "The :field must have at least :min items.",
   119      "min.file": "The :field must be at least :min KiB."
   120  }
   121  ```
   122  
   123  #### Array validation
   124  
   125  Each rule, except the file-related rules and the `confirmed` rule, can be used to validate array values. If a rule is used to validate an array value and doesn't pass, the rule message `validation.rules.<rule_name>.array` (or `validation.rules.<rule_name>.<type>.array` if the rule is type-dependent) is returned.
   126  
   127  **Example:**
   128  ```json
   129  {
   130      "min.string.array": "The :field values must be at least :min characters.",
   131      "min.numeric.array": "The :field values must be at least :min.",
   132      "min.array.array": "The :field values must have at least :min items.",
   133      "digits.array": "The :field values must be digits only."
   134  }
   135  ```
   136  
   137  ### Overrides
   138  
   139  If you define the `en-US`  language in your application, the default language lines will be overridden by the ones in your language files, and all the undefined ones will be kept.
   140  
   141  It is possible to load a language directory manually from another location than the stardard `resources/lang` using the `lang.Load()` function. If the loaded language is already available in your application, the newly loaded one will override the previous in the same manner.
   142  
   143  ## Using localization
   144  
   145  When an incoming request enters your application, the core language middleware checks if the `Accept-Language` header is set, and set the `goyave.Request`'s `Lang` attribute accordingly. Localization is handled automatically by the validator.
   146  
   147  To use the localization feature, import the `lang` package:
   148  ``` go
   149  import "github.com/System-Glitch/goyave/v2/lang"
   150  ```
   151  
   152  The main function of the localization feature is `lang.Get(language, line string)`. This function lets you retrieve a language entry.
   153  
   154  For validation rules and attributes messages, use the following dot-separated paths:
   155  - `validation.rules.<rule_name>`
   156  - `validation.rules.<rule_name>.string`
   157  - `validation.rules.<rule_name>.numeric`
   158  - `validation.rules.<rule_name>.array`
   159  - `validation.rules.<rule_name>.file`
   160  - `validation.fields.<field_name>`
   161  - `validation.fields.<field_name>.<rule_name>`
   162  
   163  For normal lines, just use the name of the line. Note that if you have a line called "validation", it won't conflict with the dot-separated paths. If the line cannot be found, or the requested language is not available, the function will return the exact `line` attribute.
   164  
   165  **Example:**
   166  ``` go
   167  func ControllerHandler(response *goyave.Response, request *goyave.Request) {
   168      response.String(http.StatusOK, lang.Get(request.Lang, "my-custom-message"))
   169  }
   170  ```
   171  
   172  ### Placeholders
   173  
   174  Language lines can contain **placeholders**. Placeholders are identified by a colon directly followed by the placeholder name:
   175  
   176  ```json
   177  "greetings": "Greetings, :username!"
   178  ```
   179  
   180  The last parameter of the `lang.Get()` method is a variadic associative slice of placeholders and their replacement. In the following example, the placeholder `:username` will be replaced with the Name field in the user struct.
   181  
   182  ```go
   183  lang.Get("en-US", "greetings", ":username", user.Name) // "Greetings, Taylor!"
   184  ```
   185  
   186  You can provide as many as you want:
   187  
   188  ```go
   189  lang.Get("en-US", "greetings-with-date", ":username", user.Name, ":day", "Monday") // "Greetings, Taylor! Today is Monday"
   190  ```
   191  
   192  ::: tip
   193  When a placeholder is given, **all occurrences** are replaced.
   194  
   195  ```json
   196  "popular": ":product are very popular. :product sales exceeded 1000 last week."
   197  ```
   198  ```go
   199  lang.Get("en-US", "popular", ":product", "Lawnmowers")
   200  // "Lawnmowers are very popular. Lawnmowers sales exceeded 1000 last week."
   201  ```
   202  :::
   203  
   204  ### Localization reference
   205  
   206  ::: table
   207  [Get](#lang-get)
   208  [Load](#lang-load)
   209  [IsAvailable](#lang-isavailable)
   210  [GetAvailableLanguages](#lang-getavailablelanguages)
   211  [DetectLanguage](#lang-detectlanguage)
   212  :::
   213  
   214  #### lang.Get
   215  
   216  Get a language line.
   217  
   218  | Parameters               | Return   |
   219  |--------------------------|----------|
   220  | `lang string`            | `string` |
   221  | `line string`            |          |
   222  | `placeholders ...string` |          |
   223  
   224  **Example:**
   225  ``` go
   226  fmt.Println(lang.Get("en-US", "my-custom-message")) // "my message"
   227  fmt.Println(lang.Get("en-US", "validation.rules.greater_than.string")) // "The :field must be longer than the :other."
   228  fmt.Println(lang.Get("en-US", "validation.fields.email")) // "email address"
   229  fmt.Println(lang.Get("en-US", "greetings", ":username", user.Name)) // "Greetings, Taylor!"
   230  ```
   231  
   232  #### lang.Load
   233  
   234  Load a language directory.
   235  
   236  | Parameters        | Return |
   237  |-------------------|--------|
   238  | `language string` | `void` |
   239  | `path string`     |        |
   240  
   241  **Example:**
   242  ``` go
   243  lang.Load("zh", "/path/to/chinese-lang")
   244  ```
   245  
   246  #### lang.IsAvailable
   247  
   248  Returns true if the language is available.
   249  
   250  | Parameters    | Return |
   251  |---------------|--------|
   252  | `lang string` | `bool` |
   253  
   254  **Example:**
   255  ``` go
   256  fmt.Println(lang.IsAvailable("zh")) // true
   257  ```
   258  
   259  #### lang.GetAvailableLanguages
   260  
   261  Returns a slice of all loaded languages.
   262  
   263  This can be used to generate different routes for all languages supported by your applications such as:
   264  ```
   265  /en/products
   266  /fr/produits
   267  ...
   268  ```
   269  
   270  | Parameters    | Return |
   271  |---------------|--------|
   272  | `lang string` | `bool` |
   273  
   274  **Example:**
   275  ``` go
   276  fmt.Println(lang.GetAvailableLanguages()) // [en-US zh]
   277  ```
   278  
   279  #### lang.DetectLanguage
   280  
   281  DetectLanguage detects the language to use based on the given lang string.
   282  The given lang string can use the HTTP "Accept-Language" header format.
   283  
   284  - If `*` is provided, the default language will be used.
   285  - If multiple languages are given, the first available language will be used, and if none are available, the default language will be used.
   286  - If no variant is given (for example "en"), the first available variant will be used.
   287   
   288  For example, if `en-US` and `en-UK` are available and the request accepts `en`, `en-US` will be used.
   289  
   290  | Parameters    | Return   |
   291  |---------------|----------|
   292  | `lang string` | `string` |
   293  
   294  **Example:**
   295  ``` go
   296  fmt.Println(lang.DetectLanguage("en, fr-FR;q=0.9")) // "en-US"
   297  ```