or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

core-translation.mdindex.mdinitialization.mdjquery-integration.mdlanguage-management.mdresource-management.md
tile.json

resource-management.mddocs/

Resource Management

Dynamic loading, caching, and management of translation resources with namespace organization support.

Capabilities

Resource Bundle Management

Add, retrieve, and manage complete resource bundles for specific languages and namespaces.

/**
 * Add a resource bundle for a language and namespace
 * @param lng - Language code
 * @param ns - Namespace (optional, defaults to default namespace)
 * @param resources - Resource object to add
 * @param deep - Whether to deep merge (optional)
 * @param overwrite - Whether to overwrite existing keys during deep merge (optional)
 */
function addResourceBundle(lng, ns, resources, deep, overwrite): void;

/**
 * Check if a resource bundle exists for language and namespace
 * @param lng - Language code
 * @param ns - Namespace (optional, defaults to default namespace)
 * @returns True if bundle exists and has content
 */
function hasResourceBundle(lng, ns): boolean;

/**
 * Get a copy of the resource bundle for language and namespace
 * @param lng - Language code
 * @param ns - Namespace (optional, defaults to default namespace)
 * @returns Copy of resource bundle object
 */
function getResourceBundle(lng, ns): object;

/**
 * Remove a resource bundle for language and namespace
 * @param lng - Language code
 * @param ns - Namespace (optional, defaults to default namespace)
 */
function removeResourceBundle(lng, ns): void;

Usage Examples:

// Add resource bundle for default namespace
i18n.addResourceBundle('en', {
  welcome: 'Welcome',
  goodbye: 'Goodbye',
  user: {
    profile: 'Profile',
    settings: 'Settings'
  }
});

// Add resource bundle for specific namespace
i18n.addResourceBundle('en', 'common', {
  buttons: {
    save: 'Save',
    cancel: 'Cancel',
    delete: 'Delete'
  },
  labels: {
    name: 'Name',
    email: 'Email'
  }
});

// Deep merge with existing resources
i18n.addResourceBundle('en', 'common', {
  buttons: {
    edit: 'Edit' // Adds to existing buttons object
  }
}, true); // deep = true

// Deep merge with overwrite
i18n.addResourceBundle('en', 'common', {
  buttons: {
    save: 'Save Changes' // Overwrites existing save button
  }
}, true, true); // deep = true, overwrite = true

// Check if bundle exists
if (i18n.hasResourceBundle('es', 'common')) {
  console.log('Spanish common bundle is available');
}

// Get resource bundle copy
const enCommonBundle = i18n.getResourceBundle('en', 'common');
console.log('English common resources:', enCommonBundle);

// Remove resource bundle
i18n.removeResourceBundle('fr', 'admin');

Individual Resource Management

Add and manage individual translation resources.

/**
 * Add a single resource key-value pair
 * @param lng - Language code
 * @param ns - Namespace (optional, defaults to default namespace)
 * @param key - Resource key (supports nested keys with dot notation)
 * @param value - Translation value
 */
function addResource(lng, ns, key, value): void;

/**
 * Add multiple resources from an object
 * @param lng - Language code
 * @param ns - Namespace (optional, defaults to default namespace)
 * @param resources - Object containing key-value pairs
 */
function addResources(lng, ns, resources): void;

Usage Examples:

// Add single resource to default namespace
i18n.addResource('en', 'welcome', 'Welcome to our app');

// Add single resource to specific namespace
i18n.addResource('en', 'common', 'buttons.submit', 'Submit');

// Add nested resource using dot notation
i18n.addResource('en', 'common', 'user.profile.title', 'User Profile');

// Add multiple resources
i18n.addResources('en', 'forms', {
  validation: {
    required: 'This field is required',
    email: 'Please enter a valid email',
    minLength: 'Minimum length is __min__ characters'
  },
  placeholders: {
    email: 'Enter your email',
    password: 'Enter your password'
  }
});

// Add resources to default namespace (omit namespace parameter)
i18n.addResources('es', {
  welcome: 'Bienvenido',
  goodbye: 'Adiós'
});

Namespace Management

Manage namespaces and load them dynamically.

/**
 * Set the default namespace
 * @param ns - Namespace name to set as default
 */
function setDefaultNamespace(ns): void;

/**
 * Load a single namespace dynamically
 * @param namespace - Namespace to load
 * @param callback - Function called when loading completes
 */
function loadNamespace(namespace, callback): void;

/**
 * Load multiple namespaces dynamically
 * @param namespaces - Array of namespace names to load
 * @param callback - Function called when all loading completes
 */
function loadNamespaces(namespaces, callback): void;

Usage Examples:

// Set default namespace
i18n.setDefaultNamespace('app');

// Load single namespace
i18n.loadNamespace('admin', function() {
  console.log('Admin namespace loaded');
  console.log(i18n.t('admin:dashboard.title'));
});

// Load multiple namespaces
i18n.loadNamespaces(['forms', 'validation', 'errors'], function() {
  console.log('Form-related namespaces loaded');
  console.log(i18n.t('forms:login.title'));
  console.log(i18n.t('validation:required'));
});

// Load namespaces with error handling
i18n.loadNamespaces(['missing-namespace'], function(err) {
  if (err) {
    console.error('Failed to load namespaces:', err);
  } else {
    console.log('Namespaces loaded successfully');
  }
});

Resource Loading Patterns

File-based Resources

Configure automatic loading from JSON files.

