arnaucube
arnaucube/jellyfin-toolsPublic Self-hosted repository
jellyfin-tools/jellyfin-year-review/web/src/lib/i18n.js
jellyfin-year-review/web/src/lib/i18n.jsRaw
 1import translations from './translations.json' with { type: 'json' };
 2
 3// Select one catalog for the entire build, including page language and formatting.
 4if (!Object.hasOwn(translations.languages, translations.language)) {
 5  throw new Error(`Unknown translation language: ${translations.language}`);
 6}
 7const catalog = translations.languages[translations.language];
 8export const locale = catalog.locale;
 9export const direction = catalog.direction;
10
11// Replace named placeholders once, keeping inserted names and titles as plain text.
12export function t(english, values = {}) {
13  const translated = Object.hasOwn(catalog.strings, english) ? catalog.strings[english] : english;
14  return translated.replace(/\{(\w+)\}/g, (placeholder, name) => Object.hasOwn(values, name) ? String(values[name]) : placeholder);
15}
16
17const countedMessages = [
18  '{count} records excluded because media metadata was deleted or unavailable.',
19  '{count} aggregate activity records; records may combine resumed viewing.'
20];
21
22// Review exports contain English messages; translate them without changing stored data.
23export function message(english) {
24  if (!english) return '';
25  for (const template of countedMessages) {
26    const suffix = template.slice('{count}'.length);
27    if (english.endsWith(suffix)) {
28      const count = english.slice(0, -suffix.length);
29      if (/^\d+$/.test(count)) return t(template, { count: new Intl.NumberFormat(locale).format(Number(count)) });
30    }
31  }
32  return t(english);
33}