CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-intl

Internationalize React apps with components and APIs for formatting dates, numbers, strings, pluralization and 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

inject-intl.mddocs/

Legacy HOC Support

Higher-order component for injecting internationalization functionality into class components, providing backward compatibility with legacy codebases.

Capabilities

injectIntl HOC

Higher-order component that injects an intl prop containing the IntlShape object into wrapped components.

/**
 * Higher-order component for injecting intl prop into class components
 * Provides backward compatibility for legacy React class components
 * @param WrappedComponent - Component to wrap with intl functionality
 * @param options - Configuration options for injection behavior
 * @returns Enhanced component with intl prop injected
 */
function injectIntl<
  IntlPropName extends string = 'intl',
  P extends WrappedComponentProps<IntlPropName> = WrappedComponentProps<any>
>(
  WrappedComponent: React.ComponentType<P>,
  options?: InjectIntlOptions<IntlPropName>
): React.ComponentType<WithIntlProps<P>>;

interface InjectIntlOptions<IntlPropName extends string = 'intl'> {
  /** Name of the prop to inject (defaults to 'intl') */
  intlPropName?: IntlPropName;
  /** Whether to forward refs to the wrapped component */
  forwardRef?: boolean;
  /** Whether to enforce IntlProvider context existence */
  enforceContext?: boolean;
}

Usage Examples:

import React from 'react';
import { injectIntl, WrappedComponentProps } from 'react-intl';

// Class component with intl prop
class LegacyComponent extends React.Component<WrappedComponentProps> {
  render() {
    const { intl } = this.props;
    
    const greeting = intl.formatMessage({
      id: 'greeting',
      defaultMessage: 'Hello!'
    });
    
    const formattedDate = intl.formatDate(new Date());
    
    return (
      <div>
        <h1>{greeting}</h1>
        <p>Today is {formattedDate}</p>
      </div>
    );
  }
}

// Inject intl prop
const EnhancedLegacyComponent = injectIntl(LegacyComponent);

// Usage
<EnhancedLegacyComponent />

Custom Prop Name

Customize the name of the injected prop for flexibility or conflict avoidance.

/**
 * Inject intl with custom prop name
 */
function injectIntl<IntlPropName extends string>(
  WrappedComponent: React.ComponentType<{ [K in IntlPropName]: IntlShape } & any>,
  options: { intlPropName: IntlPropName }
): React.ComponentType<any>;

Usage Examples:

import React from 'react';
import { injectIntl } from 'react-intl';

// Component expecting custom prop name
interface Props {
  i18n: IntlShape;
  name: string;
}

class CustomPropComponent extends React.Component<Props> {
  render() {
    const { i18n, name } = this.props;
    
    const welcome = i18n.formatMessage(
      { id: 'welcome', defaultMessage: 'Welcome {name}!' },
      { name }
    );
    
    return <div>{welcome}</div>;
  }
}

// Inject with custom prop name
const EnhancedCustomComponent = injectIntl(CustomPropComponent, {
  intlPropName: 'i18n'
});

// Usage
<EnhancedCustomComponent name="Alice" />

Ref Forwarding

Enable ref forwarding for accessing wrapped component instances.

/**
 * Inject intl with ref forwarding support
 */
function injectIntl<P>(
  WrappedComponent: React.ComponentType<P>,
  options: { forwardRef: true }
): React.ForwardRefExoticComponent<WithIntlProps<P> & React.RefAttributes<any>>;

Usage Examples:

import React from 'react';
import { injectIntl, WrappedComponentProps } from 'react-intl';

class RefForwardingComponent extends React.Component<WrappedComponentProps> {
  private inputRef = React.createRef<HTMLInputElement>();
  
  focus = () => {
    this.inputRef.current?.focus();
  };
  
  render() {
    const { intl } = this.props;
    const placeholder = intl.formatMessage({
      id: 'search.placeholder',
      defaultMessage: 'Search...'
    });
    
    return (
      <input 
        ref={this.inputRef}
        placeholder={placeholder}
        type="text"
      />
    );
  }
}

// Enable ref forwarding
const EnhancedRefComponent = injectIntl(RefForwardingComponent, {
  forwardRef: true
});

// Usage with ref
function ParentComponent() {
  const componentRef = React.useRef<RefForwardingComponent>(null);
  
  const handleFocus = () => {
    componentRef.current?.focus();
  };
  
  return (
    <div>
      <EnhancedRefComponent ref={componentRef} />
      <button onClick={handleFocus}>Focus Input</button>
    </div>
  );
}

Context Enforcement

Control whether to enforce IntlProvider context existence.

/**
 * Inject intl with optional context enforcement
 */
function injectIntl<P>(
  WrappedComponent: React.ComponentType<P>,
  options?: { enforceContext?: boolean }
): React.ComponentType<WithIntlProps<P>>;

Usage Examples:

import React from 'react';
import { injectIntl, WrappedComponentProps } from 'react-intl';

