next-i18next 10.3.0 → 10.4.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
@@ -223,16 +223,18 @@ This option will reload your translations whenever `serverSideTranslations` is c
223
223
 
224
224
  #### Options
225
225
 
226
- | Key | Default value |
227
- | ------------------- | -------------------- |
228
- | `defaultNS` | `'common'` |
229
- | `localeExtension` | `'json'` |
230
- | `localePath` | `'./public/locales'` |
231
- | `localeStructure` | `'{{lng}}/{{ns}}'` |
232
- | `reloadOnPrerender` | `false` |
233
- | `serializeConfig` | `true` |
234
- | `strictMode` | `true` |
235
- | `use` (for plugins) | `[]` |
226
+ | Key | Default value | Note |
227
+ | ------------------- | -------------------- | -------------------------------------- |
228
+ | `defaultNS` | `'common'` | |
229
+ | `localePath` | `'./public/locales'` | Can be a function, see note below. |
230
+ | `localeExtension` | `'json'` | Ignored if `localePath` is a function. |
231
+ | `localeStructure` | `'{{lng}}/{{ns}}'` | Ignored if `localePath` is a function. |
232
+ | `reloadOnPrerender` | `false` | |
233
+ | `serializeConfig` | `true` | |
234
+ | `strictMode` | `true` | |
235
+ | `use` (for plugins) | `[]` | |
236
+
237
+ `localePath` as a function is of the form `(locale: string, namespace: string, missing: boolean) => string` returning the entire path including filename and extension. When `missing` is true, return the path for the `addPath` option of `i18next-fs-backend`, when false, return the path for the `loadPath` option. [More info at the `i18next-fs-backend` repo.](https://github.com/i18next/i18next-fs-backend/tree/master#backend-options)
236
238
 
237
239
  All other [i18next options](https://www.i18next.com/overview/configuration-options) can be passed in as well.
238
240
 
@@ -100,6 +100,7 @@ var appWithTranslation = function appWithTranslation(WrappedComponent) {
100
100
  if (!_nextI18Next) return null;
101
101
  var userConfig = _nextI18Next.userConfig;
102
102
  var initialI18nStore = _nextI18Next.initialI18nStore;
103
+ var resources = configOverride !== null && configOverride !== void 0 && configOverride.resources ? configOverride.resources : initialI18nStore;
103
104
 
104
105
  if (userConfig === null && configOverride === null) {
105
106
  throw new Error('appWithTranslation was called without a next-i18next config');
@@ -117,7 +118,7 @@ var appWithTranslation = function appWithTranslation(WrappedComponent) {
117
118
  lng: locale
118
119
  }))), {}, {
119
120
  lng: locale,
120
- resources: initialI18nStore
121
+ resources: resources
121
122
  })).i18n;
122
123
  exports.globalI18n = globalI18n = instance;
123
124
  return instance;
@@ -61,14 +61,12 @@ require("core-js/modules/es.array.reduce.js");
61
61
 
62
62
  require("core-js/modules/es.object.values.js");
63
63
 
64
- require("core-js/modules/es.string.match.js");
65
-
66
64
  require("core-js/modules/es.array.for-each.js");
67
65
 
68
- var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
69
-
70
66
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
71
67
 
68
+ var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
69
+
72
70
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
73
71
 
74
72
  var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
