Add internationalization support with astro-i18next integration
- Implemented astro-i18next for multi-language support, including English, Dutch, and Italian. - Configured default locale and language fallback settings. - Defined routes for localized content in the configuration. - Updated package.json and package-lock.json to include new dependencies for i18next and related plugins.
This commit is contained in:
169
node_modules/i18next-http-backend/lib/index.js
generated
vendored
Normal file
169
node_modules/i18next-http-backend/lib/index.js
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
import { makePromise } from './utils.js'
|
||||
import request from './request.js'
|
||||
|
||||
const getDefaults = () => {
|
||||
return {
|
||||
loadPath: '/locales/{{lng}}/{{ns}}.json',
|
||||
addPath: '/locales/add/{{lng}}/{{ns}}',
|
||||
parse: data => JSON.parse(data),
|
||||
stringify: JSON.stringify,
|
||||
parsePayload: (namespace, key, fallbackValue) => ({ [key]: fallbackValue || '' }),
|
||||
parseLoadPayload: (languages, namespaces) => undefined,
|
||||
request,
|
||||
reloadInterval: typeof window !== 'undefined' ? false : 60 * 60 * 1000,
|
||||
customHeaders: {},
|
||||
queryStringParams: {},
|
||||
crossDomain: false, // used for XmlHttpRequest
|
||||
withCredentials: false, // used for XmlHttpRequest
|
||||
overrideMimeType: false, // used for XmlHttpRequest
|
||||
requestOptions: { // used for fetch
|
||||
mode: 'cors',
|
||||
credentials: 'same-origin',
|
||||
cache: 'default'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Backend {
|
||||
constructor (services, options = {}, allOptions = {}) {
|
||||
this.services = services
|
||||
this.options = options
|
||||
this.allOptions = allOptions
|
||||
this.type = 'backend'
|
||||
this.init(services, options, allOptions)
|
||||
}
|
||||
|
||||
init (services, options = {}, allOptions = {}) {
|
||||
this.services = services
|
||||
this.options = { ...getDefaults(), ...(this.options || {}), ...options }
|
||||
this.allOptions = allOptions
|
||||
if (this.services && this.options.reloadInterval) {
|
||||
const timer = setInterval(() => this.reload(), this.options.reloadInterval)
|
||||
if (typeof timer === 'object' && typeof timer.unref === 'function') timer.unref()
|
||||
}
|
||||
}
|
||||
|
||||
readMulti (languages, namespaces, callback) {
|
||||
this._readAny(languages, languages, namespaces, namespaces, callback)
|
||||
}
|
||||
|
||||
read (language, namespace, callback) {
|
||||
this._readAny([language], language, [namespace], namespace, callback)
|
||||
}
|
||||
|
||||
_readAny (languages, loadUrlLanguages, namespaces, loadUrlNamespaces, callback) {
|
||||
let loadPath = this.options.loadPath
|
||||
if (typeof this.options.loadPath === 'function') {
|
||||
loadPath = this.options.loadPath(languages, namespaces)
|
||||
}
|
||||
|
||||
loadPath = makePromise(loadPath)
|
||||
|
||||
loadPath.then(resolvedLoadPath => {
|
||||
if (!resolvedLoadPath) return callback(null, {})
|
||||
const url = this.services.interpolator.interpolate(resolvedLoadPath, { lng: languages.join('+'), ns: namespaces.join('+') })
|
||||
this.loadUrl(url, callback, loadUrlLanguages, loadUrlNamespaces)
|
||||
})
|
||||
}
|
||||
|
||||
loadUrl (url, callback, languages, namespaces) {
|
||||
const lng = (typeof languages === 'string') ? [languages] : languages
|
||||
const ns = (typeof namespaces === 'string') ? [namespaces] : namespaces
|
||||
// parseLoadPayload — default undefined
|
||||
const payload = this.options.parseLoadPayload(lng, ns)
|
||||
this.options.request(this.options, url, payload, (err, res) => {
|
||||
if (res && ((res.status >= 500 && res.status < 600) || !res.status)) return callback('failed loading ' + url + '; status code: ' + res.status, true /* retry */)
|
||||
if (res && res.status >= 400 && res.status < 500) return callback('failed loading ' + url + '; status code: ' + res.status, false /* no retry */)
|
||||
if (!res && err && err.message) {
|
||||
const errorMessage = err.message.toLowerCase()
|
||||
// for example:
|
||||
// Chrome: "Failed to fetch"
|
||||
// Firefox: "NetworkError when attempting to fetch resource."
|
||||
// Safari: "Load failed"
|
||||
const isNetworkError = [
|
||||
'failed',
|
||||
'fetch',
|
||||
'network',
|
||||
'load'
|
||||
].find((term) => errorMessage.indexOf(term) > -1)
|
||||
if (isNetworkError) {
|
||||
return callback('failed loading ' + url + ': ' + err.message, true /* retry */)
|
||||
}
|
||||
}
|
||||
if (err) return callback(err, false)
|
||||
|
||||
let ret, parseErr
|
||||
try {
|
||||
if (typeof res.data === 'string') {
|
||||
ret = this.options.parse(res.data, languages, namespaces)
|
||||
} else { // fallback, which omits calling the parse function
|
||||
ret = res.data
|
||||
}
|
||||
} catch (e) {
|
||||
parseErr = 'failed parsing ' + url + ' to json'
|
||||
}
|
||||
if (parseErr) return callback(parseErr, false)
|
||||
callback(null, ret)
|
||||
})
|
||||
}
|
||||
|
||||
create (languages, namespace, key, fallbackValue, callback) {
|
||||
// If there is a falsey addPath, then abort -- this has been disabled.
|
||||
if (!this.options.addPath) return
|
||||
if (typeof languages === 'string') languages = [languages]
|
||||
const payload = this.options.parsePayload(namespace, key, fallbackValue)
|
||||
let finished = 0
|
||||
const dataArray = []
|
||||
const resArray = []
|
||||
languages.forEach(lng => {
|
||||
let addPath = this.options.addPath
|
||||
if (typeof this.options.addPath === 'function') {
|
||||
addPath = this.options.addPath(lng, namespace)
|
||||
}
|
||||
const url = this.services.interpolator.interpolate(addPath, { lng, ns: namespace })
|
||||
|
||||
this.options.request(this.options, url, payload, (data, res) => {
|
||||
// TODO: if res.status === 4xx do log
|
||||
finished += 1
|
||||
dataArray.push(data)
|
||||
resArray.push(res)
|
||||
if (finished === languages.length) {
|
||||
if (typeof callback === 'function') callback(dataArray, resArray)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
reload () {
|
||||
const { backendConnector, languageUtils, logger } = this.services
|
||||
const currentLanguage = backendConnector.language
|
||||
if (currentLanguage && currentLanguage.toLowerCase() === 'cimode') return // avoid loading resources for cimode
|
||||
|
||||
const toLoad = []
|
||||
const append = (lng) => {
|
||||
const lngs = languageUtils.toResolveHierarchy(lng)
|
||||
lngs.forEach(l => {
|
||||
if (toLoad.indexOf(l) < 0) toLoad.push(l)
|
||||
})
|
||||
}
|
||||
|
||||
append(currentLanguage)
|
||||
|
||||
if (this.allOptions.preload) this.allOptions.preload.forEach((l) => append(l))
|
||||
|
||||
toLoad.forEach(lng => {
|
||||
this.allOptions.ns.forEach(ns => {
|
||||
backendConnector.read(lng, ns, 'read', null, null, (err, data) => {
|
||||
if (err) logger.warn(`loading namespace ${ns} for language ${lng} failed`, err)
|
||||
if (!err && data) logger.log(`loaded namespace ${ns} for language ${lng}`, data)
|
||||
|
||||
backendConnector.loaded(`${lng}|${ns}`, err, data)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Backend.type = 'backend'
|
||||
|
||||
export default Backend
|
Reference in New Issue
Block a user