i18next + React + Webpack - getFixedT не является функцией - PullRequest
0 голосов
/ 11 марта 2019

У меня проблемы с React, i18next и Webpack. Я перепробовал много решений, но ни одно из них не сработало. Когда я пытаюсь собрать свое приложение, оно успешно собирается. Но при попытке открыть консоль выдает ошибку. Мой webpack.config и трассировка стека ошибок приведены ниже.

webpack.prod.config.js

const webpack = require('webpack');
const path = require('path');
const htmlWebpackPlugin = require("html-webpack-plugin")
const miniCSSExtractPlugin = require("mini-css-extract-plugin")
const terserPlugin = require("terser-webpack-plugin")
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin")
const cleanWebpackPlugin = require("clean-webpack-plugin")

const i18nPlugin = require("i18n-webpack-plugin")
const options = require("../src/controllers/i18n").options
const locales = require("../src/controllers/i18n/locales")

options.backend.loadPath = "." + options.backend.loadPath

const config = {
    mode: "production",
    output: {
        path: path.resolve(__dirname, '../dist'),
        publicPath: "./",
        filename: 'bundle.js'
    },
    resolve: {
        extensions: [" ", ".js", ".jsx"],
        alias: {
            "@components": path.resolve(__dirname, "../src/components"),
            "@views": path.resolve(__dirname, "../src/views")
        }
    },
    optimization: {
        minimizer: [
            new terserPlugin({
                cache: true,
                parallel: true,
                include: /\.(js|jsx)$/
            }),
            new OptimizeCSSAssetsPlugin({})
        ]
    },
    module: {
        rules: [{
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: [{
                    loader: "babel-loader"
                }, {
                    loader: "i18next-loader"
                }]
            },
            {
                test: /\.css$/,
                use: [
                    miniCSSExtractPlugin.loader,
                    {
                        loader: "css-loader",
                    }
                ]
            }, {
                test: /\.(png|jpg|gif)$/,
                use: [{
                    loader: 'file-loader?name=images/[hash].[ext]',
                    options: {
                        name: "assets/images/[hash].[ext]"
                    }
                }]
            }, {
                test: /\.(ttf|woff(2)|eof|svg)$/,
                use: [{
                    loader: "file-loader",
                    options: {
                        name: "assets/fonts/[hash].[ext]",
                    }
                }]
            }
        ],
    },
    plugins: [
        new htmlWebpackPlugin({
            template: path.join(__dirname, "..", "public", "index.html")
        }),
        new miniCSSExtractPlugin({
            filename: "[name].css",
            chunkFilename: "[id].css"
        }),
        new cleanWebpackPlugin("../dist/*", {
            root: __dirname + "../",
            allowExternal: true
        }),
        new i18nPlugin(locales,{
            functionName: "t",
            nested: true
        },true)
    ]
};

module.exports = config;

npm run build работает нормально, без ошибок по поводу i18next. Затем, когда я открываю приложение, я получил эту ошибку:

bundle.js:33 TypeError: r.getFixedT is not a function
   at L (bundle.js:12)
    at bundle.js:12
    at Xo (bundle.js:33)
    at Ia (bundle.js:33)
    at qi (bundle.js:33)
    at $i (bundle.js:33)
    at jl (bundle.js:33)
    at Cl (bundle.js:33)
    at Pl (bundle.js:33)
    at Ji (bundle.js:33)

Надеюсь, кто-нибудь может мне помочь.

1 Ответ

1 голос
/ 27 марта 2019

Я нашел, в чем была моя проблема. В документации i18next говорится, что я должен запустить init внутри webpack.config.js.

Проблема

Моей первоначальной проблемой была загрузка локалей. I18n не смог найти файлы после сборки, потому что веб-пакет не распознает i18n-xhr-backend, требующий .json файлы. Тогда после сборки не было файлов перевода. Затем я попытался разрешить webpack разобраться с i18n, и у меня возникла другая проблема, в следующем абзаце.

В React требуется добавить экземпляр i18n в i18nextProvider. Но по дороге, которой я занимался, в React не было ни одного экземпляра для защиты. Тогда он не может найти функцию перевода и все остальное. Я также нашел i18nWebpackPlugin, но он также не решил мою проблему, потому что он также не дает доступа к экземпляру i18n внутри реакции. В итоге у меня возникли две нерешенные проблемы.

Решение

Мое решение было довольно простым. Я создал новую конфигурацию i18n для development env и позволил веб-пакету разобраться с .json, скопировав его в новую папку после сборки. Я приведу ниже мои файлы конфигурации для веб-пакета и i18n. Мои шаги, где:

  • Верните i18n.init() обратно i18n/index.js
  • Создание разных параметров для каждой среды
  • Настройка веб-пакета для копирования файлов перевода
  • Импорт экземпляра i18n на App.js снова

Теперь все работает как шарм.

