All files / app/i18n locales.ts

97.43% Statements 38/39
100% Branches 10/10
100% Functions 4/4
100% Lines 30/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 10253x     53x     53x     53x     53x                                                                     4x 4x   4x 3x 3x 3x   2x             4x 4x             4x     136x               17x 962x 962x 962x 962x   962x 878x 442x 85x 29x     702x 702x     243x 243x    
import { WeblateLanguage, weblateToISOLocale } from "./weblate";
 
// The name of the cookie storing the current locale.
export const LOCALE_COOKIE_NAME = "NEXT_LOCALE";
 
// Final fallback locale if none other matches. Always available.
export const DEFAULT_LOCALE = "en";
 
// Locales which don't rely on translation progress.
export const ALWAYS_AVAILABLE_LOCALES = ["en"];
 
// Autonym = a language name as written in its own language.
export const LOCALE_AUTONYMS: Record<string, string> = {
  ca: "Català",
  cs: "Čeština",
  de: "Deutsch",
  en: "English",
  es: "Español",
  fr: "Français",
  he: "עברית",
  hi: "हिन्दी",
  hu: "Magyar",
  it: "Italiano",
  ja: "日本語",
  "nb-NO": "Norsk (bokmål)",
  nl: "Nederlands",
  pl: "Polski",
  pt: "Português (Portugal)",
  "pt-BR": "Português (Brasil)",
  ru: "Русский",
  sv: "Svenska",
  tr: "Türkçe",
  uk: "Українська",
  "zh-Hans": "中文(简体)",
  "zh-Hant": "中文(繁體)",
};
 
export interface LocaleInfo {
  code: string;
  autonym: string;
  stringAvailabilityPercent: number;
}
 
/**
 * Gets the locales supported by our app based on Weblate-reported language stats,
 * and including always-available locales.
 */
export function getLocaleInfos(weblateLanguages: WeblateLanguage[]): LocaleInfo[] {
  const locales: Record<string, LocaleInfo> = {};
 
  for (const language of weblateLanguages) {
    const code = weblateToISOLocale(language.code);
    const autonym = LOCALE_AUTONYMS[code];
    if (!autonym) continue;
 
    locales[code] = {
      code,
      autonym,
      stringAvailabilityPercent: language.translated_percent,
    };
  }
 
  for (const code of ALWAYS_AVAILABLE_LOCALES) {
    locales[code] = {
      code,
      autonym: LOCALE_AUTONYMS[code],
      stringAvailabilityPercent: 100,
    };
  }
 
  return Object.values(locales);
}
 
export enum LocaleReadiness {
  JustStarted,
  EarlyStage,
  Midway,
  AlmostDone,
  Complete,
}
 
export function getLocaleReadiness(stringAvailabilityPercent: number): LocaleReadiness {
  const EARLY_STAGE_PERCENTAGE = 20;
  const MIDWAY_PERCENTAGE = 50;
  const ALMOST_DONE_PERCENTAGE = 80;
  const COMPLETE_PERCENTAGE = 100;
 
  if (stringAvailabilityPercent >= COMPLETE_PERCENTAGE) return LocaleReadiness.Complete;
  if (stringAvailabilityPercent >= ALMOST_DONE_PERCENTAGE) return LocaleReadiness.AlmostDone;
  if (stringAvailabilityPercent >= MIDWAY_PERCENTAGE) return LocaleReadiness.Midway;
  if (stringAvailabilityPercent >= EARLY_STAGE_PERCENTAGE) return LocaleReadiness.EarlyStage;
  return LocaleReadiness.JustStarted;
}
 
export function isLocaleProductionReady(locale: LocaleInfo): boolean {
  return getLocaleReadiness(locale.stringAvailabilityPercent) >= LocaleReadiness.AlmostDone;
}
 
export function isLocaleSelectable(locale: LocaleInfo): boolean {
  return getLocaleReadiness(locale.stringAvailabilityPercent) >= LocaleReadiness.Midway;
}