@smallstack/svelte-ui
Version:
Tiny library for Svelte 5 and DaisyUI, published as multi entry ESM module and as web components.
101 lines (100 loc) • 3.68 kB
JavaScript
import i18nNext from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import { getContext, setContext } from "svelte";
import { derived, get, writable } from "svelte/store";
export const createI18nStore = (i18nNextOptions) => {
i18nNext.use(LanguageDetector).init({
fallbackLng: "en",
detection: {
order: ["localStorage", "navigator"],
caches: ["localStorage"]
},
interpolation: {
escapeValue: false // not needed for svelte as it escapes by default
},
defaultNS: "translation",
...i18nNextOptions
});
return derived([currentLanguage], () => i18nNext);
};
export function initI18n(i18nNextOptions) {
setContext("i18n", createI18nStore(i18nNextOptions));
}
export function addTranslations(locale, translations) {
i18nNext.addResourceBundle(locale, "translation", translations, true, true);
translationsUpdated.set(true);
}
export async function addTranslationsFromUrl(url) {
// load translations async
await fetch(url).then(async (response) => {
const translations = await response.json();
for (const translation of translations.elements) {
const keyValueMap = translation.translations.reduce((acc, curr) => {
acc[curr.key] = curr.value;
return acc;
}, {});
i18nNext.addResourceBundle(translation.language, "translation", keyValueMap, true, true);
}
translationsUpdated.set(true);
});
}
export function getI18n() {
const i18nFromContext = getContext("i18n");
if (!i18nFromContext)
throw new Error("i18n store not found on context, did you forget to call initI18n?");
return i18nFromContext;
}
export const currentLanguage = writable("de");
i18nNext.on("languageChanged", (lng) => {
const formattedLanguage = lng.split("-")[0];
currentLanguage.set(formattedLanguage);
});
export const availableLanguages = writable(["de", "en"]);
export const translationsUpdated = writable(undefined);
export function translateInlineTranslation(translation, options = { useFallback: true }) {
if (!translation)
return undefined;
if (typeof translation === "string")
return translation;
if (!options.language)
options.language = get(currentLanguage);
const t = translation[options.language];
if (t)
return t;
if (options.useFallback !== true)
return "";
return Object.values(translation)[0];
}
/** translates inline translations */
export const it = derived(currentLanguage, () => translateInlineTranslation);
/** based on the input either inline translations or keys are getting translated */
export const t = derived(currentLanguage, (currentLanguage) => {
return (key, options) => {
if (typeof key === "string")
return i18nNext.t(key, options);
else if (isTranslatable(key))
return i18nNext.t(key.key, {
...options,
...key.replacers
});
else
return translateInlineTranslation(key, { language: currentLanguage });
};
});
export function isInlineTranslation(obj) {
if (!(obj instanceof Object))
return false;
for (const [key, value] of Object.entries(obj))
if (typeof key !== "string" || typeof value !== "string")
return false;
return true;
}
export function isTranslatable(obj) {
if (!(obj instanceof Object))
return false;
if (typeof obj.key !== "string")
return false;
if (obj.replacers && !(obj.replacers instanceof Object))
return false;
return true;
}