@@ -136,39 +134,66 @@ var createConfig = function createConfig(userConfig) {
136
134
  if (!hasCustomBackend) {
137
135
  var fs = require('fs');
138
136
 
139
- var path = require('path');
140
-
141
- var serverLocalePath = localePath; //
137
+ var path = require('path'); //
142
138
  // Validate defaultNS
143
139
  // https://github.com/isaachinman/next-i18next/issues/358
144
140
  //
145
141
 
142
+
146
143
  if (typeof defaultNS === 'string' && typeof lng !== 'undefined') {
147
- var _userConfig$interpola, _userConfig$interpola2, _userConfig$interpola3, _userConfig$interpola4;
144
+ if (typeof localePath === 'string') {
145
+ var _userConfig$interpola, _userConfig$interpola2, _userConfig$interpola3, _userConfig$interpola4;
146
+
147
+ var prefix = (_userConfig$interpola = userConfig === null || userConfig === void 0 ? void 0 : (_userConfig$interpola2 = userConfig.interpolation) === null || _userConfig$interpola2 === void 0 ? void 0 : _userConfig$interpola2.prefix) !== null && _userConfig$interpola !== void 0 ? _userConfig$interpola : '{{';
148
+ var suffix = (_userConfig$interpola3 = userConfig === null || userConfig === void 0 ? void 0 : (_userConfig$interpola4 = userConfig.interpolation) === null || _userConfig$interpola4 === void 0 ? void 0 : _userConfig$interpola4.suffix) !== null && _userConfig$interpola3 !== void 0 ? _userConfig$interpola3 : '}}';
149
+ var defaultLocaleStructure = localeStructure.replace("".concat(prefix, "lng").concat(suffix), lng).replace("".concat(prefix, "ns").concat(suffix), defaultNS);
150
+ var defaultFile = "/".concat(defaultLocaleStructure, ".").concat(localeExtension);
151
+ var defaultNSPath = path.join(localePath, defaultFile);
152
+ var defaultNSExists = fs.existsSync(defaultNSPath);
153
+
154
+ if (!defaultNSExists && process.env.NODE_ENV !== 'production') {
155
+ throw new Error("Default namespace not found at ".concat(defaultNSPath));
156
+ }
157
+ } else if (typeof localePath === 'function') {
158
+ var _defaultNSPath = localePath(lng, defaultNS, false);
148
159
 
149
- var prefix = (_userConfig$interpola = userConfig === null || userConfig === void 0 ? void 0 : (_userConfig$interpola2 = userConfig.interpolation) === null || _userConfig$interpola2 === void 0 ? void 0 : _userConfig$interpola2.prefix) !== null && _userConfig$interpola !== void 0 ? _userConfig$interpola : '{{';
150
- var suffix = (_userConfig$interpola3 = userConfig === null || userConfig === void 0 ? void 0 : (_userConfig$interpola4 = userConfig.interpolation) === null || _userConfig$interpola4 === void 0 ? void 0 : _userConfig$interpola4.suffix) !== null && _userConfig$interpola3 !== void 0 ? _userConfig$interpola3 : '}}';
151
- var defaultLocaleStructure = localeStructure.replace("".concat(prefix, "lng").concat(suffix), lng).replace("".concat(prefix, "ns").concat(suffix), defaultNS);
152
- var defaultFile = "/".concat(defaultLocaleStructure, ".").concat(localeExtension);
153
- var defaultNSPath = path.join(localePath, defaultFile);
154
- var defaultNSExists = fs.existsSync(defaultNSPath);
160
+ var _defaultNSExists = fs.existsSync(_defaultNSPath);
155
161
 
156
- if (!defaultNSExists && process.env.NODE_ENV !== 'production') {
157
- throw new Error("Default namespace not found at ".concat(defaultNSPath));
162
+ if (!_defaultNSExists && process.env.NODE_ENV !== 'production') {
163
+ throw new Error("Default namespace not found at ".concat(_defaultNSPath));
164
+ }
158
165
  }
159
166
  } //
160
167
  // Set server side backend
161
168
  //
162
169
 
163
170
 
164
- combinedConfig.backend = {
165
- addPath: path.resolve(process.cwd(), "".concat(serverLocalePath, "/").concat(localeStructure, ".missing.").concat(localeExtension)),
166
- loadPath: path.resolve(process.cwd(), "".concat(serverLocalePath, "/").concat(localeStructure, ".").concat(localeExtension))
167
- }; //
171
+ if (typeof localePath === 'string') {
172
+ combinedConfig.backend = {
173
+ addPath: path.resolve(process.cwd(), "".concat(localePath, "/").concat(localeStructure, ".missing.").concat(localeExtension)),
174
+ loadPath: path.resolve(process.cwd(), "".concat(localePath, "/").concat(localeStructure, ".").concat(localeExtension))
175
+ };
176
+ } else if (typeof localePath === 'function') {
177
+ combinedConfig.backend = {
178
+ addPath: function addPath(locale, namespace) {
179
+ return localePath(locale, namespace, true);
180
+ },
181
+ loadPath: function loadPath(locale, namespace) {
182
+ return localePath(locale, namespace, false);
183
+ }
184
+ };
185
+ } else {
186
+ throw new Error("Unsupported localePath type: ".concat((0, _typeof2["default"])(localePath)));
187
+ } //
168
188
  // Set server side preload (namespaces)
169
189
  //
170
190
 
191
+
171
192
  if (!combinedConfig.ns && typeof lng !== 'undefined') {
193
+ if (typeof localePath === 'function') {
194
+ throw new Error('Must provide all namespaces in ns option if using a function as localePath');
195
+ }
196
+
172
197
  var unique = function unique(list) {
173
198
  return Array.from(new Set(list));
174
199
  };
@@ -181,7 +206,7 @@ var createConfig = function createConfig(userConfig) {
181
206
  };
182
207
 
183
208
  var namespacesByLocale = locales.map(function (locale) {
184
- return getLocaleNamespaces(path.resolve(process.cwd(), "".concat(serverLocalePath, "/").concat(locale)));
209
+ return getLocaleNamespaces(path.resolve(process.cwd(), "".concat(localePath, "/").concat(locale)));
185
210
  });
186
211
  var allNamespaces = [];
187
212
 
@@ -225,22 +250,25 @@ var createConfig = function createConfig(userConfig) {
225
250
  }
226
251
  }
227
252
  } else {
228
- var clientLocalePath = localePath; //
229
- // Remove public prefix from client site config
230
253
  //
231
-
232
- if (localePath.match(/^\.?\/public\//)) {
233
- clientLocalePath = localePath.replace(/^\.?\/public/, '');
234
- } //
235
254
  // Set client side backend, if there is no custom backend
236
255
  //
237
-
238
-
239
256
  if (!hasCustomBackend) {
240
- combinedConfig.backend = {
241
- addPath: "".concat(clientLocalePath, "/").concat(localeStructure, ".missing.").concat(localeExtension),
242
- loadPath: "".concat(clientLocalePath, "/").concat(localeStructure, ".").concat(localeExtension)
243
- };
257
+ if (typeof localePath === 'string') {
258
+ combinedConfig.backend = {
259
+ addPath: "".concat(localePath, "/").concat(localeStructure, ".missing.").concat(localeExtension),
260
+ loadPath: "".concat(localePath, "/").concat(localeStructure, ".").concat(localeExtension)
261
+ };
262
+ } else if (typeof localePath === 'function') {
263
+ combinedConfig.backend = {
264
+ addPath: function addPath(locale, namespace) {
265
+ return localePath(locale, namespace, true);
266
+ },
267
+ loadPath: function loadPath(locale, namespace) {
268
+ return localePath(locale, namespace, false);
269
+ }
270
+ };
271
+ }
244
272
  }
245
273
 
246
274
  if (typeof combinedConfig.ns !== 'string' && !Array.isArray(combinedConfig.ns)) {
@@ -222,19 +222,31 @@ var serverSideTranslations = /*#__PURE__*/function () {
222
222
  initialI18nStore[lng] = {};
223
223
  });
224
224
 
225
- if (!Array.isArray(namespacesRequired)) {
226
- getLocaleNamespaces = function getLocaleNamespaces(path) {
227
- return _fs["default"].readdirSync(path).map(function (file) {
228
- return file.replace(".".concat(localeExtension), '');
229
- });
230
- };
231
-
232
- namespacesByLocale = Object.keys(initialI18nStore).map(function (locale) {
233
- return getLocaleNamespaces(_path["default"].resolve(process.cwd(), "".concat(localePath, "/").concat(locale)));
234
- });
235
- namespacesRequired = flatNamespaces(namespacesByLocale);
225
+ if (Array.isArray(namespacesRequired)) {
226
+ _context.next = 27;
227
+ break;
228
+ }
229
+
230
+ if (!(typeof localePath === 'function')) {
231
+ _context.next = 24;
232
+ break;
236
233
  }
237
234
 
235
+ throw new Error('Must provide namespacesRequired to serverSideTranslations when using a function as localePath');
236
+
237
+ case 24:
238
+ getLocaleNamespaces = function getLocaleNamespaces(path) {
239
+ return _fs["default"].readdirSync(path).map(function (file) {
240
+ return file.replace(".".concat(localeExtension), '');
241
+ });
242
+ };
243
+
244
+ namespacesByLocale = Object.keys(initialI18nStore).map(function (locale) {
245
+ return getLocaleNamespaces(_path["default"].resolve(process.cwd(), "".concat(localePath, "/").concat(locale)));
246
+ });
247
+ namespacesRequired = flatNamespaces(namespacesByLocale);
248
+
249
+ case 27:
238
250
  namespacesRequired.forEach(function (ns) {
239
251
  for (var locale in initialI18nStore) {
240
252
  initialI18nStore[locale][ns] = (i18n.services.resourceStore.data[locale] || {})[ns] || {};
@@ -248,7 +260,7 @@ var serverSideTranslations = /*#__PURE__*/function () {
248
260
  }
249
261
  });
250
262
 
251
- case 24:
263
+ case 29:
252
264
  case "end":
253
265
  return _context.stop();
254
266
  }
@@ -26,6 +26,7 @@ export const appWithTranslation = (WrappedComponent, configOverride = null) => {
26
26
  const {
27
27
  initialI18nStore
28
28
  } = _nextI18Next;
29
+ const resources = configOverride !== null && configOverride !== void 0 && configOverride.resources ? configOverride.resources : initialI18nStore;
29
30
 
30
31
  if (userConfig === null && configOverride === null) {
31
32
  throw new Error('appWithTranslation was called without a next-i18next config');
@@ -43,7 +44,7 @@ export const appWithTranslation = (WrappedComponent, configOverride = null) => {
43
44
  lng: locale
44
45
  }),
45
46
  lng: locale,
46
- resources: initialI18nStore
47
+ resources
47
48
  }).i18n;
48
49
  globalI18n = instance;
49
50
  return instance;
@@ -52,45 +52,67 @@ export const createConfig = userConfig => {
52
52
  if (!hasCustomBackend) {
53
53
  const fs = require('fs');
54
54
 
55
- const path = require('path');
56
-
57
- const serverLocalePath = localePath; //
55
+ const path = require('path'); //
58
56
  // Validate defaultNS
59
57
  // https://github.com/isaachinman/next-i18next/issues/358
60
58
  //
61
59
 
62
- if (typeof defaultNS === 'string' && typeof lng !== 'undefined') {
63
- var _userConfig$interpola, _userConfig$interpola2;
64
60
 
65
- const prefix = (userConfig === null || userConfig === void 0 ? void 0 : (_userConfig$interpola = userConfig.interpolation) === null || _userConfig$interpola === void 0 ? void 0 : _userConfig$interpola.prefix) ?? '{{';
66
- const suffix = (userConfig === null || userConfig === void 0 ? void 0 : (_userConfig$interpola2 = userConfig.interpolation) === null || _userConfig$interpola2 === void 0 ? void 0 : _userConfig$interpola2.suffix) ?? '}}';
67
- const defaultLocaleStructure = localeStructure.replace(`${prefix}lng${suffix}`, lng).replace(`${prefix}ns${suffix}`, defaultNS);
68
- const defaultFile = `/${defaultLocaleStructure}.${localeExtension}`;
69
- const defaultNSPath = path.join(localePath, defaultFile);
70
- const defaultNSExists = fs.existsSync(defaultNSPath);
61
+ if (typeof defaultNS === 'string' && typeof lng !== 'undefined') {
62
+ if (typeof localePath === 'string') {
63
+ var _userConfig$interpola, _userConfig$interpola2;
64
+
65
+ const prefix = (userConfig === null || userConfig === void 0 ? void 0 : (_userConfig$interpola = userConfig.interpolation) === null || _userConfig$interpola === void 0 ? void 0 : _userConfig$interpola.prefix) ?? '{{';
66
+ const suffix = (userConfig === null || userConfig === void 0 ? void 0 : (_userConfig$interpola2 = userConfig.interpolation) === null || _userConfig$interpola2 === void 0 ? void 0 : _userConfig$interpola2.suffix) ?? '}}';
67
+ const defaultLocaleStructure = localeStructure.replace(`${prefix}lng${suffix}`, lng).replace(`${prefix}ns${suffix}`, defaultNS);
68
+ const defaultFile = `/${defaultLocaleStructure}.${localeExtension}`;
69
+ const defaultNSPath = path.join(localePath, defaultFile);
70
+ const defaultNSExists = fs.existsSync(defaultNSPath);
71
+
72
+ if (!defaultNSExists && process.env.NODE_ENV !== 'production') {
73
+ throw new Error(`Default namespace not found at ${defaultNSPath}`);
74
+ }
75
+ } else if (typeof localePath === 'function') {
76
+ const defaultNSPath = localePath(lng, defaultNS, false);
77
+ const defaultNSExists = fs.existsSync(defaultNSPath);
71
78
 
72
- if (!defaultNSExists && process.env.NODE_ENV !== 'production') {
73
- throw new Error(`Default namespace not found at ${defaultNSPath}`);
79
+ if (!defaultNSExists && process.env.NODE_ENV !== 'production') {
80
+ throw new Error(`Default namespace not found at ${defaultNSPath}`);
81
+ }
74
82
  }
75
83
  } //
76
84
  // Set server side backend
77
85
  //
78
86
 
79
87
 
80
- combinedConfig.backend = {
81
- addPath: path.resolve(process.cwd(), `${serverLocalePath}/${localeStructure}.missing.${localeExtension}`),
82
- loadPath: path.resolve(process.cwd(), `${serverLocalePath}/${localeStructure}.${localeExtension}`)
83
- }; //
88
+ if (typeof localePath === 'string') {
89
+ combinedConfig.backend = {
90
+ addPath: path.resolve(process.cwd(), `${localePath}/${localeStructure}.missing.${localeExtension}`),
91
+ loadPath: path.resolve(process.cwd(), `${localePath}/${localeStructure}.${localeExtension}`)
92
+ };
93
+ } else if (typeof localePath === 'function') {
94
+ combinedConfig.backend = {
95
+ addPath: (locale, namespace) => localePath(locale, namespace, true),
96
+ loadPath: (locale, namespace) => localePath(locale, namespace, false)
97
+ };
98
+ } else {
99
+ throw new Error(`Unsupported localePath type: ${typeof localePath}`);
100
+ } //
84
101
  // Set server side preload (namespaces)
85
102
  //
86
103
 
104
+
87
105
  if (!combinedConfig.ns && typeof lng !== 'undefined') {
106
+ if (typeof localePath === 'function') {
107
+ throw new Error('Must provide all namespaces in ns option if using a function as localePath');
108
+ }
109
+
88
110
  const unique = list => Array.from(new Set(list));
89
111
 
90
112
  const getNamespaces = locales => {
91
113
  const getLocaleNamespaces = p => fs.readdirSync(p).map(file => file.replace(`.${localeExtension}`, ''));
92
114
 
93
- const namespacesByLocale = locales.map(locale => getLocaleNamespaces(path.resolve(process.cwd(), `${serverLocalePath}/${locale}`)));
115
+ const namespacesByLocale = locales.map(locale => getLocaleNamespaces(path.resolve(process.cwd(), `${localePath}/${locale}`)));
94
116
  const allNamespaces = [];
95
117
 
96
118
  for (const localNamespaces of namespacesByLocale) {
@@ -121,22 +143,21 @@ export const createConfig = userConfig => {
121
143
  }
122
144
  }
123
145
  } else {
124
- let clientLocalePath = localePath; //
125
- // Remove public prefix from client site config
126
146
  //
127
-
128
- if (localePath.match(/^\.?\/public\//)) {
129
- clientLocalePath = localePath.replace(/^\.?\/public/, '');
130
- } //
131
147
  // Set client side backend, if there is no custom backend
132
148
  //
133
-
134
-
135
149
  if (!hasCustomBackend) {
136
- combinedConfig.backend = {
137
- addPath: `${clientLocalePath}/${localeStructure}.missing.${localeExtension}`,
138
- loadPath: `${clientLocalePath}/${localeStructure}.${localeExtension}`
139
- };
150
+ if (typeof localePath === 'string') {
151
+ combinedConfig.backend = {
152
+ addPath: `${localePath}/${localeStructure}.missing.${localeExtension}`,
153
+ loadPath: `${localePath}/${localeStructure}.${localeExtension}`
154
+ };
155
+ } else if (typeof localePath === 'function') {
156
+ combinedConfig.backend = {
157
+ addPath: (locale, namespace) => localePath(locale, namespace, true),
158
+ loadPath: (locale, namespace) => localePath(locale, namespace, false)
159
+ };
160
+ }
140
161
  }
141
162
 
142
163
  if (typeof combinedConfig.ns !== 'string' && !Array.isArray(combinedConfig.ns)) {
@@ -75,6 +75,10 @@ export const serverSideTranslations = async (initialLocale, namespacesRequired =
75
75
  });
76
76
 
77
77
  if (!Array.isArray(namespacesRequired)) {
78
+ if (typeof localePath === 'function') {
79
+ throw new Error('Must provide namespacesRequired to serverSideTranslations when using a function as localePath');
80
+ }
81
+
78
82
  const getLocaleNamespaces = path => fs.readdirSync(path).map(file => file.replace(`.${localeExtension}`, ''));
79
83
 
80
84
  const namespacesByLocale = Object.keys(initialI18nStore).map(locale => getLocaleNamespaces(path.resolve(process.cwd(), `${localePath}/${locale}`)));
@@ -31,6 +31,7 @@ export var appWithTranslation = function appWithTranslation(WrappedComponent) {
31
31
  if (!_nextI18Next) return null;
32
32
  var userConfig = _nextI18Next.userConfig;
33
33
  var initialI18nStore = _nextI18Next.initialI18nStore;
34
+ var resources = configOverride !== null && configOverride !== void 0 && configOverride.resources ? configOverride.resources : initialI18nStore;
34
35
 
35
36
  if (userConfig === null && configOverride === null) {
36
37
  throw new Error('appWithTranslation was called without a next-i18next config');
@@ -48,7 +49,7 @@ export var appWithTranslation = function appWithTranslation(WrappedComponent) {
48
49
  lng: locale
49
50
  }))), {}, {
50
51
  lng: locale,
51
- resources: initialI18nStore
52
+ resources: resources
52
53
  })).i18n;
53
54
  globalI18n = instance;
54
55
  return instance;
@@ -1,5 +1,5 @@
1
- import _typeof from "@babel/runtime/helpers/typeof";
2
1
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
+ import _typeof from "@babel/runtime/helpers/typeof";
3
3
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
4
  import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
5
5
  var _excluded = ["i18n"],
@@ -64,39 +64,66 @@ export var createConfig = function createConfig(userConfig) {
64
64
  if (!hasCustomBackend) {
65
65
  var fs = require('fs');
66
66
 
67
- var path = require('path');
68
-
69
- var serverLocalePath = localePath; //
67
+ var path = require('path'); //
70
68
  // Validate defaultNS
71
69
  // https://github.com/isaachinman/next-i18next/issues/358
72
70
  //
73
71
 
72
+
74
73
  if (typeof defaultNS === 'string' && typeof lng !== 'undefined') {
75
- var _userConfig$interpola, _userConfig$interpola2, _userConfig$interpola3, _userConfig$interpola4;
74
+ if (typeof localePath === 'string') {
75
+ var _userConfig$interpola, _userConfig$interpola2, _userConfig$interpola3, _userConfig$interpola4;
76
+
77
+ var prefix = (_userConfig$interpola = userConfig === null || userConfig === void 0 ? void 0 : (_userConfig$interpola2 = userConfig.interpolation) === null || _userConfig$interpola2 === void 0 ? void 0 : _userConfig$interpola2.prefix) !== null && _userConfig$interpola !== void 0 ? _userConfig$interpola : '{{';
78
+ var suffix = (_userConfig$interpola3 = userConfig === null || userConfig === void 0 ? void 0 : (_userConfig$interpola4 = userConfig.interpolation) === null || _userConfig$interpola4 === void 0 ? void 0 : _userConfig$interpola4.suffix) !== null && _userConfig$interpola3 !== void 0 ? _userConfig$interpola3 : '}}';
79
+ var defaultLocaleStructure = localeStructure.replace("".concat(prefix, "lng").concat(suffix), lng).replace("".concat(prefix, "ns").concat(suffix), defaultNS);
80
+ var defaultFile = "/".concat(defaultLocaleStructure, ".").concat(localeExtension);
81
+ var defaultNSPath = path.join(localePath, defaultFile);
82
+ var defaultNSExists = fs.existsSync(defaultNSPath);
83
+
84
+ if (!defaultNSExists && process.env.NODE_ENV !== 'production') {
85
+ throw new Error("Default namespace not found at ".concat(defaultNSPath));
86
+ }
87
+ } else if (typeof localePath === 'function') {
88
+ var _defaultNSPath = localePath(lng, defaultNS, false);
76
89
 
77
- var prefix = (_userConfig$interpola = userConfig === null || userConfig === void 0 ? void 0 : (_userConfig$interpola2 = userConfig.interpolation) === null || _userConfig$interpola2 === void 0 ? void 0 : _userConfig$interpola2.prefix) !== null && _userConfig$interpola !== void 0 ? _userConfig$interpola : '{{';
78
- var suffix = (_userConfig$interpola3 = userConfig === null || userConfig === void 0 ? void 0 : (_userConfig$interpola4 = userConfig.interpolation) === null || _userConfig$interpola4 === void 0 ? void 0 : _userConfig$interpola4.suffix) !== null && _userConfig$interpola3 !== void 0 ? _userConfig$interpola3 : '}}';
79
- var defaultLocaleStructure = localeStructure.replace("".concat(prefix, "lng").concat(suffix), lng).replace("".concat(prefix, "ns").concat(suffix), defaultNS);
80
- var defaultFile = "/".concat(defaultLocaleStructure, ".").concat(localeExtension);
81
- var defaultNSPath = path.join(localePath, defaultFile);
82
- var defaultNSExists = fs.existsSync(defaultNSPath);
90
+ var _defaultNSExists = fs.existsSync(_defaultNSPath);
83
91
 
84
- if (!defaultNSExists && process.env.NODE_ENV !== 'production') {
85
- throw new Error("Default namespace not found at ".concat(defaultNSPath));
92
+ if (!_defaultNSExists && process.env.NODE_ENV !== 'production') {
93
+ throw new Error("Default namespace not found at ".concat(_defaultNSPath));
94
+ }
86
95
  }
87
96
  } //
88
97
  // Set server side backend
89
98
  //
90
99
 
91
100
 
92
- combinedConfig.backend = {
93
- addPath: path.resolve(process.cwd(), "".concat(serverLocalePath, "/").concat(localeStructure, ".missing.").concat(localeExtension)),
94
- loadPath: path.resolve(process.cwd(), "".concat(serverLocalePath, "/").concat(localeStructure, ".").concat(localeExtension))
95
- }; //
101
+ if (typeof localePath === 'string') {
102
+ combinedConfig.backend = {
103
+ addPath: path.resolve(process.cwd(), "".concat(localePath, "/").concat(localeStructure, ".missing.").concat(localeExtension)),
104
+ loadPath: path.resolve(process.cwd(), "".concat(localePath, "/").concat(localeStructure, ".").concat(localeExtension))
105
+ };
106
+ } else if (typeof localePath === 'function') {
107
+ combinedConfig.backend = {
108
+ addPath: function addPath(locale, namespace) {
109
+ return localePath(locale, namespace, true);
110
+ },
111
+ loadPath: function loadPath(locale, namespace) {
112
+ return localePath(locale, namespace, false);
113
+ }
114
+ };
115
+ } else {
116
+ throw new Error("Unsupported localePath type: ".concat(_typeof(localePath)));
117
+ } //
96
118
  // Set server side preload (namespaces)
97
119
  //
98
120
 
121
+
99
122
  if (!combinedConfig.ns && typeof lng !== 'undefined') {
123
+ if (typeof localePath === 'function') {
124
+ throw new Error('Must provide all namespaces in ns option if using a function as localePath');
125
+ }
126
+
100
127
  var unique = function unique(list) {
101
128
  return Array.from(new Set(list));
102
129
  };
@@ -109,7 +136,7 @@ export var createConfig = function createConfig(userConfig) {
109
136
  };
110
137
 
111
138
  var namespacesByLocale = locales.map(function (locale) {
112
- return getLocaleNamespaces(path.resolve(process.cwd(), "".concat(serverLocalePath, "/").concat(locale)));
139
+ return getLocaleNamespaces(path.resolve(process.cwd(), "".concat(localePath, "/").concat(locale)));
113
140
  });
114
141
  var allNamespaces = [];
115
142
 
@@ -153,22 +180,25 @@ export var createConfig = function createConfig(userConfig) {
153
180
  }
154
181
  }
155
182
  } else {
156
- var clientLocalePath = localePath; //
157
- // Remove public prefix from client site config
158
183
  //
159
-
160
- if (localePath.match(/^\.?\/public\//)) {
161
- clientLocalePath = localePath.replace(/^\.?\/public/, '');
162
- } //
163
184
  // Set client side backend, if there is no custom backend
164
185
  //
165
-
166
-
167
186
  if (!hasCustomBackend) {
168
- combinedConfig.backend = {
169
- addPath: "".concat(clientLocalePath, "/").concat(localeStructure, ".missing.").concat(localeExtension),
170
- loadPath: "".concat(clientLocalePath, "/").concat(localeStructure, ".").concat(localeExtension)
171
- };
187
+ if (typeof localePath === 'string') {
188
+ combinedConfig.backend = {
189
+ addPath: "".concat(localePath, "/").concat(localeStructure, ".missing.").concat(localeExtension),
190
+ loadPath: "".concat(localePath, "/").concat(localeStructure, ".").concat(localeExtension)
191
+ };
192
+ } else if (typeof localePath === 'function') {
193
+ combinedConfig.backend = {
194
+ addPath: function addPath(locale, namespace) {
195
+ return localePath(locale, namespace, true);
196
+ },
197
+ loadPath: function loadPath(locale, namespace) {
198
+ return localePath(locale, namespace, false);
199
+ }
200
+ };
201
+ }
172
202
  }
173
203
 
174
204
  if (typeof combinedConfig.ns !== 'string' && !Array.isArray(combinedConfig.ns)) {
@@ -140,19 +140,31 @@ export var serverSideTranslations = /*#__PURE__*/function () {
140
140
  initialI18nStore[lng] = {};
141
141
  });
142
142
 
143
- if (!Array.isArray(namespacesRequired)) {
144
- getLocaleNamespaces = function getLocaleNamespaces(path) {
145
- return fs.readdirSync(path).map(function (file) {
146
- return file.replace(".".concat(localeExtension), '');
147
- });
148
- };
149
-
150
- namespacesByLocale = Object.keys(initialI18nStore).map(function (locale) {
151
- return getLocaleNamespaces(path.resolve(process.cwd(), "".concat(localePath, "/").concat(locale)));
152
- });
153
- namespacesRequired = flatNamespaces(namespacesByLocale);
143
+ if (Array.isArray(namespacesRequired)) {
144
+ _context.next = 27;
145
+ break;
146
+ }
147
+
148
+ if (!(typeof localePath === 'function')) {
149
+ _context.next = 24;
150
+ break;
154
151
  }
155
152
 
153
+ throw new Error('Must provide namespacesRequired to serverSideTranslations when using a function as localePath');
154
+
155
+ case 24:
156
+ getLocaleNamespaces = function getLocaleNamespaces(path) {
157
+ return fs.readdirSync(path).map(function (file) {
158
+ return file.replace(".".concat(localeExtension), '');
159
+ });
160
+ };
161
+
162
+ namespacesByLocale = Object.keys(initialI18nStore).map(function (locale) {
163
+ return getLocaleNamespaces(path.resolve(process.cwd(), "".concat(localePath, "/").concat(locale)));
164
+ });
165
+ namespacesRequired = flatNamespaces(namespacesByLocale);
166
+
167
+ case 27:
156
168
  namespacesRequired.forEach(function (ns) {
157
169
  for (var locale in initialI18nStore) {
158
170
  initialI18nStore[locale][ns] = (i18n.services.resourceStore.data[locale] || {})[ns] || {};
@@ -166,7 +178,7 @@ export var serverSideTranslations = /*#__PURE__*/function () {
166
178
  }
167
179
  });
168
180
 
169
- case 24:
181
+ case 29:
170
182
  case "end":
171
183
  return _context.stop();
172
184
  }
@@ -8,7 +8,7 @@ declare type NextJsI18NConfig = {
8
8
  export declare type UserConfig = {
9
9
  i18n: NextJsI18NConfig;
10
10
  localeExtension?: string;
11
- localePath?: string;
11
+ localePath?: string | ((locale: string, namespace: string, missing: boolean) => string);
12
12
  localeStructure?: string;
13
13
  reloadOnPrerender?: boolean;
14
14
  serializeConfig?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-i18next",
3
- "version": "10.3.0",
3
+ "version": "10.4.0",
4
4
  "repository": "git@github.com:isaachinman/next-i18next.git",
5
5
  "author": "Isaac Hinman <isaac@isaachinman.com>",
6
6
  "funding": {
@@ -72,7 +72,7 @@
72
72
  "@babel/preset-env": "^7.10.4",
73
73
  "@babel/preset-react": "^7.10.4",
74
74
  "@babel/preset-typescript": "^7.10.4",
75
- "@testing-library/react": "^11.2.5",
75
+ "@testing-library/react": "^12.1.3",
76
76
  "@types/i18next-fs-backend": "^1.1.2",
77
77
  "@types/jest": "^27.0.1",
78
78
  "@types/node": "^16.7.1",
@@ -96,7 +96,7 @@
96
96
  "eslint-plugin-typescript-sort-keys": "^2.1.0",
97
97
  "husky": "^3.0.0",
98
98
  "jest": "^26.6.3",
99
- "next": "^11.1.3",
99
+ "next": "^12.1.0",
100
100
  "react": "^17.0.1",
101
101
  "react-dom": "^17.0.1",
102
102
  "start-server-and-test": "^1.12.0",
package/vercel.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "github": {
3
+ "silent": true
4
+ }
5
+ }