113 lines
2.9 KiB
TypeScript
113 lines
2.9 KiB
TypeScript
// Type definitions
|
|
interface LocalizationResource {
|
|
texts: Record<string, string>
|
|
baseResources: string[]
|
|
}
|
|
|
|
interface LocalizationState {
|
|
resources: Record<string, LocalizationResource>
|
|
}
|
|
|
|
interface LocalizationKey {
|
|
key: string
|
|
defaultValue?: string
|
|
}
|
|
|
|
const getBaseResources = (state: LocalizationState, resourceNames: string[]): Record<string, string> => {
|
|
if (!resourceNames.length) {
|
|
return {}
|
|
}
|
|
|
|
// [{}, {}, {}]
|
|
const texts = resourceNames.map((resourceName: string) => {
|
|
const resource = state.resources[resourceName]
|
|
return {
|
|
...resource.texts,
|
|
...getBaseResources(state, resource.baseResources),
|
|
}
|
|
})
|
|
|
|
return Object.assign({}, ...texts)
|
|
}
|
|
|
|
export const setLocalization = (state: LocalizationState): Record<string, Record<string, string>> => {
|
|
const values: Record<string, Record<string, string>> = {}
|
|
Object.entries(state.resources).forEach(([key, value]) => {
|
|
values[key] = {
|
|
...value.texts,
|
|
...getBaseResources(state, value.baseResources),
|
|
}
|
|
})
|
|
|
|
return values
|
|
}
|
|
|
|
// 🔑 Interpolation helper
|
|
const interpolate = (text: string, params: Record<string, string | number>) => {
|
|
if (!params || typeof params !== 'object') return text
|
|
|
|
return Object.entries(params).reduce((acc, [key, value]) => {
|
|
const pattern = new RegExp(`{{\\s*${key}\\s*}}`, 'g')
|
|
return acc.replace(pattern, String(value))
|
|
}, text)
|
|
}
|
|
|
|
export const getLocalization = (
|
|
texts: Record<string, Record<string, string>>,
|
|
defaultResourceName: string | undefined,
|
|
key: string | LocalizationKey,
|
|
params?: Record<string, string | number>
|
|
): string => {
|
|
let keyString = ''
|
|
let defaultValue = ''
|
|
|
|
if (typeof key === 'string') {
|
|
keyString = key || ''
|
|
} else {
|
|
defaultValue = key.defaultValue || ''
|
|
keyString = key.key
|
|
}
|
|
|
|
const keys = keyString.split('::')
|
|
const warn = (message: string) => {
|
|
if (import.meta.env.DEV) console.warn(message)
|
|
}
|
|
|
|
if (keys.length < 2) {
|
|
warn('The localization source separator (::) not found.')
|
|
return defaultValue || keyString
|
|
}
|
|
if (!texts) return defaultValue || keys[1]
|
|
|
|
const sourceName = keys[0] || defaultResourceName
|
|
const sourceKey = keys[1]
|
|
|
|
if (sourceName === '_') {
|
|
return defaultValue || sourceKey
|
|
}
|
|
|
|
if (!sourceName) {
|
|
warn('Localization source name is not specified and the defaultResourceName was not defined!')
|
|
return defaultValue || sourceKey
|
|
}
|
|
|
|
const source = texts[sourceName]
|
|
if (!source) {
|
|
warn('Could not find localization source: ' + sourceName)
|
|
return defaultValue || sourceKey
|
|
}
|
|
|
|
let localization = source[sourceKey]
|
|
if (typeof localization === 'undefined') {
|
|
return defaultValue || sourceKey
|
|
}
|
|
|
|
if (typeof localization !== 'string') localization = ''
|
|
|
|
// ✅ Interpolation using the helper function
|
|
if (localization && params && typeof params === 'object') {
|
|
localization = interpolate(localization, params)
|
|
}
|
|
|
|
return localization || defaultValue || keyString
|
|
}
|