Given the following file structure (the same for en) in Laravel 5:
resources/
de/
list.php
countries.php
mail.php
pages/
pageA.json
pageB.json
I would like to know:
Is __(..) or @lang(..) disturbed from the presence of a folder pages with .json files?
How are the language files loaded?
This is what I managed to find out by myself:
The function __('list.button_send') triggers getFromJson($key, array $replace = [], $locale = null) with $key = 'list.button_send'
This is the main part of the function:
$locale = $locale ?: $this->locale;
// For JSON translations, there is only one file per locale, so we will simply load
// that file and then we will be ready to check the array for the key. These are
// only one level deep so we do not need to do any fancy searching through it.
$this->load('*', '*', $locale);
$line = $this->loaded['*']['*'][$locale][$key] ?? null;
I am already confused by the comment - my translations are in the three different *.php files. Why is Taylor talking about a single JSON file? But if we ignore that and continue, one finds that the load function looks like this:
// The loader is responsible for returning the array of language lines for the
// given namespace, group, and locale. We'll set the lines in this array of
// lines that have already been loaded so that we can easily access them.
$lines = $this->loader->load($locale, $group, $namespace);
$this->loaded[$namespace][$group][$locale] = $lines;
I have no idea why there is a need to call this function with $namespace and $group because it looks to me that they will always be * inside the Translator class. But ignoring that also, I come to the interesting part: What is $lines ? I would guess its an array of the form
$lines = ['list' => ... , 'countries' => ..., 'mail' => ...];
which would answer my questions to:
no they don't interfere
If one access a singe key in a lang, then all language files in that lang (meaning all *.php in that directory) are loaded and stored in the Translator object.
However, I was not able to confirm my guess. In order to do that, I need to find out what $this->loader->load($locale, $group, $namespace); actually does. But $this->loader get assigned by dependency injection in the constructor and I coulnd't find where it is defined.
Your first question Is __(..) or @lang(..) disturbed from the presence of a folder pages with .json files?:
Short answer, no.
$locale = $locale ?: $this->locale;
// For JSON translations, there is only one file per locale, so we will simply load
// that file and then we will be ready to check the array for the key. These are
// only one level deep so we do not need to do any fancy searching through it.
$this->load('*', '*', $locale);
$line = $this->loaded['*']['*'][$locale][$key] ?? null;
In the introduction section of https://laravel.com/docs/8.x/localization#introduction, it states that there are two approaches, one using an array in a php file:
Laravel provides two ways to manage translation strings. First, language > strings may be stored in files within the resources/lang directory. [...]
/resources
/lang
/en
messages.php
/es
messages.php
and another approach using a json file:
Or, translation strings may be defined within JSON files that are placed within the resources/lang directory [...]
/resources
/lang
en.json
es.json
The second approach is convenient, because it does not need keys. However it comes with the downside, that it will contain all language files from all sites in one file.
If you keep digging, you can see from the TranslationServiceProvider that the loader is definied by the FileLoader class. This is the method that loads the json file:
protected function loadJsonPaths($locale)
{
return collect(array_merge($this->jsonPaths, [$this->path]))
->reduce(function ($output, $path) use ($locale) {
if ($this->files->exists($full = "{$path}/{$locale}.json")) {
$decoded = json_decode($this->files->get($full), true);
if (is_null($decoded) || json_last_error() !== JSON_ERROR_NONE) {
throw new RuntimeException("Translation file [{$full}] contains an invalid JSON structure.");
}
$output = array_merge($output, $decoded);
}
return $output;
}, []);
}
The array $this->jsonPaths is empty per default. So unless you specify the jsonPaths in your app (through the Translator service) your json files inside your pages directory will be ignored.
Your second question How are the language files loaded?
You can load any translatable string through the helper function __($key,..) (you can also provide replacement array and locale and fallback, but we can ignore this for now). This will call app('translator')->get($key,...) The structure of the key is like this:
Namespace::group.key
The "Namespace::" is only relevant for packages https://laravel.com/docs/8.x/packages#translations so within your application, your keys look probably more like this:
group.key
In the first step, it will be checked if the key can be found in current language json (for example resources/lang/en.json) or in default langauge json.
If this cannot be found, then it will be checked if the language file can be found in resources/lang/{lang}/{group}.php. This will be checked for current locale and fallback locale.The group.php will be loaded only once and stored in the FileLoader singlton in memory.
Thus, for the current language and the default language, first the {lang}.json is loaded, if it exists, and then for those languages the resources/lang/{lang}/{group}.php is loaded (if not found in json). Each group will be loaded once per request. If a langauge group is not requested, it will also not be loaded.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With