next-i18next 2.1.3 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -31,18 +31,21 @@ You need to also have `react` and `next` installed.
31
31
  By default, `next-i18next` expects your translations to be organised as such:
32
32
  ```
33
33
  .
34
- └── static
35
- └── locales
36
- ├── en
37
- | └── common.json
38
- └── de
39
- └── common.json
34
+ └── public
35
+ └── static
36
+ └── locales
37
+ ├── en
38
+ | └── common.json
39
+ └── de
40
+ └── common.json
40
41
  ```
41
42
 
42
43
  This structure can also be seen in the [simple example](./examples/simple).
43
44
 
44
45
  If you want to structure your translations/namespaces in a custom way, you will need to pass modified `localePath` and `localeStructure` values into the initialisation config.
45
46
 
47
+ If translations are not found in `config.localePath` or `public/static/locales` an attempt will be made to find the locales in `static/locales`, if found a deprecation warning will be logged.
48
+
46
49
  ### 3. Project setup
47
50
 
48
51
  The default export of `next-i18next` is a class constructor, into which you pass your config options. The resulting class has all the methods you will need to translate your app:
@@ -236,10 +239,10 @@ MyPage.getInitialProps = async({ req }) => {
236
239
  | `browserLanguageDetection` | `true` |
237
240
  | `defaultNS` | `'common'` |
238
241
  | `defaultLanguage` | `'en'` |
239
- | `ignoreRoutes` | `['/_next/', '/static/']` |
242
+ | `ignoreRoutes` | `['/_next/', '/static/', '/public/', '/api/']` |
240
243
  | `otherLanguages` (required) | `[]` |
241
244
  | `localeExtension` | `'json'` |
242
- | `localePath` | `'static/locales'` |
245
+ | `localePath` | `'public/static/locales'` |
243
246
  | `localeStructure` | `'{{lng}}/{{ns}}'` |
244
247
  | `localeSubpaths` | `{}` |
245
248
  | `serverLanguageDetection` | `true` |
@@ -263,7 +266,7 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds
263
266
 
264
267
  <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
265
268
  <!-- prettier-ignore -->
266
- <table cellspacing="0" cellpadding="1"><tr><td><a href="https://github.com/capellini"><img src="https://avatars3.githubusercontent.com/u/75311?v=4" width="100px;" height="100px;" alt="Rob Capellini"/><br /><sub><b>Rob Capellini</b></sub></a><br /><a href="https://github.com/isaachinman/next-i18next/commits?author=capellini" title="Code">💻</a> <a href="https://github.com/isaachinman/next-i18next/commits?author=capellini" title="Tests">⚠️</a></td><td><a href="https://en.kachkaev.ru"><img src="https://avatars3.githubusercontent.com/u/608862?v=4" width="100px;" height="100px;" alt="Alexander Kachkaev"/><br /><sub><b>Alexander Kachkaev</b></sub></a><br /><a href="#talk-kachkaev" title="Talks">📢</a> <a href="#question-kachkaev" title="Answering Questions">💬</a> <a href="#ideas-kachkaev" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/isaachinman/next-i18next/commits?author=kachkaev" title="Code">💻</a> <a href="https://github.com/isaachinman/next-i18next/commits?author=kachkaev" title="Tests">⚠️</a></td><td><a href="https://kandelborg.dk"><img src="https://avatars1.githubusercontent.com/u/33042011?v=4" width="100px;" height="100px;" alt="Mathias Wøbbe"/><br /><sub><b>Mathias Wøbbe</b></sub></a><br /><a href="https://github.com/isaachinman/next-i18next/commits?author=MathiasKandelborg" title="Code">💻</a> <a href="#ideas-MathiasKandelborg" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/isaachinman/next-i18next/commits?author=MathiasKandelborg" title="Tests">⚠️</a></td><td><a href="http://lucasfeliciano.com"><img src="https://avatars3.githubusercontent.com/u/968014?v=4" width="100px;" height="100px;" alt="Lucas Feliciano"/><br /><sub><b>Lucas Feliciano</b></sub></a><br /><a href="#ideas-lucasfeliciano" title="Ideas, Planning, & Feedback">🤔</a> <a href="#review-lucasfeliciano" title="Reviewed Pull Requests">👀</a></td><td><a href="http://www.fifteenprospects.com"><img src="https://avatars2.githubusercontent.com/u/6932550?v=4" width="100px;" height="100px;" alt="Ryan Leung"/><br /><sub><b>Ryan Leung</b></sub></a><br /><a href="https://github.com/isaachinman/next-i18next/commits?author=minocys" title="Code">💻</a></td></tr></table>
269
+ <table cellspacing="0" cellpadding="1"><tr><td><a href="https://github.com/capellini"><img src="https://avatars3.githubusercontent.com/u/75311?v=4" width="100px;" height="100px;" alt="Rob Capellini"/><br /><sub><b>Rob Capellini</b></sub></a><br /><a href="https://github.com/isaachinman/next-i18next/commits?author=capellini" title="Code">💻</a> <a href="https://github.com/isaachinman/next-i18next/commits?author=capellini" title="Tests">⚠️</a></td><td><a href="https://en.kachkaev.ru"><img src="https://avatars3.githubusercontent.com/u/608862?v=4" width="100px;" height="100px;" alt="Alexander Kachkaev"/><br /><sub><b>Alexander Kachkaev</b></sub></a><br /><a href="#talk-kachkaev" title="Talks">📢</a> <a href="#question-kachkaev" title="Answering Questions">💬</a> <a href="#ideas-kachkaev" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/isaachinman/next-i18next/commits?author=kachkaev" title="Code">💻</a> <a href="https://github.com/isaachinman/next-i18next/commits?author=kachkaev" title="Tests">⚠️</a></td><td><a href="https://kandelborg.dk"><img src="https://avatars1.githubusercontent.com/u/33042011?v=4" width="100px;" height="100px;" alt="Mathias Wøbbe"/><br /><sub><b>Mathias Wøbbe</b></sub></a><br /><a href="https://github.com/isaachinman/next-i18next/commits?author=MathiasKandelborg" title="Code">💻</a> <a href="#ideas-MathiasKandelborg" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/isaachinman/next-i18next/commits?author=MathiasKandelborg" title="Tests">⚠️</a></td><td><a href="http://lucasfeliciano.com"><img src="https://avatars3.githubusercontent.com/u/968014?v=4" width="100px;" height="100px;" alt="Lucas Feliciano"/><br /><sub><b>Lucas Feliciano</b></sub></a><br /><a href="#ideas-lucasfeliciano" title="Ideas, Planning, & Feedback">🤔</a> <a href="#review-lucasfeliciano" title="Reviewed Pull Requests">👀</a></td><td><a href="http://www.fifteenprospects.com"><img src="https://avatars2.githubusercontent.com/u/6932550?v=4" width="100px;" height="100px;" alt="Ryan Leung"/><br /><sub><b>Ryan Leung</b></sub></a><br /><a href="https://github.com/isaachinman/next-i18next/commits?author=minocys" title="Code">💻</a></td><td><a href="http://nathanfriemel.com"><img src="https://avatars3.githubusercontent.com/u/1325835?v=4" width="100px;" height="100px;" alt="Nathan Friemel"/><br /><sub><b>Nathan Friemel</b></sub></a><br /><a href="https://github.com/isaachinman/next-i18next/commits?author=nathanfriemel" title="Code">💻</a> <a href="https://github.com/isaachinman/next-i18next/commits?author=nathanfriemel" title="Documentation">📖</a> <a href="#example-nathanfriemel" title="Examples">💡</a> <a href="#ideas-nathanfriemel" title="Ideas, Planning, & Feedback">🤔</a></td></tr></table>
267
270
  <!-- ALL-CONTRIBUTORS-LIST:END -->
268
271
 
269
272
  This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
@@ -11,6 +11,8 @@ exports.createConfig = void 0;
11
11
 
12
12
  require("core-js/modules/es6.array.for-each");
13
13
 
14
+ require("core-js/modules/es6.string.starts-with");
15
+
14
16
  require("core-js/modules/es6.regexp.replace");
15
17
 
16
18
  require("core-js/modules/es6.array.map");
@@ -23,7 +25,7 @@ require("core-js/modules/es6.array.filter");
23
25
 
24
26
  var _defaultConfig = require("./default-config");
25
27
 
26
- var _isServer = require("../utils/is-server");
28
+ var _utils = require("../utils");
27
29
 
28
30
  var deepMergeObjects = ['backend', 'detection'];
29
31
 
@@ -33,13 +35,21 @@ var dedupe = function dedupe(names) {
33
35
  });
