import type { TolgeeStaticData } from '@tolgee/svelte' import { env } from '$env/dynamic/private' import { loadAsync } from 'jszip' class TranslationCacheItem { constructor( public translastions: TolgeeStaticData, public timestamp: number, ) {} get isExpired(): boolean { const now = Date.now() const TTL = Number(env.TRANSLATION_CACHE_TTL) if (Number.isNaN(TTL)) return false return now - this.timestamp > TTL * 1000 } } class LanguageService { protected cache: Record = {} async getTranslations( languageCodes: string[], ): Promise> { const languageCodesToFetch = new Set() const result: Record = {} for (const lang of languageCodes) { const cacheItem = this.cache[lang] if (!cacheItem || cacheItem.isExpired) { languageCodesToFetch.add(lang) continue } Object.assign(result, { [lang]: cacheItem.translastions }) } if (languageCodesToFetch.size === 0) { return result } const freshTranslations = await this.fetchTranslations( Array.from(languageCodesToFetch), ) for (const langKey of Object.keys(freshTranslations)) { if (langKey in this.cache) { delete this.cache[langKey] } this.cache[langKey] = new TranslationCacheItem( freshTranslations[langKey], Date.now(), ) result[langKey] = Object.assign(freshTranslations[langKey]) } return result } protected async fetchTranslations(languageCodes: string | string[]) { const url = new URL(`${env.TOLGEE_API_URL}/v2/projects/2/export`) url.searchParams.append('format', 'JSON') url.searchParams.append('zip', 'true') url.searchParams.append('supportArrays', 'true') for (const lang of languageCodes) { url.searchParams.append('languages', lang) } if (!env.TOLGEE_API_KEY) { throw new Error('TOLGEE_API_KEY not set') } const response = await fetch(url, { method: 'GET', headers: { 'X-API-Key': env.TOLGEE_API_KEY, Accept: 'application/*', }, }) const zippedBuffer = await response.arrayBuffer() const zip = await loadAsync(zippedBuffer) const translations: Record = {} for (const [filename, file] of Object.entries(zip.files)) { if (!file.dir && filename.endsWith('.json')) { const content = await file.async('string') const locale = filename.replace('.json', '') translations[locale] = JSON.parse(content) } } return translations } } export const languageService = new LanguageService()