Get the FREE Ultimate OpenClaw Setup Guide →

nylo-localization

Scanned
npx machina-cli add skill nylo-core/claude-code/nylo-localization --openclaw
Files (1)
SKILL.md
12.1 KB

Nylo Localization

Overview

Nylo v7 provides a JSON-based localization system configured in lib/config/localization.dart. Translation files live in the lang/ directory, and strings are accessed throughout the app using the .tr() extension or the TextTr convenience widget.

When to Use

  • Adding multi-language (i18n) support to a Nylo project
  • Creating or editing JSON translation files
  • Displaying translated text with Text.tr, TextTr, or .tr()
  • Passing dynamic arguments into translated strings
  • Switching languages at runtime (programmatically or via LanguageSwitcher widget)
  • Configuring supported locales, default locale, or fallback locale
  • Handling right-to-left (RTL) languages like Arabic or Hebrew
  • Debugging missing translation keys
  • When NOT to use: For theming or styling text appearance unrelated to language, use nylo-themes instead

Quick Reference

ActionCode / Location
Translation files directorylang/en.json, lang/es.json, etc.
Localization configlib/config/localization.dart
Set default localeDEFAULT_LOCALE=en in .env
Use device localeLOCALE_TYPE=device in .env
Debug missing keysDEBUG_TRANSLATIONS=true in .env
Translate a string"welcome".tr()
Translate with args"greeting".tr(arguments: {"name": "John"})
Translate nested key"navigation.home".tr()
TextTr widgetTextTr("welcome")
TextTr with argsTextTr("greeting", arguments: {"name": "John"})
Switch language (NyPage)changeLanguage('es')
Switch language (anywhere)await NyLocalization.instance.setLanguage(context, language: 'es')
Check if RTLLocalizationConfig.isRtl(languageCode)
Verify key existsNyLocalization.instance.hasTranslation("key")
Get all loaded keysNyLocalization.instance.getAllKeys()
Rebuild env after changesmetro make:env --force

Project Setup

1. Create Language Files

Add JSON files to the lang/ directory at the project root. Each file is named by its locale code:

lang/
  en.json
  es.json
  fr.json
  ar.json

2. Register Assets in pubspec.yaml

flutter:
  assets:
    - lang/en.json
    - lang/es.json
    - lang/fr.json
    - lang/ar.json

3. Configure Environment Variables

In the .env file:

DEFAULT_LOCALE=en
LOCALE_TYPE=locale
DEBUG_TRANSLATIONS=true
VariableValuesPurpose
DEFAULT_LOCALEAny locale code (e.g., en, es)Sets the app's default language
LOCALE_TYPElocale or devicelocale uses DEFAULT_LOCALE; device uses the system language
DEBUG_TRANSLATIONStrue or falseLogs warnings when translation keys are missing

After changing .env, run:

metro make:env --force

4. Configure Supported Locales

In lib/config/localization.dart, define supported locales and the fallback:

class LocalizationConfig {
  static List<Locale> get supportedLocales => [
    Locale('en'),
    Locale('es'),
    Locale('fr'),
    Locale('ar'),
  ];

  static String get fallbackLanguageCode => 'en';
}

The supportedLocales list feeds into Flutter's MaterialApp.supportedLocales. The fallbackLanguageCode is used when a translation key is missing in the active locale, preventing raw keys from being displayed to users.

Translation File Format

Nested Keys with Dot Notation

Translation files are JSON with simple key-value pairs. Use nested objects for organization, accessed with dot notation:

{
  "navigation": {
    "home": "Home",
    "profile": "Profile",
    "settings": "Settings"
  },
  "auth": {
    "login": "Log In",
    "register": "Sign Up",
    "forgot_password": "Forgot Password?"
  }
}

Access: "navigation.home".tr() returns "Home".

Parameterized Strings

Use {{key}} placeholders for dynamic values:

{
  "greeting": "Hello, {{name}}!",
  "item_count": "You have {{total}} items in your cart"
}

Styled Text Templates

Use {{key:text}} syntax for styled/tappable spans. The key stays stable across locales; the text is translated. Integrates with StyledText.template() for styling and tap handlers:

{
  "learn": "Learn {{lang:Languages}}, {{read:Reading}} skills"
}

Using Translations in Widgets

The .tr() Extension

The most common way to display translations:

// Simple translation
Text("welcome".tr())

// With arguments
Text("greeting".tr(arguments: {"name": "Anthony"}))

// Nested keys
Text("navigation.home".tr())

// With arguments on nested keys
Text("item_count".tr(arguments: {"total": "5"}))

The trans() Helper Function

