lang-provider
v1.0.3
Published
A flexible React provider for managing multilingual applications with **TypeScript** support.
Downloads
89
Readme
lang-provider
A flexible React provider for managing multilingual applications with TypeScript support.
Installation
npm install lang-provider
Quick Start
Follow these steps to get started with using lang-provider
:
// Define your translations
const translations = {
sv: {
welcome: "Välkommen",
portfolio: "Min portfölj"
},
en: {
welcome: "Welcome",
portfolio: "My Portfolio"
}
};
// Create typed config
const config = {
defaultLanguage: "sv" as const, // Type assertion for literal type
languages: ["sv", "en"] as const, // Type assertion for tuple type
translations
};
// Infer types from config
type AppLanguages = typeof config.languages[number]; // Results in "sv" | "en"
type TextKeys = keyof typeof config.translations.sv & string; // Results in "welcome" | "portfolio"
const App = () => (
<LangProvider<AppLanguages, TextKeys> config={config}>
<TextProvider<AppLanguages, TextKeys> config={config}>
<YourApp />
</TextProvider>
</LangProvider>
);
Configuration
Translation File Structure
{
"sv": {
"welcome": "Välkommen",
"portfolio": "Min portfölj"
},
"en": {
"welcome": "Welcome",
"portfolio": "My Portfolio"
}
}
Config Interface
interface LanguageConfig<L extends string, K extends string> {
defaultLanguage: L; // The fallback language
languages: readonly L[] | L[]; // Array of supported languages
translations: Record<L, Record<K, string>>; // Translations map
}
Hooks
useLang
Returns language control functions and state:
const {
language, // Current active language
switchLanguage, // Function to change language: (lang: L) => void
availableLanguages // Array of supported languages: L[]
} = useLang();
useText
Returns text management functions:
const {
getText, // Get translated text: (key: K) => string
setTexts // Update translations: (texts: Record<L, Record<K, string>>) => void
} = useText();
Usage Examples
Switching Languages
import { useLang } from "lang-provider";
const LanguageSelector = () => {
const { switchLanguage, availableLanguages, language } = useLang();
return (
<div>
{availableLanguages.map(lang => (
<button
key={lang}
onClick={() => switchLanguage(lang)}
disabled={lang === language}
>
{lang.toUpperCase()}
</button>
))}
</div>
);
};
Displaying Translated Text
import { useText } from "lang-provider";
const Welcome = () => {
const { getText } = useText();
return <h1>{getText('welcome')}</h1>;
};
Update Translations
The setTexts
function from useText
allows you to update translations at runtime. Here's a complete example:
import { useText } from "lang-provider";
import type { LanguageConfig } from "lang-provider";
// Define your types
type Languages = "en" | "sv";
type TextKeys = "welcome" | "portfolio";
const TranslationUpdater = () => {
const { setTexts } = useText();
const updateTranslations = async () => {
try {
// Fetch new translations from your API/source
const response = await fetch('https://api.example.com/translations');
const newTranslations: LanguageConfig<Languages, TextKeys>['translations'] = await response.json();
// Validate the structure matches your types
if (isValidTranslation(newTranslations)) {
setTexts(newTranslations);
}
} catch (error) {
console.error('Failed to update translations:', error);
}
};
// Type guard to validate translation structure
const isValidTranslation = (
data: unknown
): data is Record<Languages, Record<TextKeys, string>> => {
if (!data || typeof data !== 'object') return false;
const requiredLanguages: Languages[] = ['en', 'sv'];
const requiredKeys: TextKeys[] = ['welcome', 'portfolio'];
return requiredLanguages.every(lang =>
typeof data[lang] === 'object' &&
requiredKeys.every(key =>
typeof data[lang][key] === 'string'
)
);
};
return <button onClick={updateTranslations}>Update Translations</button>;
};
Your translation API should return data in this format:
{
"sv": {
"welcome": "Välkommen",
"portfolio": "Min portfölj"
},
"en": {
"welcome": "Welcome",
"portfolio": "My Portfolio"
}
}
The setTexts
function will:
- Update the internal translation state
- Trigger a re-render of components using getText
- Preserve type safety with the provided generic types
TypeScript Support
Language Type
type AppLanguages = "en" | "sv"; // Your supported languages
Text Keys
type TextKeys = "welcome" | "portfolio"; // Your translation keys
Provider Types
<LangProvider<AppLanguages, TextKeys> config={config}>
<TextProvider<AppLanguages, TextKeys> config={config}>
Best Practices
- Keep translations in separate JSON files
- Use TypeScript for type safety
- Use namespaced keys (e.g.,
common.welcome
) - Always provide fallback texts in default language
- Load translations asynchronously for large applications
- Use constant assertions for better type inference
API Reference
LangProvider
Props
config
:LanguageConfig
objectchildren
: React nodes
TextProvider
Props
config
:LanguageConfig
objectchildren
: React nodes
LanguageConfig
defaultLanguage
: Default language codelanguages
: Array of supported language codestranslations
: Translation key-value pairs
Hook Returns
useLang
language
: Current language codeswitchLanguage
: (lang: L) => voidavailableLanguages
: L[]
useText
getText
: (key: K) => stringsetTexts
: (texts: Record<L, Record<K, string>>) => void