Backend на основе файловой системы используется для загрузки переводов напрямую с диска в Node.js-окружении, обеспечивая классическую модель хранения локализационных ресурсов в виде JSON-файлов. Такой подход особенно распространён в серверных приложениях, где доступ к файловой системе не ограничен и требуется простая интеграция с i18next.
Модуль i18next-fs-backend реализует стратегию загрузки переводов через синхронное или асинхронное чтение файлов, поддерживая кэширование, неймспейсы и динамическую подгрузку ресурсов. Его использование позволяет отделить код приложения от языковых файлов и масштабировать структуру переводов без изменения бизнес-логики.
Файловый backend строится вокруг простой идеи: каждый язык хранится в отдельной директории, внутри которой располагаются JSON-файлы по неймспейсам.
Типичная структура:
/locales
/en
common.json
auth.json
/ru
common.json
auth.json
Каждый файл содержит ключи переводов:
{
"welcome": "Добро пожаловать",
"logout": "Выйти"
}
Такой формат обеспечивает:
Backend устанавливается как отдельный пакет и подключается к экземпляру i18next.
npm install i18next i18next-fs-backend
Инициализация в Node.js:
import i18next from 'i18next';
import Backend from 'i18next-fs-backend';
i18next
.use(Backend)
.init({
lng: 'ru',
fallbackLng: 'en',
backend: {
loadPath: './locales/{{lng}}/{{ns}}.json'
}
});
Ключевая часть конфигурации — loadPath, определяющий
шаблон пути к файлам переводов.
Файловый backend выполняет подстановку переменных:
{{lng}} — язык{{ns}} — неймспейсПосле формирования пути выполняется чтение файла через
fs.readFile.
Алгоритм загрузки:
Кэширование позволяет избежать повторного чтения файлов при каждом запросе перевода.
Backend поддерживает два режима:
Используется по умолчанию и не блокирует event loop:
backend: {
loadPath: './locales/{{lng}}/{{ns}}.json',
addPath: './locales/{{lng}}/{{ns}}.missing.json'
}
Асинхронный режим критичен для HTTP-серверов, так как предотвращает блокировки при высокой нагрузке.
Иногда применяется при старте приложения или в SSR-сценариях:
i18next.init({
initImmediate: false,
backend: {
loadPath: './locales/{{lng}}/{{ns}}.json',
read: (language, namespace) => {
const fs = require('fs');
return JSON.parse(
fs.readFileSync(`./locales/${language}/${namespace}.json`, 'utf-8')
);
}
}
});
Синхронный режим увеличивает предсказуемость загрузки, но блокирует поток выполнения.
Неймспейсы позволяют разделять переводы по функциональным областям:
auth — авторизацияprofile — профиль пользователяdashboard — интерфейс панелиerrors — сообщения ошибокПример обращения:
i18next.t('auth:login.button');
Файловый backend загружает только необходимые неймспейсы, снижая потребление памяти.
Механизм lazy-loading позволяет подгружать переводы только при обращении к ним.
При первом запросе:
i18next.t('profile:title');
происходит:
profileprofile.jsonЭто особенно важно для больших приложений с десятками языков.
Backend использует внутренний кэш:
Поведение кэша:
Очистка кэша:
i18next.services.backendConnector.backend.cache.clear();
При высокой нагрузке кэширование существенно снижает количество операций I/O.
loadPath поддерживает шаблоны:
loadPath: '/translations/{{lng}}/{{ns}}.json'
Допустимые переменные:
{{lng}} — язык{{ns}} — namespace{{lng}}-{{ns}} — комбинированные структурыГибкость шаблонов позволяет адаптировать backend под любые файловые схемы.
При отсутствии ключа или файла применяется fallback-логика:
Дополнительная настройка:
i18next.init({
saveMissing: true,
backend: {
addPath: './locales/{{lng}}/{{ns}}.missing.json'
}
});
Missing keys могут сохраняться в отдельный файл для последующей обработки.
Файловый backend оптимизирован под серверные сценарии:
Основное ограничение — I/O операции. При большом числе языков рекомендуется:
При серверном рендеринге backend инициализируется на каждый запрос или на пул процессов.
Пример интеграции с Express:
app.use((req, res, next) => {
i18next
.cloneInstance()
.init({
lng: req.language,
backend: {
loadPath: './locales/{{lng}}/{{ns}}.json'
}
})
.then(() => next());
});
Клонирование экземпляра предотвращает утечку состояния между запросами.
Частая проблема связана с относительными путями:
ENOENT: no such file or directory
Решение — использование абсолютных путей:
loadPath: path.join(process.cwd(), 'locales/{{lng}}/{{ns}}.json')
Backend ожидает валидный JSON. Ошибки парсинга приводят к падению загрузки:
{
"key": "value",
}
Запятая после последнего элемента делает файл невалидным.
Слишком мелкая декомпозиция namespaces приводит к:
Баланс между модульностью и производительностью критичен.
Возможна переопределённая логика чтения:
backend: {
read: (language, namespace, callback) => {
fs.readFile(
`./locales/${language}/${namespace}.json`,
'utf-8',
(err, data) => {
if (err) return callback(err, false);
callback(null, JSON.parse(data));
}
);
}
}
Такой подход позволяет внедрять:
Хотя backend ориентирован на файловую систему, он может использоваться совместно с build-процессами:
В cluster-mode каждый процесс:
Это снижает зависимость между воркерами, но увеличивает потребление памяти.
Рекомендуемые подходы:
auth.login.button)Пример плоской структуры:
{
"auth.login.button": "Войти",
"auth.logout.button": "Выйти"
}
Механизм fallback работает каскадно:
ru-RU → ru → en → default
Backend участвует только в предоставлении данных, логика fallback управляется i18next.
Файловый backend предполагает:
Рекомендуется: