Сервис переводов в i18next представляет собой слой, отвечающий за получение, хранение и доставку локализованных ресурсов в приложение. Он отделяет бизнес-логику от механизма загрузки переводов и обеспечивает гибкость при работе с различными источниками данных.
Основная задача сервиса заключается в унификации доступа к переводам независимо от того, откуда они поступают: из локальных JSON-файлов, удалённого API, базы данных или CDN.
Ключевые функции сервиса:
В основе системы лежит разделение переводов по двум измерениям:
en, ru,
decommon, auth,
errorsСервис переводов работает с запросами вида:
/locales/{lng}/{namespace}.json
или через API:
GET /translations?lng=ru&ns=common
Внутри i18next эти запросы обрабатываются backend-модулем, который подключается как плагин.
Сервис переводов в большинстве случаев реализуется через backend-плагин. Он отвечает за фактическое получение данных.
Пример стандартного HTTP backend:
import i18next from 'i18next'
import HttpBackend from 'i18next-http-backend'
i18next
.use(HttpBackend)
.init({
lng: 'ru',
ns: ['common', 'auth'],
defaultNS: 'common',
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json'
}
})
Здесь backend выполняет роль сервиса, который:
Гибкость i18next позволяет реализовать собственный сервис, заменяя стандартный backend.
Кастомный backend реализуется через интерфейс:
read(language, namespace, callback)create() (опционально)init() (инициализация)type — идентификатор backend-аПример реализации сервиса на основе API:
class TranslationService {
constructor(services, options = {}) {
this.services = services
this.options = options
}
read(language, namespace, callback) {
fetch(`${this.options.api}/translations?lng=${language}&ns=${namespace}`)
.then(res => res.json())
.then(data => callback(null, data))
.catch(err => callback(err, false))
}
init(services, backendOptions) {
this.services = services
this.options = backendOptions
}
type = 'customBackend'
}
Подключение:
import i18next from 'i18next'
i18next.init({
lng: 'ru',
ns: ['common'],
backend: {
api: 'https://example.com'
},
backend: TranslationService
})
При запросе строки перевода выполняется последовательность:
t()Сервис выступает промежуточным слоем между t() и
источником данных.
Сервис переводов должен минимизировать сетевые запросы. В i18next кеширование встроено на уровне ресурсов.
Типовые стратегии:
Переводы сохраняются в runtime:
i18next.init({
saveMissing: false,
cache: {
enabled: true
}
})
Использование заголовков:
Cache-Control: max-age=86400
ETag: "translation-v3"
Используется для офлайн-режима через плагины.
Сервис переводов поддерживает цепочку языков:
ru → en → default
Если ключ отсутствует:
Настройка:
i18next.init({
fallbackLng: 'en',
load: 'currentOnly'
})
Fallback является частью логики сервиса, а не только функции
t().
Сервис переводов работает асинхронно, что влияет на инициализацию приложения.
Типичный сценарий:
i18next
.init({
lng: 'ru',
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json'
}
})
.then(() => {
console.log('translations loaded')
})
Пока сервис не завершил загрузку, переводы могут быть пустыми или заменяться fallback-значениями.
Сервис переводов не только доставляет строки, но и участвует в подготовке данных для интерполяции.
Пример:
{
"welcome": "Привет, {{name}}"
}
Использование:
t('welcome', { name: 'Alex' })
Внутри i18next происходит:
В сложных системах сервис переводов может объединять несколько источников:
Пример комбинированного подхода:
const backend = {
read: (lng, ns, cb) => {
const local = localCache.get(lng, ns)
if (local) {
cb(null, local)
return
}
api.fetchTranslations(lng, ns)
.then(data => cb(null, data))
.catch(err => cb(err))
}
}
Такая схема позволяет строить приоритетные цепочки источников.
Сервис переводов обязан корректно обрабатывать сбои:
Стратегии обработки:
read(language, namespace, callback) {
try {
fetchData(language, namespace)
} catch (e) {
callback(null, {})
}
}
В i18next пустой объект переводов не ломает приложение, а перевод переходит в fallback-режим.
Ключевая концепция заключается в том, что сервис переводов отделяет:
t())Это позволяет изменять backend без изменения логики интерфейса.
Пример смены источника:
// Было: HTTP backend
// Стало: CMS backend
i18next.use(CMSBackend).init({...})
При этом интерфейс t() остаётся неизменным.
Оптимизация сервиса переводов включает:
Пример lazy-loading:
i18next.loadNamespaces(['auth'])
Это уменьшает объём первичной загрузки и ускоряет рендер интерфейса.
Сервис переводов в i18next поддерживает расширение через middleware-подобные плагины:
Каждый слой добавляет функциональность без изменения ядра.
Пример postProcessor:
const uppercase = {
type: 'postProcessor',
process: (value) => value.toUpperCase()
}
i18next.use(uppercase)
В крупных приложениях сервис переводов становится централизованной системой доставки контента, где:
Такой подход делает систему локализации независимой от архитектуры UI и позволяет управлять переводами как отдельным продуктовым слоем.