class OptionalIntlComponent extends React.Component<WrappedComponentProps> {
  render() {
    const { intl } = this.props;
    
    // intl might be null if no IntlProvider exists
    if (!intl) {
      return <div>No internationalization available</div>;
    }
    
    const message = intl.formatMessage({
      id: 'optional.message',
      defaultMessage: 'Optional message'
    });
    
    return <div>{message}</div>;
  }
}

// Disable context enforcement
const FlexibleComponent = injectIntl(OptionalIntlComponent, {
  enforceContext: false
});

// Can be used outside IntlProvider without throwing
<FlexibleComponent />

Complex HOC Patterns

Advanced patterns for complex component hierarchies and prop manipulation.

Usage Examples:

import React from 'react';
import { injectIntl, WrappedComponentProps } from 'react-intl';

// Component with additional props
interface ComponentProps extends WrappedComponentProps {
  title: string;
  count: number;
  onAction: () => void;
}

class ComplexComponent extends React.Component<ComponentProps> {
  render() {
    const { intl, title, count, onAction } = this.props;
    
    const formattedTitle = intl.formatMessage({
      id: 'component.title',
      defaultMessage: '{title} ({count})'
    }, { title, count });
    
    const actionLabel = intl.formatMessage({
      id: 'action.label',
      defaultMessage: 'Take Action'
    });
    
    return (
      <div>
        <h2>{formattedTitle}</h2>
        <button onClick={onAction}>{actionLabel}</button>
      </div>
    );
  }
}

// Enhanced component maintains original prop interface
const EnhancedComplexComponent = injectIntl(ComplexComponent);

// Usage maintains type safety
<EnhancedComplexComponent 
  title="Dashboard"
  count={5}
  onAction={() => console.log('Action!')}
/>

// HOC composition
const withLogging = <P extends object>(Component: React.ComponentType<P>) => {
  return class extends React.Component<P> {
    componentDidMount() {
      console.log('Component mounted');
    }
    
    render() {
      return <Component {...this.props} />;
    }
  };
};

// Compose HOCs
const EnhancedWithLogging = withLogging(
  injectIntl(ComplexComponent)
);

Migration from Class to Hooks

Pattern for gradually migrating from HOC to hooks.

Usage Examples:

import React from 'react';
import { injectIntl, useIntl, WrappedComponentProps } from 'react-intl';

// Original class component
class LegacyClassComponent extends React.Component<WrappedComponentProps> {
  render() {
    const { intl } = this.props;
    return <div>{intl.formatMessage({ id: 'message' })}</div>;
  }
}

// Migration wrapper using hooks
function ModernWrapper() {
  const intl = useIntl();
  
  // Pass intl as prop to legacy component
  return <LegacyClassComponent intl={intl} />;
}

// Gradually replace class components
function FullyModernComponent() {
  const intl = useIntl();
  const message = intl.formatMessage({ id: 'message' });
  return <div>{message}</div>;
}

Types

/**
 * Props interface for components that receive intl prop
 */
type WrappedComponentProps<IntlPropName extends string = 'intl'> = {
  [K in IntlPropName]: IntlShape;
};

/**
 * Utility type for components using injectIntl HOC
 * Removes intl prop from component props interface
 */
type WithIntlProps<P> = Omit<P, keyof WrappedComponentProps> & {
  forwardedRef?: React.Ref<any>;
};

/**
 * Distributed omit utility for union types
 */
type DistributedOmit<T, K extends PropertyKey> = T extends unknown
  ? Omit<T, K>
  : never;

/**
 * Options for configuring injectIntl behavior
 */
interface InjectIntlOptions<IntlPropName extends string = 'intl'> {
  intlPropName?: IntlPropName;
  forwardRef?: boolean;
  enforceContext?: boolean;
}

Migration Guidelines

From injectIntl to useIntl

// Before: HOC pattern
class OldComponent extends React.Component<WrappedComponentProps> {
  render() {
    const { intl } = this.props;
    return <div>{intl.formatMessage({ id: 'hello' })}</div>;
  }
}
const EnhancedOldComponent = injectIntl(OldComponent);

// After: Hooks pattern
function NewComponent() {
  const intl = useIntl();
  return <div>{intl.formatMessage({ id: 'hello' })}</div>;
}

Maintaining Backward Compatibility

// Hybrid approach for gradual migration
interface Props {
  name: string;
}

// Modern implementation
function ModernImplementation({ name }: Props) {
  const intl = useIntl();
  const greeting = intl.formatMessage(
    { id: 'greeting', defaultMessage: 'Hello {name}!' },
    { name }
  );
  return <div>{greeting}</div>;
}

// Legacy wrapper for existing usage
const LegacyWrapper = injectIntl(
  class extends React.Component<Props & WrappedComponentProps> {
    render() {
      const { intl, ...props } = this.props;
      return (
        <IntlProvider locale={intl.locale} messages={intl.messages}>
          <ModernImplementation {...props} />
        </IntlProvider>
      );
    }
  }
);

// Export both for flexibility
export { ModernImplementation as MyComponent, LegacyWrapper as MyComponentLegacy };

docs

date-time.md

hooks.md

index.md

inject-intl.md

messages.md

number-list.md

provider.md

tile.json