OBS: Чтобы веб-пакет распознал файлы .json, его необходимо импортировать куда-нибудь. Я сделал внутри resources.js файла.

webpack.prod.config.js

const webpack = require("webpack");
const path = require("path");
const htmlWebpackPlugin = require("html-webpack-plugin");
const miniCSSExtractPlugin = require("mini-css-extract-plugin");
const terserPlugin = require("terser-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const cleanWebpackPlugin = require("clean-webpack-plugin");

const config = {
  mode: "production",
  output: {
    path: path.resolve(__dirname, "../dist"),
    publicPath: "./",
    filename: "bundle.js"
  },
  resolve: {
    extensions: [" ", ".js", ".jsx"],
    alias: {
      "@components": path.resolve(__dirname, "../src/components"),
      "@views": path.resolve(__dirname, "../src/views"),
      "@static": path.resolve(__dirname, "../src/static")
    }
  },
  optimization: {
    minimizer: [
      new terserPlugin({
        cache: true,
        parallel: true,
        include: /\.(js|jsx)$/
      }),
      new OptimizeCSSAssetsPlugin({})
    ]
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: [
          {
            loader: "babel-loader"
          }
        ]
      },
      {
        test: /\.css$/,
        use: [
          miniCSSExtractPlugin.loader,
          {
            loader: "css-loader"
          }
        ]
      },
      {
        test: /\.(png|jpg|gif|ico)$/,
        use: [
          {
            loader: "file-loader?name=images/[hash].[ext]",
            options: {
              name: "assets/images/[hash].[ext]"
            }
          }
        ]
      },
      {
        test: /\.(ttf|woff2?|eo(f|t)|svg)$/,
        use: [
          {
            loader: "file-loader",
            options: {
              name: "assets/fonts/[hash].[ext]"
            }
          }
        ]
      },
      {
        test: /\.(json)$/,
        type: "javascript/auto",
        use: [
          {
            loader: "file-loader",
            options: {
              name: "[folder]/[name].[ext]",
              outputPath: "assets/locales/"
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new htmlWebpackPlugin({
      template: path.join(__dirname, "..", "public", "index.html")
    }),
    new miniCSSExtractPlugin({
      filename: "[name].css",
      chunkFilename: "[id].css"
    }),
    new cleanWebpackPlugin("../dist/*", {
      root: __dirname + "../",
      allowExternal: true
    })
  ]
};
module.exports = config;

i18n / index.js

const i18n = require("i18next");
const initReactI18next = require("react-i18next").initReactI18next;
const langDetector = require("i18next-browser-languagedetector");
const backend = require("i18next-xhr-backend");
const moment = require("moment");

const resources = require("../../static/locales");

/*

Other codes...

*/

i18n.use(langDetector).use(initReactI18next);

var options;

switch (process.env.NODE_ENV) {
  case "test":
    options = {
      whitelist: ["en", "pt"],
      fallbackLng: "en",
      resources,
      ns: "translation",
      defaultNS: "translation",
      interpolation: {
        format: function(value, format, lng) {
          if (value instanceof Date) return moment(value).format(format);
          return value.toString();
        }
      }
    };
    break;
  case "production":
    i18n.use(backend);
    options = {
      whitelist: ["en-US", "pt-BR"],
      fallbackLng: {
        pt: ["pt-BR"],
        en: ["en-US"],
        default: ["en"]
      },
      ns: ["button", "common", "lng", "info"],
      defaultNS: "common",
      backend: {
        loadPath: "./assets/locales/{{lng}}/{{ns}}.json"
      },
      detection: {
        order: ["querystring", "cookie", "navigator", "localStorage"]
      },
      lookupQuerystring: "lng",
      caches: ["localStorage", "cookie"],
      react: {
        wait: true
      },
      interpolation: {
        format: function(value, format, lng) {
          if (format === "uppercase") return value.toUpperCase();
          if (value instanceof Date) return moment(value).format(format);
          return value;
        }
      }
    };
    break;
  case "development":
    i18n.use(backend);
    options = {
      whitelist: ["en-US", "pt-BR"],
      fallbackLng: {
        pt: ["pt-BR"],
        en: ["en-US"],
        default: ["en"]
      },
      ns: ["button", "common", "lng", "info"],
      defaultNS: "common",
      backend: {
        loadPath: "./src/static/locales/{{lng}}/{{ns}}.json"
      },
      detection: {
        order: ["querystring", "cookie", "navigator", "localStorage"]
      },
      lookupQuerystring: "lng",
      caches: ["localStorage", "cookie"],
      react: {
        wait: true
      },
      interpolation: {
        format: function(value, format, lng) {
          if (format === "uppercase") return value.toUpperCase();
          if (value instanceof Date) return moment(value).format(format);
          return value;
        }
      }
    };
    break;
}

i18n.init(options);

module.exports = i18n;
...