34
36
  };
35
37
 
38
+ var STATIC_LOCALE_PATH = 'static/locales';
39
+
36
40
  var createConfig = function createConfig(userConfig) {
37
41
  if (typeof userConfig.localeSubpaths === 'string') {
38
42
  throw new Error('The localeSubpaths option has been changed to an object. Please refer to documentation.');
39
- } // Initial merge of default and user-provided config
43
+ }
44
+ /*
45
+ Initial merge of default and user-provided config
46
+ */
40
47
 
41
48
 
42
- var combinedConfig = (0, _objectSpread2["default"])({}, _defaultConfig.defaultConfig, userConfig); // Sensible defaults to prevent user duplication
49
+ var combinedConfig = (0, _objectSpread2["default"])({}, _defaultConfig.defaultConfig, userConfig);
50
+ /*
51
+ Sensible defaults to prevent user duplication
52
+ */
43
53
 
44
54
  combinedConfig.allLanguages = dedupe(combinedConfig.otherLanguages.concat([combinedConfig.defaultLanguage]));
45
55
  combinedConfig.whitelist = combinedConfig.allLanguages;
@@ -49,26 +59,49 @@ var createConfig = function createConfig(userConfig) {
49
59
  localePath = combinedConfig.localePath,
50
60
  localeStructure = combinedConfig.localeStructure;
51
61
 
52
- if ((0, _isServer.isServer)()) {
62
+ if ((0, _utils.isServer)()) {
53
63
  var fs = eval("require('fs')");
54
64
 
55
- var path = require('path'); // Validate defaultNS
56
- // https://github.com/isaachinman/next-i18next/issues/358
65
+ var path = require('path');
57
66
 
67
+ var serverLocalePath = localePath;
68
+ /*
69
+ Validate defaultNS
70
+ https://github.com/isaachinman/next-i18next/issues/358
71
+ */
58
72
 
59
- if (process.env.NODE_ENV !== 'production' && typeof combinedConfig.defaultNS === 'string') {
60
- var defaultNSPath = path.join(process.cwd(), "".concat(localePath, "/").concat(defaultLanguage, "/").concat(combinedConfig.defaultNS, ".").concat(localeExtension));
73
+ if (typeof combinedConfig.defaultNS === 'string') {
74
+ var defaultFile = "/".concat(defaultLanguage, "/").concat(combinedConfig.defaultNS, ".").concat(localeExtension);
75
+ var defaultNSPath = path.join(process.cwd(), localePath, defaultFile);
61
76
  var defaultNSExists = fs.existsSync(defaultNSPath);
62
77
 
63
78
  if (!defaultNSExists) {
64
- throw new Error("Default namespace not found at ".concat(defaultNSPath));
79
+ /*
80
+ If defaultNS doesn't exist, try to fall back to the deprecated static folder
81
+ https://github.com/isaachinman/next-i18next/issues/523
82
+ */
83
+ var staticDirPath = path.join(process.cwd(), STATIC_LOCALE_PATH, defaultFile);
84
+ var staticDirExists = fs.existsSync(staticDirPath);
85
+
86
+ if (staticDirExists) {
87
+ (0, _utils.consoleMessage)('warn', 'next-i18next: Falling back to /static folder, deprecated in next@9.1.*', combinedConfig);
88
+ serverLocalePath = STATIC_LOCALE_PATH;
89
+ } else if (process.env.NODE_ENV !== 'production') {
90
+ throw new Error("Default namespace not found at ".concat(defaultNSPath));
91
+ }
65
92
  }
66
- } // Set server side backend
93
+ }
94
+ /*
95
+ Set server side backend
96
+ */
67
97
 
68
98
 
69
99
  combinedConfig.backend = {
70
- loadPath: path.join(process.cwd(), "".concat(localePath, "/").concat(localeStructure, ".").concat(localeExtension)),
71
- addPath: path.join(process.cwd(), "".concat(localePath, "/").concat(localeStructure, ".missing.").concat(localeExtension)) // Set server side preload (languages and namespaces)
100
+ loadPath: path.join(process.cwd(), "".concat(serverLocalePath, "/").concat(localeStructure, ".").concat(localeExtension)),
101
+ addPath: path.join(process.cwd(), "".concat(serverLocalePath, "/").concat(localeStructure, ".missing.").concat(localeExtension))
102
+ /*
103
+ Set server side preload (languages and namespaces)
104
+ */
72
105
 
73
106
  };
74
107
  combinedConfig.preload = allLanguages;
@@ -80,21 +113,39 @@ var createConfig = function createConfig(userConfig) {
80
113
  });
81
114
  };
82
115
 
83
- combinedConfig.ns = getAllNamespaces(path.join(process.cwd(), "".concat(localePath, "/").concat(defaultLanguage)));
116
+ combinedConfig.ns = getAllNamespaces(path.join(process.cwd(), "".concat(serverLocalePath, "/").concat(defaultLanguage)));
84
117
  }
