@shelchin/svelte-i18n
Version:
The last Svelte i18n library you'll ever need. Type-safe, AI-powered, zero-config.
91 lines (90 loc) • 3.55 kB
JavaScript
import { detectBrowserLanguage as detectBrowserLang } from './browser-detection.js';
export function getNestedValue(obj, path) {
const result = path
.split('.')
.reduce((current, key) => current?.[key], obj);
return result === undefined ? null : result;
}
export function interpolate(template, params = {}, config = {}) {
const prefix = config?.prefix || '{';
const suffix = config?.suffix || '}';
const regex = new RegExp(`${escapeRegex(prefix)}([^${escapeRegex(suffix)}]+)${escapeRegex(suffix)}`, 'g');
return template.replace(regex, (match, key) => {
const value = params[key.trim()];
return value !== undefined ? String(value) : match;
});
}
export function pluralize(template, count, locale = 'en', rules) {
const parts = template.split('|').map((s) => s.trim());
if (parts.length === 1)
return parts[0];
const pluralRule = rules?.[locale] || defaultPluralRule;
const index = Math.min(pluralRule(count), parts.length - 1);
return parts[index] || parts[parts.length - 1];
}
function defaultPluralRule(count) {
if (count === 0)
return 0;
if (count === 1)
return 0;
return 1;
}
function escapeRegex(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
export function validateSchema(translations, schema, path = '') {
const errors = [];
for (const key in schema) {
const fullPath = path ? `${path}.${key}` : key;
const schemaValue = schema[key];
const translationValue = translations?.[key];
if (translationValue === undefined) {
errors.push(`Missing translation: ${fullPath}`);
}
else if (Array.isArray(schemaValue)) {
// Handle array validation
if (!Array.isArray(translationValue)) {
errors.push(`Type mismatch at ${fullPath}: expected array, got ${typeof translationValue}`);
}
else if (schemaValue.length !== translationValue.length) {
errors.push(`Array length mismatch at ${fullPath}: expected ${schemaValue.length} items, got ${translationValue.length}`);
}
}
else if (typeof schemaValue === 'object' && schemaValue !== null) {
if (typeof translationValue !== 'object' || translationValue === null) {
errors.push(`Type mismatch at ${fullPath}: expected object, got ${typeof translationValue}`);
}
else {
errors.push(...validateSchema(translationValue, schemaValue, fullPath));
}
}
else if (typeof schemaValue === 'string' && typeof translationValue !== 'string') {
errors.push(`Type mismatch at ${fullPath}: expected string, got ${typeof translationValue}`);
}
}
return errors;
}
export function detectBrowserLanguage() {
const browserLang = detectBrowserLang();
if (browserLang) {
return browserLang.split('-')[0];
}
return null;
}
export function mergeTranslations(base, override) {
const result = { ...base };
for (const key in override) {
const overrideValue = override[key];
const baseValue = base[key];
if (typeof overrideValue === 'object' &&
typeof baseValue === 'object' &&
!Array.isArray(overrideValue) &&
!Array.isArray(baseValue)) {
result[key] = mergeTranslations(baseValue, overrideValue);
}
else {
result[key] = overrideValue;
}
}
return result;
}