我正在尝试使我的项目支持多种语言。
我想使用 JSON 文件,因为我的项目有很多页面,所以需要翻译很多字符串。
为了避免混淆,我想使用嵌套的 JSON 对象而不仅仅是键。
例如我的 en.json 文件如下所示:
{
"login": {
"login": "Login",
"email": "Email",
"emailPlaceholder": "Registered email address",
"password": "Password",
"passwordPlaceHolder": "Your account password"
},
"dashboard": {}
}
所以我想要每个页面都有一个密钥。
但是当我在视图文件上使用它时,它读起来就像一个常规字符串:
<label for="email">
{{ __('login.email') }}
</label>
任何帮助都会很好,非常感谢。
尝试:
<label for="email">
{{ __('login')['email'] }}
</label>
您可以通过更改默认的
__
帮助器来实现此方法:
use Illuminate\Support\Arr;
function __($key = null, $replace = [], $locale = null)
{
// Default behavior
if (is_null($key)) return $key;
if (trans()->has($key)) return trans($key, $replace, $locale);
// Search in .json file
$search = Arr::get(trans()->get('*'), $key);
if ($search !== null) return $search;
// Return .json fallback
$fallback = Arr::get(trans()->get('*', [], config('app.fallback_locale')), $key);
if ($fallback !== null) return $fallback;
// Return key name if not found
else return $key;
}
如果您不知道如何更改默认帮助程序,请创建一个具有任意名称的文件(例如:
bootstrap/helpers.php
),然后在文件中public/index.php
在“注册自动加载程序”之前添加此行
/*
|--------------------------------------------------------------------------
| Register Custom Helpers
|------------------------------------------------------------------------
*/
require __DIR__.'/../bootstrap/helpers.php';
如果您还想使用 Variables 功能,就像
__(welcome.user, ['user'=>'david'])
一样,您必须在该文件上创建一个新的帮助程序:
use Illuminate\Support\Str;
function trans_replacements($line, array $replace)
{
if (empty($replace)) return $line;
$shouldReplace = [];
foreach ($replace as $key => $value) {
$shouldReplace[':'.Str::ucfirst($key)] = Str::ucfirst($value);
$shouldReplace[':'.Str::upper($key)] = Str::upper($value);
$shouldReplace[':'.$key] = $value;
}
return strtr($line, $shouldReplace);
}
然后将
return $search
替换为 trans_replacements($search, $replace)
,将 return $fallback
替换为 trans_replacements($fallback, $replace)
对于 Countable 功能(例如:
'an apple|many apples'
),是相同的过程,只需添加此助手:
use Illuminate\Support\Facades\App;
function trans_choice($key, $number, array $replace = [], $locale = null)
{
// Get message
$message = __($key, $replace, $locale);
// If the given "number" is actually an array or countable we will simply count the
// number of elements in an instance.
if (is_array($number) || $number instanceof Countable)
$number = count($number);
$replace['count'] = $number;
return trans_replacements(
trans()->getSelector()->choose($message, $number, $locale = App::getLocale()),
$replace
);
}
这是文件,以防万一:bendeckdavid/laravel_locale_nested_json
Laravel 默认不支持这一点很烦人。 不过,你可以使用我做的这个功能:
function ___($path) {
$properties = explode(".", $path);
$base = __($properties[0]);
unset($properties[0]);
foreach($properties as $property) {
// Allows specification of indexes
if(is_numeric($property)) {
$property = intval($property);
}
// If the key has not been found, return the initial parameter like __()
try {
$base = $base[$property];
} catch (\Throwable $th) {
return $path;
}
}
return $base;
}
如果你像我一样在这里偶然发现想要使用如下的文件结构,而在使用 php 语言文件时不需要为每个字符串指定键。
-app
-lang
--fr
---Headers.json
对上面 David G 的答案稍作修改,
<?php
use Illuminate\Support\Arr;
function ___($path = null, $replace = [], $locale = null)
{
// Default behavior
if (is_null($path)) return $path;
if(!strrpos($path, '.')) {
return $path;
}
$properties = explode(".", $path);
$currentLocale = app()->getLocale();
// If the file/folder doesn't exist
// return the last part of the dot notation
$translated_string = substr($path, strrpos($path, '.') + 1);
if(is_dir(lang_path($currentLocale))) {
if (is_file(lang_path($currentLocale.'\\'.$properties[0].'.json'))) {
$contents = json_decode(file_get_contents(lang_path($currentLocale.'\\'.$properties[0].'.json')), true);
// If no value exists for the key, the key is itself returned
$translated_string = Arr::get($contents, $properties[1], $properties[1]);
}
}
return $translated_string;
}
到目前为止,这不适用于区域设置文件夹下的子目录下的文件。我确信,上面的代码可以优化,但这应该给你一个想法。
此外,此函数使用三重下划线
{{___()}}
而不是常规的双下划线 {{__()}}
以避免冲突。
适用于,
{{___('Messages.Welcome') }} // lang/(locale)/Messages.json
{{___('Welcome')}} // lang/(locale).json
您可以扩展
index.php
别名的 laravel 绑定,而不是编辑 artisan
和 translator
来需要自定义函数。
在
Translator
下创建app/Translation/Translator.php
类:
namespace App\Translation;
use Illuminate\Support\Arr;
use Illuminate\Translation\Translator as BaseTranslator;
class Translator extends BaseTranslator
{
/**
* @param $key
* @param array $replace
* @param $locale
* @param $fallback
*
* @return array|string|null
*/
public function get ($key, array $replace = [], $locale = null, $fallback = true)
{
$results = parent::get($key, $replace, $locale, $fallback);
// If key does not contain nested translation
// or result did not return key back then it's ok
if (!str_contains($key, '.') || $results !== $key) {
return $results;
}
$locale = $locale ?: $this->locale;
$line = Arr::get($this->loaded['*']['*'][$locale], $key);
return $this->makeReplacements($line ?: $key, $replace);
}
}
在
app/Services/AppServiceProvider.php
中绑定您的班级:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Translation\Translator;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
$this->app->extend('translator', function ($service, $app) {
return new Translator($service->getLoader(), $service->getLocale());
});
}
}
现在您可以在翻译中使用嵌套路径
<label for="email">
{{ __('login.email') }}
</label>
假设你的json存储在
$json
中,你想使用json_decode
将其解析为数组
$data = json_decode($json, TRUE);
您可以通过以下方式访问:
<label for="email">
{{ $data['login']['emailPlaceholder'] }}
</label>