85
118
  } else {
86
- // Set client side backend
119
+ var clientLocalePath = localePath;
120
+ /*
121
+ Remove public prefix from client site config
122
+ */
123
+
124
+ if (localePath.startsWith('public/')) {
125
+ clientLocalePath = localePath.replace(/^public\//, '');
126
+ }
127
+ /*
128
+ Set client side backend
129
+ */
130
+
131
+
87
132
  combinedConfig.backend = {
88
- loadPath: "/".concat(localePath, "/").concat(localeStructure, ".").concat(localeExtension),
89
- addPath: "/".concat(localePath, "/").concat(localeStructure, ".missing.").concat(localeExtension)
133
+ loadPath: "/".concat(clientLocalePath, "/").concat(localeStructure, ".").concat(localeExtension),
134
+ addPath: "/".concat(clientLocalePath, "/").concat(localeStructure, ".missing.").concat(localeExtension)
90
135
  };
91
136
  combinedConfig.ns = [combinedConfig.defaultNS];
92
- } // Set fallback language to defaultLanguage in production
137
+ }
138
+ /*
139
+ Set fallback language to defaultLanguage in production
140
+ */
93
141
 
94
142
 
95
143
  if (!userConfig.fallbackLng) {
96
144
  combinedConfig.fallbackLng = process.env.NODE_ENV === 'production' ? combinedConfig.defaultLanguage : false;
97
- } // Deep merge with overwrite - goes last
145
+ }
146
+ /*
147
+ Deep merge with overwrite - goes last
148
+ */
98
149
 
