Я собираюсь ответить на свой вопрос.После исследования я выяснил, что мой вариант использования встречается редко, и я решил выполнить некоторую предварительную обработку локали для достижения желаемой функциональности.
Я использую конфигурацию по умолчанию create-react-app
вместе с react-i18next
и мойСтруктура файла выглядит следующим образом:
src
- Component A
- locales
- en.json
- sk.json
- Component B
- locales
- en.json
Вот настройки для модуля react-i18next
:
i18n
.use(Backend)
.use('en')
.use(reactI18nextModule)
.init({
fallbackLng: 'en',
debug: false,
backend: {
loadPath: function() {
return `${config.BASE_URL}locales/{{lng}}.json`;
}
},
react: {
wait: true
}
});
Так как я использую конфигурацию по умолчанию create-react-app
, локали обслуживаются из папки public
в приложении и собираются сами.
Итеперь это становится сложно.Поскольку файлы локалей находятся в дереве компонентов (а не в общей папке), нам необходимо выполнить некоторую предварительную обработку локалей - в основном нам нужно объединить все файлы JSON и переместить их в общую папку.
Файлы для общей папки создаются на лету с помощью задачи узла (prepare-locales.js
) ниже:
const jsonConcat = require('json-concat');
const minifyJson = require('minify-json');
const glob = require('glob');
const availableLocales = ['en', 'sk'];
const path = require('path');
module.exports.development = function() {
availableLocales.forEach(locale => {
glob(`./src/**/locales/${locale}.json`, {}, (err, globFiles) => {
if (globFiles.length) {
const file = `./public/locales/${locale}.json`;
jsonConcat(
{
src: globFiles,
dest: file
},
json => {
minifyJson(file);
}
);
}
});
});
};
module.exports.production = function() {
glob('./build/static/js/main.*.js', {}, (err, globFiles) => {
const files = require('source-map-explorer')(globFiles[0]).files;
let localeFolders = [];
Object.keys(files).forEach(fileName => {
localeFolders.push(path.dirname(fileName).replace('./', ''));
});
localeFolders = [...new Set(localeFolders)];
availableLocales.forEach(locale => {
const localeFiles = localeFolders.map(
lf => `./src/${lf}/locales/${locale}.json`
);
if (localeFiles.length) {
const file = `./build/locales/${locale}.json`;
jsonConcat(
{
src: localeFiles,
dest: file
},
json => {
minifyJson(file);
}
);
}
});
});
};
Для версии для разработки я собираю все файлы JSON, которые находятся в дереве.
Для версии для работы я использую source-map-explorer
и я объединяю только те локали, которые используются в сборке.
Вот мой упрощенный package.json
с задачами, необходимыми для этого:
{
"devDependencies": {
"json-concat": "0.0.1",
"minify-json": "^1.0.0",
"npm-watch": "^0.4.0",
"path": "^0.12.7",
"react-scripts": "2.1.1",
"source-map-explorer": "^1.6.0"
},
"scripts": {
"start": "react-scripts start & npm run prepare-locales:development:watch",
"build:production": "react-scripts build && npm run prepare-locales:production",
"prepare-locales:development:watch": "npm-watch prepare-locales:development",
"prepare-locales:development": "node -e 'require(\"./prepare-locales.js\").development()'",
"prepare-locales:production": "node -e 'require(\"./prepare-locales.js\").production()'"
},
"watch": {
"prepare-locales:development": {
"patterns": "src/**/locales/",
"extensions": "json"
}
}
}
Возможно, это не лучшее решение, но оно подходит для моего варианта использования и, надеюсь, поможет кому-то с подобными проблемами.