Internationalization (i18n)
Vyuh provides an i18n plugin interface for managing translations across your application. It works alongside Flutter's built-in localization system (MaterialLocalizations, CupertinoLocalizations, etc.) and can integrate with CMS-driven content for dynamic translations.
The i18n plugin is accessible via vyuh.i18n and handles locale management, translation lookups, and locale switching across all features in your application.
Setting Up i18n
Configure the i18n plugin as part of the runApp() call by passing it into the PluginDescriptor:
import 'package:vyuh_core/vyuh_core.dart' as vc;
void main() async {
vc.runApp(
plugins: PluginDescriptor(
i18n: MyI18nPlugin(
supportedLocales: [
Locale('en'),
Locale('es'),
Locale('fr'),
],
defaultLocale: Locale('en'),
),
),
features: () => [...],
);
}The supportedLocales list defines which locales your application supports, and defaultLocale specifies the fallback locale when a requested locale is not available.
INFO
The i18n plugin manages application-level translations. Flutter's built-in MaterialLocalizations and CupertinoLocalizations handle framework-level strings (button labels, date formats, etc.) separately. Both systems work together to provide a fully localized experience.
Using Translations
Once configured, you can access the i18n plugin from anywhere in your application using the vyuh singleton:
// Access the current locale
final locale = vyuh.i18n.currentLocale;
// Switch to a different locale
await vyuh.i18n.setLocale(Locale('es'));
// Get a translated string
final greeting = vyuh.i18n.translate('hello');When setLocale() is called, the framework notifies all features and rebuilds the widget tree so that the UI reflects the new locale.
Feature-Level Translations
Each feature in a Vyuh application can contribute its own set of translations. This keeps translation files modular and co-located with the feature they belong to.
Features declare their supported locales and translation keys as part of their configuration. When the application initializes, the framework aggregates translations from all registered features into the i18n plugin.
final feature = FeatureDescriptor(
name: 'checkout',
title: 'Checkout',
init: () async {
vyuh.i18n.registerTranslations('checkout', {
'en': {
'cart.title': 'Your Cart',
'cart.empty': 'Your cart is empty',
'checkout.button': 'Proceed to Checkout',
},
'es': {
'cart.title': 'Tu Carrito',
'cart.empty': 'Tu carrito esta vacio',
'checkout.button': 'Proceder al Pago',
},
});
},
routes: () async => [...],
);This modular approach means that adding a new feature automatically brings its translations along, and removing a feature cleans up its translation keys.
TIP
Use a dotted naming convention for translation keys (e.g., feature.section.label) to avoid collisions between features and to keep keys organized.
CMS-Driven Translations
One of the advantages of combining i18n with a CMS is the ability to manage translations without code changes. Content stored in the CMS can have locale-specific variants, and the content plugin fetches the appropriate variant based on the current locale.
This workflow looks like:
- Content editors create locale-specific versions of content in the CMS
- The content plugin queries for the variant matching
vyuh.i18n.currentLocale - The correct localized content is rendered in the app
No code changes are needed when adding new translations or supporting additional locales for CMS-driven content. The business team can manage translations directly from the CMS.
INFO
CMS-driven translations are suited for content that changes frequently or is managed by non-developers (marketing copy, product descriptions, announcements). Static UI strings (button labels, form hints) are better handled through code-level translation files.
Creating a Custom i18n Plugin
To create your own i18n plugin, implement the i18n plugin interface from vyuh_core. This allows you to integrate with any translation backend -- JSON files, remote services, or a custom solution.
import 'package:vyuh_core/vyuh_core.dart';
final class JsonI18nPlugin extends I18nPlugin {
final Map<String, Map<String, String>> _translations = {};
Locale _currentLocale;
final List<Locale> supportedLocales;
JsonI18nPlugin({
required this.supportedLocales,
required Locale defaultLocale,
}) : _currentLocale = defaultLocale;
@override
Locale get currentLocale => _currentLocale;
@override
Future<void> setLocale(Locale locale) async {
if (!supportedLocales.contains(locale)) {
throw UnsupportedError('Locale $locale is not supported');
}
_currentLocale = locale;
await _loadTranslations(locale);
}
@override
String translate(String key) {
final localeTranslations = _translations[_currentLocale.languageCode];
return localeTranslations?[key] ?? key;
}
Future<void> _loadTranslations(Locale locale) async {
// Load translations from JSON files, a remote API, or any other source
final data = await _fetchTranslations(locale);
_translations[locale.languageCode] = data;
}
Future<Map<String, String>> _fetchTranslations(Locale locale) async {
// Your implementation here
return {};
}
}Then use your plugin in the runApp() call:
vc.runApp(
plugins: PluginDescriptor(
i18n: JsonI18nPlugin(
supportedLocales: [Locale('en'), Locale('es')],
defaultLocale: Locale('en'),
),
),
features: () => [...],
);Integration with Flutter Localization Delegates
The i18n plugin works alongside Flutter's localization delegates. To ensure that both the Vyuh i18n system and Flutter's built-in localizations are active, set up the localizationsDelegates and supportedLocales in your MaterialApp configuration:
MaterialApp(
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [
Locale('en'),
Locale('es'),
Locale('fr'),
],
locale: vyuh.i18n.currentLocale,
);TIP
Keep the supportedLocales list in your MaterialApp in sync with the locales configured in the i18n plugin. This ensures that both Flutter's framework localizations and your application translations are available for the same set of locales.
Summary
The i18n plugin in the Vyuh Framework provides a structured way to manage translations across a modular application. Each feature can contribute its own translations, the CMS can supply locale-specific content variants, and locale switching propagates across all features automatically. By implementing a custom i18n plugin, you can connect to any translation backend that fits your needs.