{"_id":"@astacinco/rn-i18n","name":"@astacinco/rn-i18n","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@astacinco/rn-i18n","version":"0.1.0","description":"Internationalization with adapter pattern - swap i18n providers without code changes","main":"src/index.ts","types":"src/index.ts","repository":{"type":"git","url":"git+https://github.com/jrudydev/rn-toolkit.git","directory":"packages/i18n"},"publishConfig":{"access":"public"},"author":{"name":"Spark Labs","email":"hello@sparklabs.dev"},"homepage":"https://github.com/jrudydev/rn-toolkit#readme","scripts":{"typecheck":"tsc --noEmit","test":"jest"},"peerDependencies":{"react":">=17.0.0","react-native":">=0.64.0"},"optionalDependencies":{"i18next":">=21.0.0","react-i18next":">=11.0.0","expo-localization":">=14.0.0"},"devDependencies":{"@types/react":"^18.0.0","react":"^18.2.0","react-native":"^0.72.0","typescript":"^5.0.0"},"keywords":["react-native","i18n","internationalization","localization","adapter-pattern","accessibility","a11y","translations"],"license":"MIT","_id":"@astacinco/rn-i18n@0.1.0","gitHead":"6fa965625ad344ec91902e42e12b2000624373ea","bugs":{"url":"https://github.com/jrudydev/rn-toolkit/issues"},"_nodeVersion":"20.19.6","_npmVersion":"10.8.2","dist":{"integrity":"sha512-dSqOLG/p530qU1KcXWIr8stYuJ03Uv+zzhPhAsa8QN22s3qwqMDEMaILSrM/czQgbEcHrCABz6sgawEwwf9ftA==","shasum":"8720f7bbe42ef79be7fe0ae3b1f85ee536293ee6","tarball":"https://registry.npmjs.org/@astacinco/rn-i18n/-/rn-i18n-0.1.0.tgz","fileCount":17,"unpackedSize":75582,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDu8XsloXwkQ3KUtTJqNhk0zceSFrZ/EoxBohMhriFxOwIgZvIJhzYT8hQxINa/UVPzaW32waPQ1vu3rVR9Hy/dCsQ="}]},"_npmUser":{"name":"sparklabs343","email":"gomez.rudy@gmail.com"},"directories":{},"maintainers":[{"name":"sparklabs343","email":"gomez.rudy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/rn-i18n_0.1.0_1772793178559_0.211416756914391"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-06T10:32:58.459Z","0.1.0":"2026-03-06T10:32:58.714Z","modified":"2026-03-06T10:32:58.947Z"},"maintainers":[{"name":"sparklabs343","email":"gomez.rudy@gmail.com"}],"description":"Internationalization with adapter pattern - swap i18n providers without code changes","homepage":"https://github.com/jrudydev/rn-toolkit#readme","keywords":["react-native","i18n","internationalization","localization","adapter-pattern","accessibility","a11y","translations"],"repository":{"type":"git","url":"git+https://github.com/jrudydev/rn-toolkit.git","directory":"packages/i18n"},"author":{"name":"Spark Labs","email":"hello@sparklabs.dev"},"bugs":{"url":"https://github.com/jrudydev/rn-toolkit/issues"},"license":"MIT","readme":"# @astacinco/rn-i18n\n\nInternationalization with **adapter pattern** for React Native - swap i18n providers without code changes.\n\n## Features\n\n- **Adapter Pattern** - Swap i18n providers (react-i18next, react-intl, etc.) without changing app code\n- **Built-in Adapters** - ReactI18next, Console (debug), NoOp (testing)\n- **Translation** - Key-based translation with interpolation and pluralization\n- **Formatting** - Date, number, currency, and percentage formatting\n- **RTL Support** - Automatic RTL detection for Arabic, Hebrew, etc.\n- **Accessibility** - Screen reader announcements and a11y settings\n- **TypeScript** - Full type safety with comprehensive interfaces\n\n## Installation\n\n```bash\nnpm install @astacinco/rn-i18n\n```\n\n### For react-i18next (recommended for production)\n\n```bash\nnpm install i18next react-i18next\n```\n\n## Quick Start\n\n### 1. Choose your adapter\n\n```tsx\nimport {\n  I18nProvider,\n  ReactI18nextAdapter,\n  ConsoleAdapter,\n  NoOpAdapter,\n} from '@astacinco/rn-i18n';\n\n// Production: react-i18next\nconst adapter = new ReactI18nextAdapter({ i18n: i18nextInstance });\n\n// Development: Console logging\nconst adapter = new ConsoleAdapter({\n  defaultLocale: 'en',\n  resources: translations,\n});\n\n// Testing: No-op (silent)\nconst adapter = new NoOpAdapter();\n```\n\n### 2. Wrap your app\n\n```tsx\nfunction App() {\n  const adapter = new ConsoleAdapter({\n    defaultLocale: 'en-US',\n    resources: {\n      'en-US': {\n        common: {\n          welcome: 'Welcome, {{name}}!',\n          items: { one: '1 item', other: '{{count}} items' },\n        },\n      },\n      'es-ES': {\n        common: {\n          welcome: '¡Bienvenido, {{name}}!',\n          items: { one: '1 artículo', other: '{{count}} artículos' },\n        },\n      },\n    },\n    supportedLocales: ['en-US', 'es-ES'],\n  });\n\n  return (\n    <I18nProvider adapter={adapter} config={{ debug: __DEV__ }}>\n      <MyApp />\n    </I18nProvider>\n  );\n}\n```\n\n### 3. Use in components\n\n```tsx\nimport { useTranslation, useLocale, useAccessibility } from '@astacinco/rn-i18n';\n\nfunction HomeScreen() {\n  // Translation\n  const { t, tp } = useTranslation();\n\n  // Locale & formatting\n  const { locale, isRTL, formatCurrency, setLocale } = useLocale();\n\n  // Accessibility\n  const { announce, isScreenReaderEnabled } = useAccessibility();\n\n  return (\n    <View style={{ direction: isRTL ? 'rtl' : 'ltr' }}>\n      <Text>{t('common.welcome', { name: 'John' })}</Text>\n      <Text>{tp('common.items', 5)}</Text>\n      <Text>{formatCurrency(99.99, 'USD')}</Text>\n\n      <Button\n        title=\"Switch to Spanish\"\n        onPress={() => setLocale('es-ES')}\n      />\n    </View>\n  );\n}\n```\n\n## API Reference\n\n### I18nProvider\n\nProvider component that wraps your app with i18n context.\n\n```tsx\n<I18nProvider\n  adapter={adapter}        // Required: I18n adapter\n  config={{\n    defaultLocale: 'en',   // Default locale\n    fallbackLocale: 'en',  // Fallback when translation missing\n    debug: false,          // Enable debug logging\n    logMissingTranslations: false,  // Warn on missing keys\n    onMissingTranslation: (key, locale) => string, // Custom handler\n  }}\n>\n  {children}\n</I18nProvider>\n```\n\n### Built-in Adapters\n\n#### ConsoleAdapter (Development)\n\n```typescript\nimport { ConsoleAdapter } from '@astacinco/rn-i18n';\n\nconst adapter = new ConsoleAdapter({\n  prefix: '[I18n]',        // Log prefix\n  timestamps: true,        // Include timestamps\n  defaultLocale: 'en',     // Initial locale\n  resources: {             // Translation resources\n    en: {\n      common: {\n        hello: 'Hello',\n        greeting: 'Hello, {{name}}!',\n        items: { one: '1 item', other: '{{count}} items' },\n      },\n    },\n  },\n  supportedLocales: ['en', 'es', 'fr'],\n});\n```\n\n#### NoOpAdapter (Testing)\n\n```typescript\nimport { NoOpAdapter } from '@astacinco/rn-i18n';\n\nconst adapter = new NoOpAdapter();\n// Returns keys as-is, useful for testing\n```\n\n#### ReactI18nextAdapter (Production)\n\n```typescript\nimport { ReactI18nextAdapter } from '@astacinco/rn-i18n';\nimport i18n from './i18n'; // Your i18next instance\n\nconst adapter = new ReactI18nextAdapter({\n  i18n,\n  supportedLocales: ['en', 'es', 'fr'],\n});\n```\n\n### Creating Custom Adapters\n\nImplement the `I18nAdapter` interface:\n\n```typescript\nimport type { I18nAdapter } from '@astacinco/rn-i18n';\n\nclass MyCustomAdapter implements I18nAdapter {\n  readonly name = 'custom';\n\n  async initialize() {\n    // Initialize your i18n library\n  }\n\n  translate(key: string, params?: TranslationParams): string {\n    // Return translated string\n  }\n\n  translatePlural(key: string, count: number, params?: TranslationParams): string {\n    // Return plural-aware translation\n  }\n\n  // ... implement all other methods\n}\n```\n\n### Hooks\n\n#### useTranslation\n\nMain hook for translations.\n\n```typescript\nconst {\n  t,          // Translate key: t('common.hello')\n  tp,         // Translate plural: tp('items', 5)\n  hasKey,     // Check key exists: hasKey('common.hello')\n  locale,     // Current locale\n  language,   // Current language code\n  isReady,    // Provider initialized\n} = useTranslation({\n  keyPrefix: 'profile',           // Optional: prefix all keys\n  defaultParams: { app: 'MyApp' }, // Optional: default params\n});\n\n// With prefix\nconst { t } = useTranslation({ keyPrefix: 'profile' });\nt('title');  // Translates 'profile.title'\n```\n\n#### useLocale\n\nLocale management and formatting.\n\n```typescript\nconst {\n  locale,            // Current locale (e.g., 'en-US')\n  language,          // Language code (e.g., 'en')\n  isRTL,             // Is right-to-left\n  supportedLocales,  // Available locales\n  setLocale,         // Change locale\n  formatDate,        // Format date\n  formatRelativeTime, // Format relative time\n  formatNumber,      // Format number\n  formatCurrency,    // Format currency\n  formatPercent,     // Format percentage\n} = useLocale();\n```\n\n#### useAccessibility\n\nAccessibility features.\n\n```typescript\nconst {\n  isScreenReaderEnabled,  // Screen reader active\n  isReduceMotionEnabled,  // Reduce motion preference\n  isBoldTextEnabled,      // Bold text preference\n  fontScale,              // Font scale multiplier\n  announce,               // Announce to screen reader\n  settings,               // Full settings object\n} = useAccessibility();\n\n// Announce action completion\nannounce('Item added to cart', 'polite');\n```\n\n## Formatting Examples\n\n### Dates\n\n```typescript\nconst { formatDate, formatRelativeTime } = useLocale();\n\n// Date styles\nformatDate(new Date(), { dateStyle: 'full' });    // \"Monday, January 15, 2024\"\nformatDate(new Date(), { dateStyle: 'short' });   // \"1/15/24\"\nformatDate(new Date(), { timeStyle: 'short' });   // \"3:30 PM\"\n\n// Relative time\nformatRelativeTime(yesterday);  // \"yesterday\"\nformatRelativeTime(lastWeek);   // \"7 days ago\"\n```\n\n### Numbers & Currency\n\n```typescript\nconst { formatNumber, formatCurrency, formatPercent } = useLocale();\n\nformatNumber(1234.56);                    // \"1,234.56\"\nformatNumber(1234.56, { style: 'decimal', minimumFractionDigits: 2 });\n\nformatCurrency(99.99, 'USD');             // \"$99.99\"\nformatCurrency(99.99, 'EUR');             // \"€99.99\"\n\nformatPercent(0.75);                      // \"75%\"\n```\n\n## RTL Support\n\n```tsx\nfunction RTLAwareComponent() {\n  const { isRTL } = useLocale();\n\n  return (\n    <View style={{\n      flexDirection: isRTL ? 'row-reverse' : 'row',\n      textAlign: isRTL ? 'right' : 'left',\n    }}>\n      <Text>This text respects RTL</Text>\n    </View>\n  );\n}\n```\n\n## Pluralization\n\n```tsx\nconst { tp } = useTranslation();\n\n// In your resources:\n// items: { one: '1 item', other: '{{count}} items' }\n\ntp('items', 0);   // \"0 items\"\ntp('items', 1);   // \"1 item\"\ntp('items', 5);   // \"5 items\"\n```\n\n## Adapter Pattern Benefits\n\nThe adapter pattern allows you to:\n\n1. **Swap providers easily** - Change from react-i18next to react-intl with one line\n2. **Test without real i18n** - Use `NoOpAdapter` or `ConsoleAdapter`\n3. **Debug translations** - Use `ConsoleAdapter` to see all translations\n4. **Create custom adapters** - Build adapters for any i18n service\n\n```typescript\n// Switch providers without changing any component code:\n\n// Before (react-i18next)\n<I18nProvider adapter={new ReactI18nextAdapter({ i18n })}>\n\n// After (custom solution)\n<I18nProvider adapter={new MyCustomAdapter()}>\n\n// Your components don't change at all!\n```\n\n## TypeScript\n\nFull TypeScript support with exported types:\n\n```typescript\nimport type {\n  I18nAdapter,\n  I18nConfig,\n  TranslationParams,\n  PluralForms,\n  DateFormatOptions,\n  NumberFormatOptions,\n  AccessibilitySettings,\n  LocaleConfig,\n} from '@astacinco/rn-i18n';\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-b44659a5b4e89659f0d433c38d80052e"}