99
150
 
100
151
  deepMergeObjects.forEach(function (obj) {
@@ -12,7 +12,7 @@ var _utils = require("../utils");
12
12
  var DEFAULT_LANGUAGE = 'en';
13
13
  var OTHER_LANGUAGES = [];
14
14
  var DEFAULT_NAMESPACE = 'common';
15
- var LOCALE_PATH = 'static/locales';
15
+ var LOCALE_PATH = 'public/static/locales';
16
16
  var LOCALE_STRUCTURE = '{{lng}}/{{ns}}';
17
17
  var LOCALE_EXTENSION = 'json';
18
18
  var defaultConfig = {
@@ -34,7 +34,7 @@ var defaultConfig = {
34
34
  },
35
35
  browserLanguageDetection: true,
36
36
  serverLanguageDetection: true,
37
- ignoreRoutes: ['/_next/', '/static/'],
37
+ ignoreRoutes: ['/_next/', '/static/', '/public/', '/api/'],
38
38
  customDetectors: [],
39
39
  detection: {
40
40
  lookupCookie: 'next-i18next',
@@ -20,6 +20,8 @@ var _i18nextXhrBackend = _interopRequireDefault(require("i18next-xhr-backend"));
20
20
  var _i18nextBrowserLanguagedetector = _interopRequireDefault(require("i18next-browser-languagedetector"));
21
21
 
22
22
  var _default = function _default(config) {
23
+ var initPromise;
24
+
23
25
  if (!_i18next["default"].isInitialized) {
24
26
  if (_detectNode["default"]) {
25
27
  var i18nextNodeBackend = eval("require('i18next-node-fs-backend')");
@@ -51,11 +53,13 @@ var _default = function _default(config) {
51
53
  config.use.forEach(function (x) {
52
54
  return _i18next["default"].use(x);
53
55
  });
54
-
55
- _i18next["default"].init(config);
56
+ initPromise = _i18next["default"].init(config);
56
57
  }
57
58
 
58
- return _i18next["default"];
59
+ return {
60
+ i18n: _i18next["default"],
61
+ initPromise: initPromise
62
+ };
59
63
  };
60
64
 
61
65
  exports["default"] = _default;
@@ -43,6 +43,7 @@ var NextI18Next = function NextI18Next(userConfig) {
43
43
  (0, _defineProperty2["default"])(this, "Link", void 0);
44
44
  (0, _defineProperty2["default"])(this, "Router", void 0);
45
45
  (0, _defineProperty2["default"])(this, "i18n", void 0);
46
+ (0, _defineProperty2["default"])(this, "initPromise", void 0);
46
47
  (0, _defineProperty2["default"])(this, "config", void 0);
47
48
  (0, _defineProperty2["default"])(this, "useTranslation", void 0);
48
49
  (0, _defineProperty2["default"])(this, "withTranslation", void 0);
@@ -61,7 +62,12 @@ var NextI18Next = function NextI18Next(userConfig) {
61
62
  throw new Error('next-i18next has upgraded to react-i18next v10 - please rename withNamespaces to withTranslation.');
62
63
  };
63
64
 
64
- this.i18n = (0, _createI18nextClient["default"])(this.config);
65
+ var _createI18NextClient = (0, _createI18nextClient["default"])(this.config),
66
+ i18n = _createI18NextClient.i18n,
67
+ initPromise = _createI18NextClient.initPromise;
68
+
69
+ this.i18n = i18n;
70
+ this.initPromise = initPromise;
65
71
  this.appWithTranslation = _hocs.appWithTranslation.bind(this);
66
72
 
67
73
  this.withTranslation = function (namespace, options) {
@@ -44,9 +44,9 @@ var logMessage = function logMessage(messageType, message) {
44
44
  };
45
45
 
46
46
  var consoleMessage = function consoleMessage(messageType, message) {
47
- var _this$config = this.config,
48
- errorStackTraceLimit = _this$config.errorStackTraceLimit,
49
- strictMode = _this$config.strictMode;
47
+ var config = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.config;
48
+ var errorStackTraceLimit = config.errorStackTraceLimit,
49
+ strictMode = config.strictMode;
50
50
  var prevStackLimit = Error.stackTraceLimit;
51
51
  var util;
52
52
 
@@ -19,7 +19,7 @@ var subpathIsPresent = function subpathIsPresent(url, subpath) {
19
19
  var _parseUrl = (0, _url.parse)(url),
20
20
  pathname = _parseUrl.pathname;
21
21
 
22
- return pathname.length === subpath.length + 1 && pathname === "/".concat(subpath) || pathname.startsWith("/".concat(subpath, "/"));
22
+ return typeof pathname === 'string' && (pathname.length === subpath.length + 1 && pathname === "/".concat(subpath) || pathname.startsWith("/".concat(subpath, "/")));
23
23
  };
24
24
 
25
25
  exports.subpathIsPresent = subpathIsPresent;
@@ -1,18 +1,25 @@
1
1
  import { defaultConfig } from './default-config';
2
- import { isServer } from '../utils/is-server';
2
+ import { consoleMessage, isServer } from '../utils';
3
3
  const deepMergeObjects = ['backend', 'detection'];
4
4
 
5
5
  const dedupe = names => names.filter((v, i) => names.indexOf(v) === i);
6
6
 
7
+ const STATIC_LOCALE_PATH = 'static/locales';
7
8
  export const createConfig = userConfig => {
8
9
  if (typeof userConfig.localeSubpaths === 'string') {
9
10
  throw new Error('The localeSubpaths option has been changed to an object. Please refer to documentation.');
10
- } // Initial merge of default and user-provided config
11
+ }
12
+ /*
13
+ Initial merge of default and user-provided config
14
+ */
11
15
 
12
16
 
13
17
  const combinedConfig = { ...defaultConfig,
14
18
  ...userConfig
15
- }; // Sensible defaults to prevent user duplication
19
+ };
20
+ /*
21
+ Sensible defaults to prevent user duplication
22
+ */
16
23
 
17
24
  combinedConfig.allLanguages = dedupe(combinedConfig.otherLanguages.concat([combinedConfig.defaultLanguage]));
18
25
  combinedConfig.whitelist = combinedConfig.allLanguages;
@@ -27,23 +34,46 @@ export const createConfig = userConfig => {
27
34
  if (isServer()) {
28
35
  const fs = eval("require('fs')");
29
36
 
30
- const path = require('path'); // Validate defaultNS
31
- // https://github.com/isaachinman/next-i18next/issues/358
37
+ const path = require('path');
32
38
 
39
+ let serverLocalePath = localePath;
40
+ /*
41
+ Validate defaultNS
42
+ https://github.com/isaachinman/next-i18next/issues/358
43
+ */
33
44
 
34
- if (process.env.NODE_ENV !== 'production' && typeof combinedConfig.defaultNS === 'string') {
35
- const defaultNSPath = path.join(process.cwd(), `${localePath}/${defaultLanguage}/${combinedConfig.defaultNS}.${localeExtension}`);
45
+ if (typeof combinedConfig.defaultNS === 'string') {
46
+ const defaultFile = `/${defaultLanguage}/${combinedConfig.defaultNS}.${localeExtension}`;
47
+ const defaultNSPath = path.join(process.cwd(), localePath, defaultFile);
36
48
  const defaultNSExists = fs.existsSync(defaultNSPath);
37
49
 
38
50
  if (!defaultNSExists) {
39
- throw new Error(`Default namespace not found at ${defaultNSPath}`);
51
+ /*
52
+ If defaultNS doesn't exist, try to fall back to the deprecated static folder
53
+ https://github.com/isaachinman/next-i18next/issues/523
54
+ */
55
+ const staticDirPath = path.join(process.cwd(), STATIC_LOCALE_PATH, defaultFile);
56
+ const staticDirExists = fs.existsSync(staticDirPath);
57
+
58
+ if (staticDirExists) {
59
+ consoleMessage('warn', 'next-i18next: Falling back to /static folder, deprecated in next@9.1.*', combinedConfig);
60
+ serverLocalePath = STATIC_LOCALE_PATH;
61
+ } else if (process.env.NODE_ENV !== 'production') {
62
+ throw new Error(`Default namespace not found at ${defaultNSPath}`);
63
+ }
40
64
  }
41
- } // Set server side backend
65
+ }
66
+ /*
67
+ Set server side backend
68
+ */
42
69
 
43
70
 
44
71
  combinedConfig.backend = {
45
- loadPath: path.join(process.cwd(), `${localePath}/${localeStructure}.${localeExtension}`),
46
- addPath: path.join(process.cwd(), `${localePath}/${localeStructure}.missing.${localeExtension}`) // Set server side preload (languages and namespaces)
72
+ loadPath: path.join(process.cwd(), `${serverLocalePath}/${localeStructure}.${localeExtension}`),
73
+ addPath: path.join(process.cwd(), `${serverLocalePath}/${localeStructure}.missing.${localeExtension}`)
74
+ /*
75
+ Set server side preload (languages and namespaces)
76
+ */
47
77
 
48
78
  };
49
79
  combinedConfig.preload = allLanguages;
@@ -51,21 +81,39 @@ export const createConfig = userConfig => {
51
81
  if (!combinedConfig.ns) {
52
82
  const getAllNamespaces = p => fs.readdirSync(p).map(file => file.replace(`.${localeExtension}`, ''));
53
83
 
54
- combinedConfig.ns = getAllNamespaces(path.join(process.cwd(), `${localePath}/${defaultLanguage}`));
84
+ combinedConfig.ns = getAllNamespaces(path.join(process.cwd(), `${serverLocalePath}/${defaultLanguage}`));
55
85
  }
56
86
  } else {
57
- // Set client side backend
87
+ let clientLocalePath = localePath;
88
+ /*
89
+ Remove public prefix from client site config
90
+ */
91
+
92
+ if (localePath.startsWith('public/')) {
93
+ clientLocalePath = localePath.replace(/^public\//, '');
94
+ }
95
+ /*
96
+ Set client side backend
97
+ */
98
+
99
+
58
100
  combinedConfig.backend = {
59
- loadPath: `/${localePath}/${localeStructure}.${localeExtension}`,
60
- addPath: `/${localePath}/${localeStructure}.missing.${localeExtension}`
101
+ loadPath: `/${clientLocalePath}/${localeStructure}.${localeExtension}`,
102
+ addPath: `/${clientLocalePath}/${localeStructure}.missing.${localeExtension}`
61
103
  };
62
104
  combinedConfig.ns = [combinedConfig.defaultNS];
63
- } // Set fallback language to defaultLanguage in production
105
+ }
106
+ /*
107
+ Set fallback language to defaultLanguage in production
108
+ */
64
109
 
65
110
 
66
111
  if (!userConfig.fallbackLng) {
67
112
  combinedConfig.fallbackLng = process.env.NODE_ENV === 'production' ? combinedConfig.defaultLanguage : false;
68
- } // Deep merge with overwrite - goes last
113
+ }
114
+ /*
115
+ Deep merge with overwrite - goes last
116
+ */
69
117
 
70
118
 
71
119
  deepMergeObjects.forEach(obj => {
@@ -2,7 +2,7 @@ import { isServer } from '../utils';
2
2
  const DEFAULT_LANGUAGE = 'en';
3
3
  const OTHER_LANGUAGES = [];
4
4
  const DEFAULT_NAMESPACE = 'common';
5
- const LOCALE_PATH = 'static/locales';
5
+ const LOCALE_PATH = 'public/static/locales';
6
6
  const LOCALE_STRUCTURE = '{{lng}}/{{ns}}';
7
7
  const LOCALE_EXTENSION = 'json';
8
8
  export const defaultConfig = {
@@ -22,7 +22,7 @@ export const defaultConfig = {
22
22
  },
23
23
  browserLanguageDetection: true,
24
24
  serverLanguageDetection: true,
25
- ignoreRoutes: ['/_next/', '/static/'],
25
+ ignoreRoutes: ['/_next/', '/static/', '/public/', '/api/'],
26
26
  customDetectors: [],
27
27
  detection: {
28
28
  lookupCookie: 'next-i18next',
@@ -3,6 +3,8 @@ import i18n from 'i18next';
3
3
  import i18nextXHRBackend from 'i18next-xhr-backend';
4
4
  import I18nextBrowserLanguageDetector from 'i18next-browser-languagedetector';
5
5
  export default (config => {
6
+ let initPromise;
7
+
6
8
  if (!i18n.isInitialized) {
7
9
  if (isNode) {
8
10
  const i18nextNodeBackend = eval("require('i18next-node-fs-backend')");
@@ -25,8 +27,11 @@ export default (config => {
25
27
  }
26
28
 
27
29
  config.use.forEach(x => i18n.use(x));
28
- i18n.init(config);
30
+ initPromise = i18n.init(config);
29
31
  }
30
32
 
31
- return i18n;
33
+ return {
34
+ i18n,
35
+ initPromise
36
+ };
32
37
  });
package/dist/es/index.js CHANGED
@@ -21,7 +21,12 @@ export default class NextI18Next {
21
21
  throw new Error('next-i18next has upgraded to react-i18next v10 - please rename withNamespaces to withTranslation.');
22
22
  };
23
23
 
24
- this.i18n = createI18NextClient(this.config);
24
+ const {
25
+ i18n,
26
+ initPromise
27
+ } = createI18NextClient(this.config);
28
+ this.i18n = i18n;
29
+ this.initPromise = initPromise;
25
30
  this.appWithTranslation = appWithTranslation.bind(this);
26
31
 
27
32
  this.withTranslation = (namespace, options) => Component => hoistNonReactStatics(withTranslation(namespace, options)(Component), Component);
@@ -14,11 +14,11 @@ const logMessage = (messageType, message) => {
14
14
  }
15
15
  };
16
16
 
17
- export const consoleMessage = function (messageType, message) {
17
+ export const consoleMessage = function (messageType, message, config = this.config) {
18
18
  const {
19
19
  errorStackTraceLimit,
20
20
  strictMode
21
- } = this.config;
21
+ } = config;
22
22
  const prevStackLimit = Error.stackTraceLimit;
23
23
  let util;
24
24
 
@@ -7,5 +7,5 @@ export const subpathIsPresent = (url, subpath) => {
7
7
  const {
8
8
  pathname
9
9
  } = parseUrl(url);
10
- return pathname.length === subpath.length + 1 && pathname === `/${subpath}` || pathname.startsWith(`/${subpath}/`);
10
+ return typeof pathname === 'string' && (pathname.length === subpath.length + 1 && pathname === `/${subpath}` || pathname.startsWith(`/${subpath}/`));
11
11
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-i18next",
3
- "version": "2.1.3",
3
+ "version": "4.1.0",
4
4
  "repository": "git@github.com:isaachinman/next-i18next.git",
5
5
  "author": "Isaac Hinman <isaac@isaachinman.com>",
6
6
  "funding": {
@@ -95,15 +95,15 @@
95
95
  "jsdom-global": "^3.0.2",
96
96
  "next": "^9.0.1",
97
97
  "puppeteer": "^1.11.0",
98
- "react": "^16.8.6",
99
- "react-dom": "^16.8.6",
98
+ "react": "^16.12.0",
99
+ "react-dom": "^16.12.0",
100
100
  "typescript": "^3.5.3"
101
101
  },
102
102
  "dependencies": {
103
103
  "core-js": "^2",
104
104
  "detect-node": "^2.0.4",
105
105
  "hoist-non-react-statics": "^3.2.0",
106
- "i18next": "^18.0.1",
106
+ "i18next": "^19.0.3",
107
107
  "i18next-browser-languagedetector": "^4.0.0",
108
108
  "i18next-express-middleware": "^1.5.0",
109
109
  "i18next-node-fs-backend": "^2.1.0",
@@ -113,10 +113,6 @@
113
113
  "react-i18next": "^11.0.0",
114
114
  "url": "^0.11.0"
115
115
  },
116
- "resolutions": {
117
- "**/react": "^16.8.6",
118
- "**/react-dom": "^16.8.6"
119
- },
120
116
  "peerDependencies": {
121
117
  "next": ">= 7.0.0",
122
118
  "react": ">= 16.8.0"
package/types.d.ts CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  } from 'react-i18next'
10
10
  import { LinkProps } from 'next/link'
11
11
  import { SingletonRouter } from 'next/router'
12
- import i18next from 'i18next'
12
+ import { InitOptions, i18n, TFunction as I18NextTFunction } from 'i18next'
13
13
 
14
14
  export type InitConfig = {
15
15
  browserLanguageDetection?: boolean;
@@ -23,7 +23,7 @@ export type InitConfig = {
23
23
  localeSubpaths?: Record<string, string>;
24
24
  use?: any[];
25
25
  customDetectors?: any[];
26
- } & i18next.InitOptions
26
+ } & InitOptions
27
27
 
28
28
  export type Config = {
29
29
  fallbackLng: boolean;
@@ -42,10 +42,11 @@ export type Link = React.ComponentClass<LinkProps>
42
42
  export type Router = SingletonRouter
43
43
  export type UseTranslation = typeof useTranslation
44
44
  export type AppWithTranslation = <P extends object>(Component: React.ComponentType<P> | React.ElementType<P>) => any
45
- export type TFunction = i18next.TFunction
46
- export type I18n = i18next.i18n
45
+ export type TFunction = I18NextTFunction
46
+ export type I18n = i18n
47
47
  export type WithTranslationHocType = typeof withTranslation
48
48
  export type WithTranslation = ReactI18nextWithTranslation
49
+ export type InitPromise = Promise<TFunction>
49
50
 
50
51
  declare class NextI18Next {
51
52
  constructor(config: InitConfig);
@@ -53,6 +54,7 @@ declare class NextI18Next {
53
54
  Link: Link
54
55
  Router: Router
55
56
  i18n: I18n
57
+ initPromise: InitPromise
56
58
  config: Config
57
59
  useTranslation: UseTranslation
58
60
  withTranslation: WithTranslationHocType