An alternative to .tr(): Text(trans("welcome")) or Text(trans("item_count", arguments: {"total": "5"})).

The TextTr Widget

TextTr is a convenience wrapper around Flutter's Text widget that automatically calls .tr():

// Instead of Text("welcome".tr()), use:
TextTr("welcome")

// With arguments
TextTr("greeting", arguments: {"name": "John"})

// With standard Text parameters
TextTr(
  "welcome",
  style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
  textAlign: TextAlign.center,
  maxLines: 2,
  overflow: TextOverflow.ellipsis,
)

TextTr Styled Constructors

TextTr provides named constructors that automatically apply theme-based text styles:

// Uses Theme.of(context).textTheme.displayLarge
TextTr.displayLarge("page_title")

// Uses Theme.of(context).textTheme.headlineLarge
TextTr.headlineLarge("section_header")

// Uses Theme.of(context).textTheme.bodyLarge
TextTr.bodyLarge("paragraph_text")

// Uses Theme.of(context).textTheme.labelLarge
TextTr.labelLarge("button_label")

Language Switching

Using the LanguageSwitcher Widget

The LanguageSwitcher widget auto-detects languages from your lang/ directory and lets users switch between them. It persists the user's choice across sessions.

Dropdown in AppBar

@override
Widget view(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: TextTr("settings"),
      actions: [
        LanguageSwitcher(),
      ],
    ),
    body: ...
  );
}

Bottom Sheet Modal

// Show language picker as a bottom modal
LanguageSwitcher.showBottomModal(context);

// With custom height
LanguageSwitcher.showBottomModal(context, height: 300);

The bottom sheet displays all available languages with a checkmark on the currently selected one.

Customizing LanguageSwitcher Appearance

LanguageSwitcher(
  iconSize: 28,
  dropdownBgColor: Colors.white,
  elevation: 4,
  borderRadius: BorderRadius.circular(8),
  textStyle: TextStyle(fontSize: 16),
  dropdownBuilder: (Map<String, dynamic> language) {
    return Row(
      children: [
        Icon(Icons.language),
        SizedBox(width: 8),
        Text(language['name']),
      ],
    );
  },
  onLanguageChange: (Map<String, dynamic> language) {
    print('Switched to: ${language['name']}');
  },
)

Programmatic Language Switching

From a NyPage or NyState Widget

// changeLanguage() is available directly in NyPage/NyState
changeLanguage('es');

From Anywhere (Including Controllers)

// Full language switch with UI rebuild
await NyLocalization.instance.setLanguage(context, language: 'es');

// From a controller, optionally prevent state restart
changeLanguage('fr', restartState: false);

// Silent locale switch (no UI rebuild)
NyLocalization.instance.setLocale(locale: Locale('fr'));

Querying Language State

Map<String, dynamic>? lang = await LanguageSwitcher.currentLanguage();
Map<String, String>? data = LanguageSwitcher.getLanguageData("en"); // {"en": "English"}
List<Map<String, String>> all = await LanguageSwitcher.getLanguageList();
await LanguageSwitcher.storeLanguage(object: {"fr": "French"});
await LanguageSwitcher.clearLanguage();

RTL Language Support

Nylo automatically detects RTL languages. The following languages are recognized as RTL: Arabic (ar), Hebrew (he), Persian (fa), Urdu (ur), Yiddish (yi), Pashto (ps), Kurdish (ku), Sindhi (sd), and Dhivehi (dv).

Checking RTL Status

// Static check by language code
bool isRtl = LocalizationConfig.isRtl('ar'); // true

// Runtime check with context
bool isRtl = NyLocalization.instance.isDirectionRTL(context);

NyLocaleHelper Utilities

NyLocaleHelper.isRtlLanguage('ar');             // true
NyLocaleHelper.getTextDirection('ar');           // TextDirection.rtl
NyLocaleHelper.getCurrentLocale(context);        // current Locale
NyLocaleHelper.getLanguageCode(context);         // e.g. "en"
NyLocaleHelper.matchesLocale(context, 'ar');     // bool
NyLocaleHelper.toLocale('en', 'US');             // Locale('en', 'US')

NyLocalization API Reference

Method / PropertyPurpose
translate(key, arguments)Core translation function
hasTranslation(key)Check if a key exists in the current locale
getAllKeys()List all loaded translation keys
setLanguage(context, language: 'es')Switch language with UI rebuild
setLocale(locale: Locale('fr'))Switch locale silently (no rebuild)
languageCodeGet current language code
localeGet current Locale object
delegatesGet localization delegates
isDirectionRTL(context)Check if current language is RTL

Complete Example: Settings Page with Language Switcher

class _SettingsPageState extends NyPage<SettingsPage> {
  @override
  Widget view(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: TextTr("settings.language"),
        actions: [
          LanguageSwitcher(
            onLanguageChange: (language) {
              showToastSuccess(
                description: "greeting".tr(arguments: {
                  "name": language['name'],
                }),
              );
            },
          ),
        ],
      ),
      body: SafeArea(
        child: Column(
          children: [
            TextTr.headlineLarge("app_title"),
            TextTr("cart.item_count", arguments: {"count": "3"}),
            TextTr.bodyLarge("cart.checkout"),
          ],
        ),
      ),
    );
  }
}

Common Mistakes

MistakeFix
Translation key shows as raw text instead of translated valueEnsure the JSON file is registered in pubspec.yaml under flutter.assets and the key exists in the locale file
Adding a new locale but it does not appearAdd the locale to LocalizationConfig.supportedLocales and create the corresponding lang/{code}.json file
Changing .env values but locale does not updateRun metro make:env --force after any .env changes to regenerate the environment config
Using "key" in Text() instead of "key".tr()Always call .tr() on the string or use the TextTr widget; plain Text("key") displays the literal key
Arguments not interpolated (shows {{name}} literally)Ensure the arguments map key matches the placeholder exactly: "greeting".tr(arguments: {"name": "Val"}) for {{name}}
Nested key not resolvingUse dot notation in the .tr() call: "navigation.home".tr(), not "navigation_home".tr()
Language switch does not rebuild the UIUse NyLocalization.instance.setLanguage(context, language: 'es') or changeLanguage('es') from NyPage; do not use setLocale() which switches silently
RTL layout not applied for ArabicVerify ar is in supportedLocales and that the app wraps content with Directionality or relies on MaterialApp's built-in direction support
LanguageSwitcher shows no languagesEnsure lang/ JSON files are properly registered as assets in pubspec.yaml
Fallback locale not workingConfirm fallbackLanguageCode is set in LocalizationConfig and the corresponding JSON file exists with all keys

Source

git clone https://github.com/nylo-core/claude-code/blob/main/skills/nylo-localization/SKILL.mdView on GitHub

Overview

Nylo v7 uses a JSON-based localization system configured in lib/config/localization.dart. Translation files live in the lang/ directory and are accessed via the .tr() extension or TextTr widget, enabling runtime language switching and RTL support.

How This Skill Works

Translation files live under lang/ and are wired through the LocalizationConfig in lib/config/localization.dart. Strings are accessed with .tr(), or via TextTr, and dynamic arguments are supported. At runtime, languages can be switched programmatically or with the LanguageSwitcher widget, using NyLocalization.instance.setLanguage(context, language: 'es').

When to Use It

  • Add multi-language support to a Nylo project.
  • Create or edit JSON translation files in the lang/ directory.
  • Display translated text using Text.tr, TextTr, or .tr().
  • Switch languages at runtime (via LanguageSwitcher or NyLocalization).
  • Configure supported locales, default/fallback locale, and RTL handling; debug missing translations.

Quick Start

  1. Step 1: Add language JSON files to lang/ (e.g., en.json, es.json, fr.json).
  2. Step 2: Configure lib/config/localization.dart with supportedLocales and fallbackLanguageCode; set up .env (DEFAULT_LOCALE, LOCALE_TYPE, DEBUG_TRANSLATIONS).
  3. Step 3: Replace UI strings with .tr() or TextTr and use LanguageSwitcher or NyLocalization.instance.setLanguage(...) to switch languages.

Best Practices

  • Keep translation keys stable and organized; prefer nested keys with dot notation (e.g., navigation.home).
  • Place all locale JSON files under lang/ and reference them consistently in code.
  • Enable RTL checks and test layouts for languages like Arabic or Hebrew (LocalizationConfig.isRtl).
  • Enable translation debugging with DEBUG_TRANSLATIONS and verify keys exist with NyLocalization.instance.hasTranslation('key').
  • Run metro make:env --force after changing .env or localization settings to rebuild assets.

Example Use Cases

  • Add en.json and es.json in lang/, then switch the UI language with a LanguageSwitcher widget.
  • Replace a string with: 'welcome'.tr() and ensure translations appear in the selected locale.
  • Translate with dynamic args: 'greeting'.tr(arguments: {'name': 'John'}).
  • Switch language at runtime from NyPage using changeLanguage('es').
  • Set DEFAULT_LOCALE=en and LOCALE_TYPE=device in .env, then test device-based locale switching.

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers