【问题标题】:Disable translations for a given request (laravel)禁用给定请求的翻译(laravel)
【发布时间】:2019-12-01 15:28:59
【问题描述】:

我目前正在构建一个以 laravel 作为后端的 Vue.js SPA,我需要支持多个语言环境。因此,我正在考虑使用 Lang.js 和 laravel 的内置翻译系统来管理翻译的字符串。我基本上想管理 laravel 中的所有字符串(在后端),但让前端处理实际的翻译,以允许用户使用语言切换器 ui 组件动态切换语言。

问题是当我提交在服务器上验证的表单请求时,错误消息已经被翻译,因此不允许前端即时选择语言。

我的问题是如何禁用给定请求的翻译(最好使用中间件中的标头或类似的东西),而是打印原始翻译键

例如对于给定的验证

<?php
function store() {
    request()->validate(['test' => 'required'])
}

服务器返回

{
    'message': 'The given data was invalid',
    'errors': {
        'test': 'The test field is required'
    }
}

而不是

{
    'message': 'The given data was invalid',
    'errors': {
        'test': 'validation.required',
    }
}

我已经尝试过使用\App::setLocale('somethinginvalidandrandom'),从技术上讲,它应该尝试将密钥翻译成不存在的语言,从而返回密钥,但除了感觉错误和hacky之外,如果我想这种方法也行不通保留 laravel 的后备语言功能,因为密钥会在后备语言 (en) 中找到。

【问题讨论】:

    标签: javascript php laravel vue.js internationalization


    【解决方案1】:

    我个人觉得你的解决方案有点不合我的口味。

    我自己的方法是创建一个扩展原始Translator 的翻译器类。然后,我重写了方法get 并返回键和格式参数。 我需要的另一件事是获取TranslatorServiceProvider 的副本,因为Translator 已在其中实例化。新的提供者必须在config\app.php注册。

    App\Providers\ApiTranslatorServiceProvider

    <?php
    
    namespace App\Providers;
    
    use App\Common\ApiTranslator;
    use Illuminate\Translation\TranslationServiceProvider;
    
    class ApiTranslationServiceProvider extends TranslationServiceProvider
    {
        /**
         * Register services.
         *
         * @return void
         */
        public function register()
        {
            $this->registerLoader();
    
            $this->app->singleton('translator', function ($app) {
                $loader = $app['translation.loader'];
    
                // When registering the translator component, we'll need to set the default
                // locale as well as the fallback locale. So, we'll grab the application
                // configuration so we can easily get both of these values from there.
                $locale = $app['config']['app.locale'];
    
                $trans = new ApiTranslator($loader, $locale);
    
                $trans->setFallback($app['config']['app.fallback_locale']);
    
                return $trans;
            });
        }
    }
    

    App\Common\ApiTranslator

    <?php
    
    namespace App\Common;
    
    use Illuminate\Translation\Translator;
    
    class ApiTranslator extends Translator
    {
        /**
         * Get the translation for the given key.
         *
         * @param  string  $key
         * @param  array  $replace
         * @param  string|null  $locale
         * @param  bool  $fallback
         * @return string|array
         */
        public function get($key, array $replace = [], $locale = null, $fallback = true)
        {
            if (count($replace) > 0)
            {
                return ["key" => $key, "format" => $replace];
            }
            return $key;
        }
    }
    

    在某些情况下,Validator 会尝试编辑字符串消息,这就是根据情况返回字符串的原因。 因此,ajax 请求返回一个对象数组,每个对象都包含一个翻译键和值。

    【讨论】:

      【解决方案2】:

      其实是我自己解决的,想在这里回复一下,以防以后其他人也想解决和我一样的问题。

      解决方案

      我在App\Exceptions\Handler 类中添加了一个invalidJson 方法,只要抛出ValidationException 并且$request-&gt;wantsJson() 为真,Laravel 就会自动调用该方法。

      在该方法中,我只是检查了我的自定义标头 (X-WITH-UNTRANSLATED-VALIDATION) 是否存在于请求中,值为“yes”。 如果是这种情况,我会从异常中获取验证器实例,并获取所有规则。

      然而,laravel 在内部以“studly caps case”(StartsWith)表示这些规则,我们希望以蛇形案例格式(“starts_with”)获得它们。为了解决这个问题,我使用 laravel 集合助手映射嵌套数组并将规则键转换为蛇形大小写。

      代码

      这是来自app\Exceptions\Handler.php的代码。

      /**
       * Convert a validation exception into a JSON response.
       *
       * @param  \Illuminate\Http\Request  $request
       * @param  \Illuminate\Validation\ValidationException  $exception
       * @return \Illuminate\Http\Response
       */
      protected function invalidJson($request, ValidationException $exception)
      {
          //If the header is not present in the request 'no' wil be provided as the fallback value, thus not being equal with "yes"
          if($request->header('X-WITH-UNTRANSLATED-VALIDATION', 'no') === "yes") {
              $failed = $this->makeUntranslatedMessagesIntoSnakeCase($exception);
      
              return response([
                  // Get the original exception message
                  'message' => $exception->getMessage(),
                  'errors' => $failed,
                  // Add the original translated error messages under a diffrent key to help with debugging
                  'translated_errors' => $exception->errors(),
              ], $exception->status);
          }
      
          //If the header is not present (with the right value) we return the default JSON response instead
          return parent::invalidJson($request, $exception);
      }
      
      /**
       * Convert the untranslated rule names of a validation exception into snake case.
       * 
       * @param \Illuminate\Validation\ValidationException  $exception
       * @return array
       */
      protected function makeUntranslatedMessagesIntoSnakeCase(ValidationException $exception) : array
      {
          return collect($exception->validator->failed())->map(function ($item) {
              return collect($item)->mapWithKeys(function ($values, $rule) {
                  return [Str::snake($rule) => $values];
              });
          })->toArray();
      }
      

      进一步改进

      如果您需要为正常的“非 json”请求禁用翻译,您也可以覆盖 Handler.php 中的 invalid 方法并执行类似的操作,但只需将消息添加到会话中即可。同样,您也可以在未翻译的消息旁边添加已翻译的消息。

      编辑

      我还在回复中添加了'translated_errors' =&gt; $exception-&gt;errors(),以帮助调试

      【讨论】:

        【解决方案3】:

        也许不是您正在寻找的答案,但您可以在后端实现一个用于切换语言的端点。每当您在前端更改语言时,您都可以调用此端点。此外,它还允许您保存所选语言,因此如果用户退出 SPA 并稍后返回,则不会重置首选语言。

        【讨论】:

        • 我自己刚刚找到了一个解决方案,但无论如何感谢您的回答:D!这在服务器端呈现的应用程序中是一种有效的方法,因为页面会在语言更改时完全刷新,但是由于可以在发布错误消息后切换语言,因此会产生问题,因为错误消息仍然存在将使用第一语言。
        猜你喜欢
        • 2014-07-26
        • 1970-01-01
        • 2020-03-07
        • 1970-01-01
        • 2019-06-04
        • 1970-01-01
        • 2017-11-28
        • 1970-01-01
        • 2022-11-12
        相关资源
        最近更新 更多