Laravel 本地化嵌套 JSON 语言文件

问题描述 投票:0回答:6

我正在尝试使我的项目支持多种语言。

我想使用 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>

任何帮助都会很好,非常感谢。

php json laravel localization
6个回答
11
投票

尝试:

<label for="email">
    {{ __('login')['email'] }}
</label>

3
投票

您可以通过更改默认的

__
帮助器来实现此方法:

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


0
投票

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;
}

0
投票

如果你像我一样在这里偶然发现想要使用如下的文件结构,而在使用 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

0
投票

扩展laravel核心绑定

您可以扩展

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>

-3
投票

假设你的json存储在

$json
中,你想使用
json_decode

将其解析为数组
$data = json_decode($json, TRUE);

您可以通过以下方式访问:

<label for="email">
    {{ $data['login']['emailPlaceholder'] }}
</label>
© www.soinside.com 2019 - 2024. All rights reserved.