CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-formatjs--intl

Internationalize JS apps with APIs to format dates, numbers, and strings, including pluralization and handling translations.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

utility-functions.mddocs/

Utility Functions

Cache management, configuration utilities, and performance optimization helpers. Provides infrastructure functions for managing formatter instances, configuration processing, and memory optimization.

Capabilities

createIntlCache Function

Creates a cache object for storing formatter instances to prevent memory leaks and improve performance.

/**
 * Create cache for formatter instances to prevent memory leaks
 * @returns Empty cache object with all formatter storage initialized
 */
function createIntlCache(): IntlCache;

interface IntlCache {
  /** DateTimeFormat instances keyed by serialized options */
  dateTime: Record<string, DateTimeFormat>;
  /** NumberFormat instances keyed by serialized options */
  number: Record<string, Intl.NumberFormat>;
  /** IntlMessageFormat instances keyed by serialized options */
  message: Record<string, IntlMessageFormat>;
  /** RelativeTimeFormat instances keyed by serialized options */
  relativeTime: Record<string, Intl.RelativeTimeFormat>;
  /** PluralRules instances keyed by serialized options */
  pluralRules: Record<string, Intl.PluralRules>;
  /** ListFormat instances keyed by serialized options */
  list: Record<string, IntlListFormat>;
  /** DisplayNames instances keyed by serialized options */
  displayNames: Record<string, DisplayNames>;
}

Usage Examples:

import { createIntlCache, createIntl } from "@formatjs/intl";

// Create shared cache for multiple intl instances
const cache = createIntlCache();

const intlEn = createIntl({
  locale: 'en-US',
  messages: { /* ... */ }
}, cache);

const intlEs = createIntl({
  locale: 'es-ES', 
  messages: { /* ... */ }
}, cache);

// Both instances share formatter caches for memory efficiency
// Formatters with same options are reused across instances

// Cache inspection (for debugging)
console.log('Cached formatters:', {
  dateTime: Object.keys(cache.dateTime).length,
  number: Object.keys(cache.number).length,
  message: Object.keys(cache.message).length
});

// Manual cache clearing (rarely needed)
const clearCache = (cache: IntlCache) => {
  cache.dateTime = {};
  cache.number = {};
  cache.message = {};
  cache.relativeTime = {};
  cache.pluralRules = {};
  cache.list = {};
  cache.displayNames = {};
};

createFormatters Function

Creates memoized formatter instances with cache integration for optimal performance.

/**
 * Create intl formatters and populate cache
 * @param cache - Optional explicit cache to prevent leaking memory
 * @returns Formatters object with memoized factory functions
 */
function createFormatters(cache?: IntlCache): Formatters;

interface Formatters {
  /** Memoized DateTimeFormat factory */
  getDateTimeFormat(locale?: string | string[], options?: Intl.DateTimeFormatOptions): DateTimeFormat;
  /** Memoized NumberFormat factory */
  getNumberFormat(locales?: string | string[], opts?: NumberFormatOptions): Intl.NumberFormat;
  /** Memoized MessageFormat factory */
  getMessageFormat(message: string, locales?: string | string[], overrideFormats?: Partial<Formats>, opts?: IntlMessageFormatOptions): IntlMessageFormat;
  /** Memoized RelativeTimeFormat factory */
  getRelativeTimeFormat(locales?: string | string[], options?: Intl.RelativeTimeFormatOptions): Intl.RelativeTimeFormat;
  /** Memoized PluralRules factory */
  getPluralRules(locales?: string | string[], options?: Intl.PluralRulesOptions): Intl.PluralRules;
  /** Memoized ListFormat factory */
  getListFormat(locales?: string | string[], options?: IntlListFormatOptions): IntlListFormat;
  /** Memoized DisplayNames factory */
  getDisplayNames(locales?: string | string[], options?: DisplayNamesOptions): DisplayNames;
}

Usage Examples:

import { createFormatters, createIntlCache } from "@formatjs/intl";

// Create formatters with default cache
const formatters = createFormatters();

// Create formatters with explicit cache
const explicitCache = createIntlCache();
const cachedFormatters = createFormatters(explicitCache);

// Use formatters directly
const numberFormatter = formatters.getNumberFormat('en-US', {
  style: 'currency',
  currency: 'USD'
});