i18n.init({
  lng: 'en',
  ns: {
    namespaces: ['translation', 'common', 'forms'],
    defaultNs: 'translation'
  },
  resGetPath: 'locales/__lng__/__ns__.json',
  // Loads:
  // locales/en/translation.json
  // locales/en/common.json  
  // locales/en/forms.json
}, function(t) {
  console.log('File-based resources loaded');
});

Dynamic Resource Loading

Load resources on demand based on user actions or route changes.

function loadPageResources(page) {
  const namespacesToLoad = [`pages-${page}`, 'page-common'];
  
  i18n.loadNamespaces(namespacesToLoad, function() {
    console.log(`Resources for ${page} page loaded`);
    
    // Update page content
    document.title = i18n.t(`pages-${page}:title`);
    document.querySelector('.page-header').textContent = 
      i18n.t(`pages-${page}:header`);
  });
}

// Usage in SPA routing
loadPageResources('dashboard');
loadPageResources('profile');

Resource Caching

Leverage localStorage caching for improved performance.

i18n.init({
  useLocalStorage: true,
  localStorageExpirationTime: 7 * 24 * 60 * 60 * 1000, // 7 days
  resGetPath: 'api/translations/__lng__/__ns__',
  
  // Custom load function for API integration
  customLoad: function(lng, ns, options, loadComplete) {
    fetch(`/api/translations/${lng}/${ns}`)
      .then(response => response.json())
      .then(data => loadComplete(null, data))
      .catch(error => loadComplete(error, {}));
  }
}, function(t) {
  console.log('Cached resources loaded');
});

Advanced Resource Management

Resource Validation

function validateResources(lng, ns) {
  if (!i18n.hasResourceBundle(lng, ns)) {
    console.warn(`Missing resource bundle: ${lng}/${ns}`);
    return false;
  }
  
  const bundle = i18n.getResourceBundle(lng, ns);
  const keys = Object.keys(bundle);
  
  if (keys.length === 0) {
    console.warn(`Empty resource bundle: ${lng}/${ns}`);
    return false;
  }
  
  console.log(`Resource bundle ${lng}/${ns} is valid with ${keys.length} keys`);
  return true;
}

// Validate all loaded resources
['en', 'es', 'fr'].forEach(lng => {
  ['translation', 'common', 'forms'].forEach(ns => {
    validateResources(lng, ns);
  });
});

Resource Merging

function mergeResourceBundles(targetLng, sourceLng, namespace) {
  const sourceBundle = i18n.getResourceBundle(sourceLng, namespace);
  if (sourceBundle && Object.keys(sourceBundle).length > 0) {
    i18n.addResourceBundle(targetLng, namespace, sourceBundle, true);
    console.log(`Merged ${sourceLng} resources into ${targetLng} for ${namespace}`);
  }
}

// Merge fallback resources
mergeResourceBundles('es-MX', 'es', 'common');
mergeResourceBundles('en-GB', 'en', 'translation');

Resource Synchronization

function syncResources(languages, namespaces) {
  const totalResources = languages.length * namespaces.length;
  let loadedResources = 0;
  
  languages.forEach(lng => {
    namespaces.forEach(ns => {
      if (!i18n.hasResourceBundle(lng, ns)) {
        // Load missing resource
        loadResourceBundle(lng, ns).then(() => {
          loadedResources++;
          if (loadedResources === totalResources) {
            console.log('All resources synchronized');
          }
        });
      } else {
        loadedResources++;
      }
    });
  });
}

function loadResourceBundle(lng, ns) {
  return new Promise((resolve, reject) => {
    fetch(`/api/translations/${lng}/${ns}`)
      .then(response => response.json())
      .then(data => {
        i18n.addResourceBundle(lng, ns, data);
        resolve();
      })
      .catch(reject);
  });
}

Resource Hot Reloading

function enableResourceHotReload() {
  // WebSocket connection for development
  const ws = new WebSocket('ws://localhost:3001/i18n-hot-reload');
  
  ws.onmessage = function(event) {
    const { lng, ns, resources } = JSON.parse(event.data);
    
    // Update resource bundle
    i18n.addResourceBundle(lng, ns, resources, false, true);
    
    // Re-translate current page
    if (typeof $ !== 'undefined') {
      $('[data-i18n]').i18n(); // jQuery DOM update
    } else {
      i18n.translateObject(document); // Native DOM update
    }
    
    console.log(`Hot reloaded: ${lng}/${ns}`);
  };
}

// Enable in development mode
if (window.location.hostname === 'localhost') {
  enableResourceHotReload();
}

Error Handling

// Resource loading error handling
i18n.loadNamespaces(['missing-namespace'], function(err) {
  if (err) {
    console.error('Resource loading failed:', err);
    
    // Fallback to default resources
    i18n.addResourceBundle(i18n.lng(), 'missing-namespace', {
      error: 'Content not available'
    });
  }
});

// Validate resource integrity
function validateResourceIntegrity(lng, ns, expectedKeys) {
  const bundle = i18n.getResourceBundle(lng, ns);
  const missingKeys = expectedKeys.filter(key => !(key in bundle));
  
  if (missingKeys.length > 0) {
    console.warn(`Missing keys in ${lng}/${ns}:`, missingKeys);
    
    // Add placeholder values
    missingKeys.forEach(key => {
      i18n.addResource(lng, ns, key, `[Missing: ${key}]`);
    });
  }
}