@proveanything/smartlinks
Version:
Official JavaScript/TypeScript SDK for the Smartlinks API
288 lines (209 loc) • 6.49 kB
Markdown
# Internationalization (i18n) System
This document explains the i18n system for SmartLinks apps, covering URL-based language selection, static translations, and dynamic overrides.
## Overview
The i18n system supports:
- **URL parameter language selection** (`?lang=de`) - Ideal for iframe embedding
- **Static translations** in JSON files - Fast, no API calls
- **Dynamic overrides** via SmartLinks appConfig - Customer-configurable
- **Type-safe translation keys** - Compile-time safety
- **Widget support** - Translations can be passed to embedded widgets
## Quick Start
### Using Translations in Components
```typescript
import { useLanguage } from '@/i18n';
export const MyComponent = () => {
const { t, lang } = useLanguage();
return (
<div>
<h1>{t('public.title')}</h1>
<p>{t('public.description')}</p>
<small>Language: {lang}</small>
</div>
);
};
```
### With Parameter Interpolation
```typescript
const { t } = useLanguage();
// Translation: "Hello, {{name}}!"
t('greeting', { name: 'John' }); // "Hello, John!"
```
## Language Detection Priority
The system detects language from multiple sources (in order):
| Priority | Source | Example |
|----------|--------|---------|
| 1 | URL parameter | `?lang=de` |
| 2 | localStorage | `smartlinks-lang` key |
| 3 | Browser language | `navigator.language` |
| 4 | Default | `en` |
For iframe apps, the SmartLinks platform passes the language via URL parameter.
## File Structure
```text
src/i18n/
├── index.ts # Main exports
├── LanguageContext.tsx # React context + provider
├── types.ts # TypeScript types
└── locales/
├── en.json # English translations
├── de.json # German translations
└── fr.json # French translations
```
## Adding New Translations
### 1. Add the Key to Types
```typescript
// src/i18n/types.ts
export type TranslationKey =
| 'common.loading'
| 'common.error'
| 'myFeature.title' // Add new key
| 'myFeature.description';
```
### 2. Add Translations to All Locales
```json
// src/i18n/locales/en.json
{
"myFeature.title": "My Feature",
"myFeature.description": "Description of my feature"
}
// src/i18n/locales/de.json
{
"myFeature.title": "Meine Funktion",
"myFeature.description": "Beschreibung meiner Funktion"
}
```
### 3. Use in Components
```typescript
const { t } = useLanguage();
return <h1>{t('myFeature.title')}</h1>;
```
## Adding New Languages
### 1. Create the Locale File
```json
// src/i18n/locales/es.json
{
"common.loading": "Cargando...",
"common.error": "Algo salió mal",
// ... all other keys
}
```
### 2. Import in LanguageContext
```typescript
// src/i18n/LanguageContext.tsx
import es from './locales/es.json';
const staticTranslations: Record<string, PartialTranslations> = {
en: en as PartialTranslations,
de: de as PartialTranslations,
fr: fr as PartialTranslations,
es: es as PartialTranslations, // Add new language
};
const SUPPORTED_LANGUAGES = ['en', 'de', 'fr', 'es']; // Add to list
```
## Dynamic Translations (SmartLinks appConfig)
For customer-configurable translations, store them in SmartLinks appConfig:
### Config Structure
```json
{
"i18n": {
"supportedLanguages": ["en", "de"],
"defaultLanguage": "en",
"translations": {
"en": {
"public.title": "Custom Brand Title",
"public.description": "Custom brand description"
},
"de": {
"public.title": "Benutzerdefinierter Markentitel",
"public.description": "Benutzerdefinierte Markenbeschreibung"
}
}
}
}
```
### Loading Dynamic Translations
```typescript
import { useCollectionAppConfig } from '@/hooks/useSmartLinksData';
import { LanguageProvider } from '@/i18n';
const App = () => {
const { data: config } = useCollectionAppConfig(collectionId, appId);
return (
<LanguageProvider dynamicTranslations={config?.i18n?.translations}>
<MyApp />
</LanguageProvider>
);
};
```
Dynamic translations override static ones, so customers can customize specific strings while inheriting defaults.
## Widgets
Widgets receive language context via props rather than React context (since they may run outside the provider).
### Widget Props
```typescript
interface SmartLinksWidgetProps {
// ... other props
lang?: string;
translations?: Record<string, string>;
}
```
### Using in Widgets
```typescript
import { createTranslator } from '@/i18n';
export const MyWidget: React.FC<SmartLinksWidgetProps> = ({
lang = 'en',
translations = {},
...props
}) => {
const t = createTranslator(lang, translations);
return <div>{t('widget.title')}</div>;
};
```
The `createTranslator` function creates a standalone translation function that doesn't require React context.
## URL Examples
```
# English (default)
/#/?collectionId=abc&appId=pamphlet
# German
/#/?collectionId=abc&appId=pamphlet&lang=de
# French
/#/?collectionId=abc&appId=pamphlet&lang=fr
```
## Best Practices
1. **Use dot notation** for key namespacing: `category.subcategory.key`
2. **Keep translations flat** - avoid nested objects in locale files
3. **Add keys to types.ts first** - ensures type safety
4. **Provide fallbacks** - English is always the fallback language
5. **Test all languages** - Use `?lang=xx` to switch during development
## API Reference
### `useLanguage()`
Hook to access language context.
```typescript
const {
lang, // Current language code
setLang, // Function to change language
t, // Translation function
supportedLanguages // Array of supported language codes
} = useLanguage();
```
### `createTranslator(lang, overrides)`
Creates a standalone translation function for widgets.
```typescript
const t = createTranslator('de', { 'custom.key': 'Custom value' });
t('common.loading'); // "Laden..."
t('custom.key'); // "Custom value"
```
### `LanguageProvider`
React provider component.
```typescript
<LanguageProvider dynamicTranslations={optionalOverrides}>
<App />
</LanguageProvider>
```