const formatted = numberFormatter.format(1234.56);
// Result: "$1,234.56"

// Subsequent calls with same parameters return cached instance
const sameFormatter = formatters.getNumberFormat('en-US', {
  style: 'currency', 
  currency: 'USD'
});
// sameFormatter === numberFormatter (same instance)

// Different parameters create new cached instance
const euroFormatter = formatters.getNumberFormat('en-US', {
  style: 'currency',
  currency: 'EUR'
});
// Different instance, also cached

// Date formatter usage
const dateFormatter = formatters.getDateTimeFormat('en-US', {
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

const formattedDate = dateFormatter.format(new Date());
// Result: "March 15, 2024"

filterProps Function

Filters object properties based on an allowlist with optional defaults.

/**
 * Filter properties from objects with allowlist and defaults
 * @param props - Source object to filter properties from
 * @param allowlist - Array of allowed property names
 * @param defaults - Optional default values for missing properties
 * @returns New object with only allowed properties
 */
function filterProps<T extends Record<string, any>, K extends string>(
  props: T,
  allowlist: Array<K>,
  defaults?: Partial<T>
): Pick<T, K>;

Usage Examples:

import { filterProps } from "@formatjs/intl";

// Basic property filtering
const sourceObject = {
  locale: 'en-US',
  currency: 'USD',
  style: 'currency',
  unwantedProp: 'remove me',
  anotherBadProp: 123
};

const allowedProps = ['locale', 'currency', 'style'] as const;
const filtered = filterProps(sourceObject, allowedProps);
// Result: { locale: 'en-US', currency: 'USD', style: 'currency' }

// With defaults for missing properties
const incompleteObject = {
  locale: 'en-US',
  currency: 'USD'
  // missing 'style'
};

const withDefaults = filterProps(
  incompleteObject,
  allowedProps,
  { style: 'decimal' }
);
// Result: { locale: 'en-US', currency: 'USD', style: 'decimal' }

// Real-world usage in number formatting options
const NUMBER_FORMAT_OPTIONS = [
  'style', 'currency', 'unit', 'useGrouping',
  'minimumIntegerDigits', 'minimumFractionDigits',
  'maximumFractionDigits', 'minimumSignificantDigits',
  'maximumSignificantDigits'
] as const;

const userOptions = {
  style: 'currency',
  currency: 'USD',
  minimumFractionDigits: 2,
  localeMatcher: 'best fit', // Not in allowlist
  invalidOption: 'remove'    // Not in allowlist
};

const cleanOptions = filterProps(userOptions, NUMBER_FORMAT_OPTIONS);
// Result: { style: 'currency', currency: 'USD', minimumFractionDigits: 2 }

// TypeScript provides type safety
const typedFiltered: Pick<typeof sourceObject, 'locale' | 'currency' | 'style'> = 
  filterProps(sourceObject, allowedProps);

getNamedFormat Function

Retrieves named format configurations from custom formats with error handling.

/**
 * Get named format from configuration with error handling
 * @param formats - Custom formats object
 * @param type - Format type (number, date, time, relative)
 * @param name - Named format identifier
 * @param onError - Error handler for missing formats
 * @returns Format options or undefined if not found
 */
function getNamedFormat<T extends keyof CustomFormats>(
  formats: CustomFormats,
  type: T,
  name: string,
  onError: OnErrorFn
): NumberFormatOptions | Intl.DateTimeFormatOptions | Intl.RelativeTimeFormatOptions | undefined;

Usage Examples:

import { getNamedFormat } from "@formatjs/intl";

// Custom formats configuration
const customFormats = {
  number: {
    currency: { style: 'currency', currency: 'USD' },
    percentage: { style: 'percent', minimumFractionDigits: 1 },
    compact: { notation: 'compact' }
  },
  date: {
    short: { month: 'numeric', day: 'numeric', year: '2-digit' },
    long: { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }
  },
  relative: {
    short: { numeric: 'auto', style: 'short' },
    verbose: { numeric: 'always', style: 'long' }
  }
};

const onError = (error: any) => console.error('Format error:', error);

// Retrieve existing named formats
const currencyFormat = getNamedFormat(customFormats, 'number', 'currency', onError);
// Result: { style: 'currency', currency: 'USD' }

const longDateFormat = getNamedFormat(customFormats, 'date', 'long', onError);
// Result: { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }

const shortRelativeFormat = getNamedFormat(customFormats, 'relative', 'short', onError);
// Result: { numeric: 'auto', style: 'short' }

// Handle missing named formats
const missingFormat = getNamedFormat(customFormats, 'number', 'nonexistent', onError);
// Result: undefined
// Also calls onError with UnsupportedFormatterError

// Real-world usage in formatting functions
const formatWithNamedFormat = (
  value: number,
  formatName: string,
  locale: string = 'en-US'
) => {
  const formatOptions = getNamedFormat(
    customFormats,
    'number',
    formatName,
    onError
  );
  
  if (formatOptions) {
    return new Intl.NumberFormat(locale, formatOptions).format(value);
  }
  
  // Fallback to basic formatting
  return new Intl.NumberFormat(locale).format(value);
};

const price = formatWithNamedFormat(29.99, 'currency');
// Result: "$29.99"

const percentage = formatWithNamedFormat(0.156, 'percentage');
// Result: "15.6%"

DEFAULT_INTL_CONFIG Constant

Default configuration object providing sensible defaults for intl instances.

const DEFAULT_INTL_CONFIG: Pick<
  ResolvedIntlConfig<any>,
  | 'fallbackOnEmptyString'
  | 'formats'
  | 'messages'
  | 'timeZone'
  | 'defaultLocale'
  | 'defaultFormats'
  | 'onError'
  | 'onWarn'
>;

Usage Examples:

import { DEFAULT_INTL_CONFIG, createIntl } from "@formatjs/intl";

// Inspect default configuration
console.log('Default config:', DEFAULT_INTL_CONFIG);
// Result: {
//   formats: {},
//   messages: {},
//   timeZone: undefined,
//   defaultLocale: 'en',
//   defaultFormats: {},
//   fallbackOnEmptyString: true,
//   onError: [Function: defaultErrorHandler],
//   onWarn: [Function: defaultWarnHandler]
// }

// Use defaults with custom overrides
const intl = createIntl({
  ...DEFAULT_INTL_CONFIG,
  locale: 'es-ES',
  messages: {
    greeting: 'Hola {name}'
  },
  // Other defaults are preserved
});

// Override specific defaults
const customIntl = createIntl({
  locale: 'en-US',
  messages: { /* ... */ },
  // Override default error handling
  onError: (error) => {
    // Custom error handling
    console.error('Custom error handler:', error);
    
    // Send to monitoring service
    if (process.env.NODE_ENV === 'production') {
      sendErrorToMonitoring(error);
    }
  },
  // Keep other defaults by not specifying them
});

// Access individual default handlers
const defaultErrorHandler = DEFAULT_INTL_CONFIG.onError;
const defaultWarnHandler = DEFAULT_INTL_CONFIG.onWarn;

// Create wrapper with enhanced defaults
const createIntlWithDefaults = (config: Partial<IntlConfig>) => {
  return createIntl({
    ...DEFAULT_INTL_CONFIG,
    defaultLocale: 'en-US', // Override default
    fallbackOnEmptyString: false, // Override default
    ...config
  });
};

Performance Optimization Utilities

Additional utilities for optimizing intl performance in production applications.

Usage Examples:

// Cache warming for critical formatters
const warmCache = (cache: IntlCache, locales: string[]) => {
  const formatters = createFormatters(cache);
  
  // Pre-warm common formatters
  locales.forEach(locale => {
    // Common number formats
    formatters.getNumberFormat(locale, { style: 'decimal' });
    formatters.getNumberFormat(locale, { style: 'currency', currency: 'USD' });
    formatters.getNumberFormat(locale, { style: 'percent' });
    
    // Common date formats
    formatters.getDateTimeFormat(locale, { dateStyle: 'short' });
    formatters.getDateTimeFormat(locale, { timeStyle: 'short' });
    
    // Common relative time formats
    formatters.getRelativeTimeFormat(locale, { numeric: 'auto' });
    
    // Common plural rules
    formatters.getPluralRules(locale, { type: 'cardinal' });
  });
};

// Usage in app initialization
const appCache = createIntlCache();
warmCache(appCache, ['en-US', 'es-ES', 'fr-FR', 'de-DE']);

// Cache metrics for monitoring
const getCacheMetrics = (cache: IntlCache) => {
  return {
    dateTime: Object.keys(cache.dateTime).length,
    number: Object.keys(cache.number).length,
    message: Object.keys(cache.message).length,
    relativeTime: Object.keys(cache.relativeTime).length,
    pluralRules: Object.keys(cache.pluralRules).length,
    list: Object.keys(cache.list).length,
    displayNames: Object.keys(cache.displayNames).length,
    total: Object.keys(cache.dateTime).length +
           Object.keys(cache.number).length +
           Object.keys(cache.message).length +
           Object.keys(cache.relativeTime).length +
           Object.keys(cache.pluralRules).length +
           Object.keys(cache.list).length +
           Object.keys(cache.displayNames).length
  };
};

// Memory management for long-running applications
const createManagedCache = (maxSize: number = 1000) => {
  const cache = createIntlCache();
  let totalEntries = 0;
  
  const trackingCache = new Proxy(cache, {
    set(target, prop, value) {
      if (typeof prop === 'string' && prop in target) {
        const category = target[prop as keyof IntlCache];
        if (typeof value === 'object' && value !== null) {
          Object.keys(value).forEach(key => {
            if (!(key in category)) {
              totalEntries++;
            }
          });
          
          // Clear oldest entries if over limit
          if (totalEntries > maxSize) {
            const categories = Object.keys(target) as (keyof IntlCache)[];
            categories.forEach(cat => {
              const categoryCache = target[cat];
              const keys = Object.keys(categoryCache);
              if (keys.length > maxSize / categories.length) {
                // Clear half the entries (simple LRU approximation)
                keys.slice(0, Math.floor(keys.length / 2)).forEach(k => {
                  delete categoryCache[k];
                  totalEntries--;
                });
              }
            });
          }
        }
      }
      return Reflect.set(target, prop, value);
    }
  });
  
  return trackingCache;
};

Error Handler Utilities

Utilities for managing error handling in intl operations.

Usage Examples:

// Enhanced error handler with categorization
const createEnhancedErrorHandler: () => OnErrorFn = () => {
  const errorCounts = new Map<string, number>();
  
  return (error) => {
    const errorType = error.constructor.name;
    errorCounts.set(errorType, (errorCounts.get(errorType) || 0) + 1);
    
    // Log with context
    console.error(`[Intl Error ${error.code}] ${errorType}:`, error.message);
    
    // Handle specific error types
    switch (error.code) {
      case 'MISSING_TRANSLATION':
        // Report missing translations to translation management system
        reportMissingTranslation(error);
        break;
        
      case 'MISSING_DATA':
        // Handle missing locale data
        console.warn('Consider adding polyfill for:', error.message);
        break;
        
      case 'FORMAT_ERROR':
        // Handle format errors
        console.error('Format error details:', error);
        break;
    }
    
    // Metrics reporting
    if (errorCounts.get(errorType)! % 100 === 0) {
      console.warn(`${errorType} has occurred ${errorCounts.get(errorType)} times`);
    }
  };
};

// Silent error handler for production
const createSilentErrorHandler = (): OnErrorFn => {
  return (error) => {
    // Only log in development
    if (process.env.NODE_ENV === 'development') {
      console.error('Intl error:', error);
    }
    
    // Send to monitoring in production
    if (process.env.NODE_ENV === 'production') {
      // Send to error monitoring service
      sendToErrorMonitoring({
        type: 'intl_error',
        code: error.code,
        message: error.message,
        stack: error.stack
      });
    }
  };
};

const reportMissingTranslation = (error: any) => {
  // Implementation for reporting to translation management
  console.warn('Missing translation:', error.descriptor?.id);
};

const sendToErrorMonitoring = (errorData: any) => {
  // Implementation for error monitoring service
  console.log('Sending to monitoring:', errorData);
};

docs

date-time-formatting.md

display-name-formatting.md

index.md

intl-instance.md

list-formatting.md

message-formatting.md

number-formatting.md

relative-time-pluralization.md

utility-functions.md

tile.json