native-document-i18n
v0.0.2
Published
A modern internationalization package designed specifically for the NativeDocument framework, featuring automatic translation key scanner and reactive observable support.
Readme
I18n Package for NativeDocument Framework
A modern internationalization package designed specifically for the NativeDocument framework, featuring automatic translation key scanner and reactive observable support.
Features
- Automatic Scanner: Automatically detects missing translation keys in your locale files
- NativeDocument Integration: Seamless integration with NativeDocument's reactive system
- Built on i18next: Leverages the power and flexibility of i18next
- Flexible Configuration: Configuration via JSON file
- Built-in CLI: Command-line tool to scan your projects
Installation
npm install native-document-i18nConfiguration
Create an i18n.scanner.config.json file at your project root:
{
"scan": {
"dir": "src",
"extensions": ["js", "tsx"]
},
"locales": "src/locales",
"save": "src/locales-reports"
}Configuration Options
| Option | Type | Description | Default |
|--------|------|-------------|---------|
| scan.dir | string | Directory to scan | "src" |
| scan.extensions | array | File extensions to analyze | ["js"] |
| locales | string | Path to locale files directory | - |
| save | string | Directory to save reports (optional) | - |
Locale Files Structure
Organize your translation files as follows:
src/
└── locales/
├── en.json
├── fr.json
└── es.jsonExample locale file (en.json):
{
"welcome": "Welcome",
"user.greeting": "Hello {{name}}!",
"button.save": "Save",
"error.required": "This field is required"
}Usage
1. Service Initialization
import { I18nService } from 'native-document-i18n';
// Load your translation resources
const resources = {
en: { translation: require('./locales/en.json') },
fr: { translation: require('./locales/fr.json') }
};
// Initialize the service
I18nService.init(resources);2. Using Translations
Classic Method
import { I18nService } from 'native-document-i18n';
// Simple translation
const message = I18nService.tr('welcome');
// Translation with parameters
const greeting = I18nService.tr('user.greeting', { name: 'John' });With NativeDocument Observables
import { tr } from 'native-document-i18n';
// Reactive translation
const welcomeMessage = tr('welcome');
console.log(welcomeMessage.val()); // "Welcome"
// Translation with observable parameters
import { Observable } from 'native-document';
const userName = Observable('John');
const greeting = tr('user.greeting', { name: userName });
// Translation updates automatically when userName changes
userName.set('Marie'); // greeting updates automaticallyString Prototype Method
// String prototype extension
const message = 'welcome'.tr();
const greeting = 'user.greeting'.tr({ name: 'John' });3. Language Switching
import { I18nService } from 'native-document-i18n';
// Listen to language changes
I18nService.current.subscribe((lang) => {
console.log('Current language:', lang);
});
// Change language
await I18nService.use('fr');Scanner CLI
The package includes a CLI tool to automatically scan your files and detect missing keys.
Using the Scanner
# If installed globally
npx native-document-i18n
# Or directly with node
node node_modules/native-document-i18n/bin/scanner.jsHow the Scanner Works
- File Analysis: Scans all files according to configuration
- Key Extraction: Searches for
tr()calls in your code - Comparison: Compares with your existing locale files
- Report: Generates a report of missing keys
Example Output
:: scan locales
-- en : 3 keys are absent in locale file.
-- fr : 5 keys are absent in locale file.
-- save result to locales-reports/en.absent.jsonGenerated Report Format
The scanner generates JSON files with missing keys:
{
"user.profile": "user.profile",
"button.cancel": "button.cancel",
"error.network": "error.network"
}Environment Variables
The package uses the following environment variables:
| Variable | Description | Default |
|----------|-------------|---------|
| VITE_LOCALE | Default language | "en" |
| VITE_FALLBACK_LANGUE | Fallback language | "en" |
| VITE_ENV | Environment (enables debug if development) | - |
Detection Patterns
The scanner automatically searches for these patterns in your code:
// Automatically detected
tr('simple.key')
tr("double.quotes")
tr('key.with.params', { param: value })
// Not detected (dynamic keys)
const key = 'dynamic.key';
tr(key) // ⚠️ Not detected by scannerRecommended Workflow
- Development: Use
tr()in your code - Scan: Run the scanner to detect missing keys
- Translation: Add missing translations to your locale files
- Validation: Re-scan to verify everything is complete
Integration Examples
With a NativeDocument Component
import { tr } from 'native-document-i18n';
const { Observable } = NativeDocument;
const { Div, H1, P, Input, Button } = NativeDocument.elements;
const WelcomeComponent = () => {
const userName = Observable('John');
const welcome = tr('welcome');
const greeting = tr('user.greeting', { name: userName });
return Div([
H1(welcome),
P(greeting),
Input({
type: "text",
value: userName,
placeholder: "Enter your name"
}),
Button("Change Language").nd.onClick(() => {
I18nService.use('fr');
})
]);
};Build Script with Automatic Scan
{
"scripts": {
"i18n:scan": "node node_modules/native-document-i18n/bin/scanner.js"
}
}Advanced Example with Store Integration
import { tr } from 'native-document-i18n';
import { Store, Observable } from 'native-document';
import { Div, H1, P, Button, ForEach } from 'native-document/elements';
// Create global store for user preferences
Store.create("userPrefs", {
language: "en",
theme: "light"
});
const MultiLanguageApp = () => {
const userPrefs = Store.use("userPrefs");
const menuItems = Observable([
{ id: 'home', key: 'menu.home' },
{ id: 'profile', key: 'menu.profile' },
{ id: 'settings', key: 'menu.settings' }
]);
return Div([
H1(tr('app.title')),
// Language selector
Div([
Button("English").nd.onClick(() => {
I18nService.use('en');
userPrefs.set(current => ({...current, language: 'en'}));
}),
Button("Français").nd.onClick(() => {
I18nService.use('fr');
userPrefs.set(current => ({...current, language: 'fr'}));
})
]),
// Dynamic menu with translations
ForEach(menuItems, (item) =>
Button(tr(item.key)).nd.onClick(() => {
console.log(`Navigate to ${item.id}`);
})
, 'id')
]);
};
document.body.appendChild(MultiLanguageApp());
import { tr } from 'native-document-i18n';
import { Observable } from 'native-document';
import { Div, H2, P, Button, ShowIf } from 'native-document/elements';
// Reactive translation with language switching
const LanguageSwitcher = () => {
const currentLang = I18nService.current;
return Div([
H2(tr('welcome')),
P(tr('app.description')),
ShowIf(
currentLang.check(lang => lang === 'en'),
Button("Switch to French").nd.onClick(() => I18nService.use('fr'))
),
ShowIf(
currentLang.check(lang => lang === 'fr'),
Button("Switch to English").nd.onClick(() => I18nService.use('en'))
)
]);
};
document.body.appendChild(LanguageSwitcher());Troubleshooting
Scanner doesn't find my keys
- Check that your files have the correct extensions in the configuration
- Make sure you're using string literals (not variables) in
tr()
Translations don't update
- Verify you're using the
tr()function that returns a NativeDocument observable - Ensure your component is properly bound to the observable changes
"Config file not found" error
- Create the
i18n.scanner.config.jsonfile at your project root - Verify you're running the scanner from the correct directory
Contributing
Contributions are welcome! Feel free to open issues or submit pull requests.
License
MIT
