Write your own adapter

NILS provides a set of Adapters to use different types of translation resource. But if you need another kind of translation resource you can implement your own Adapter and then use it with NILS.

To create an own adapter you must implement/extends the following interfaces/classes (all are located in the package com.codepulsar.nils.core.adapter):

  • Adapter: The Adapter is the concrete implementation accessing your translation resource.

  • NilsConfig: The configuration for the adapter and for nils. It is used by the NilsFactory and provide further configuration.

  • AdapterFactory: A factory using the AdapterConfig to create a new Adapter` object. The Factory must provide a parameterless default constructor.

Base classes

The package com.codepulsar.nils.core.adapter contains classes, that can be used for the own implementation:

  • BaseAdapterFactory: A base implementation of a Factory that caches the created Adapters for a Locale.

  • BaseLocalizedResourceAdapter: A base implemenatation of a Adapter uses file resources.

The package com.codepulsar.nils.core.adapter.config contains classes, that can be used for configuration:

  • BaseNilsConfig: A base implementation for the NilsConfig.

  • BaseLocalizedResourceNilsConfig: A base implementation for the interfaces NilsConfig and LocalizedResourceConfig.

Example implementation

To guide you a little bit during the creation process, let’s assume we want to write an Adapter using a static Map of translations.

AdapterConfig

The AdapterConfig must be implement com.codepulsar.nils.api.NilsConfig. These interface defines all valid options. Because most of the basic configuration are the same for all adapter the best practice is to extends your adapter config from com.codepulsar.nils.core.adapter.config.BaseNilsConfig.

package myadapter;

import com.codepulsar.nils.api.adapter.AdapterFactory;
import com.codepulsar.nils.core.adapter.config.BaseNilsConfig;

public class MyAdapterConfig extends BaseNilsConfig<MyAdapterConfig> { (1)

  @Override
  public Class<? extends AdapterFactory<?>> getFactoryClass() {
    return MyAdapterFactory.class; (2)
  }
}
1 The adapter config extends the BaseNilsConfig class.
2 Return the class of the factory.

Adapter

package myadapter;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import com.codepulsar.nils.api.adapter.Adapter;
import com.codepulsar.nils.core.util.ParameterCheck;

public class MyAdapter implements Adapter { (1)
  @SuppressWarnings("unused")
  private final MyAdapterConfig adapterConfig;

  private final Map<String, String> translations = new HashMap<>();

  public MyAdapter(MyAdapterConfig config) { (2)
    ParameterCheck.notNull(config, "config"); (3)
    this.adapterConfig = config;
    this.translations.putAll( (4)
        Map.of(
            "customer.name",
            "Name",
            "Address.street",
            "Street",
            "page_counter",
            "Page {0} of {1}",
            "btn.close",
            "Close"));
  }

  @Override
  public Optional<String> getTranslation(String key) {
    return Optional.ofNullable(translations.get(key)); (5)
  }
}
1 The adapter implements the Adapter interface.
2 The constructur gets a configuration. Depending on the implementation you can also pass in a Locale object.
3 The ParameterCheck class provides some useful methods for checking parameters.
4 Define static translations keys and values.
5 The translation resolution: Looking up the key in the map. It is enough to resolve the translation or pass an empty optional back to the caller. All other features (like formatting, resolution of class names etc) is done by NILS.

AdapterFactory

package myadapter;

import java.util.Locale;

import com.codepulsar.nils.api.NilsConfig;
import com.codepulsar.nils.api.adapter.AdapterFactory;
import com.codepulsar.nils.core.error.ErrorTypes;

public class MyAdapterFactory implements AdapterFactory<MyAdapter> { (1)

  public MyAdapterFactory() {} (2)

  @Override
  public MyAdapter create(NilsConfig<?> config, Locale locale) { (3)
    if (!(config instanceof MyAdapterConfig)) { (4)
      throw ErrorTypes.ADAPTER_ERROR
          .asException()
          .message("The provided AdapterConfig (%s) is not of type %s.")
          .args(config, MyAdapterConfig.class.getName())
          .go();
    }
    return new MyAdapter((MyAdapterConfig) config); (5)
  }
}
1 The factory implements the AdapterFactory interface.
2 The class must have a parameterless public constructur (here only for illustration.)
3 The factory gets a config object and a Locale.
4 The factory should check if the config object is of the right type.
5 Create a new adapter instance.

Usage

public class SimpleMyAdapterExample extends BaseUI {

  private static final NilsFactory NLS_FACTORY = NilsFactory.init(new MyAdapterConfig());

  @Override
  protected void innerTranslate(
      JLabel lblCustomerName, JLabel lblStreet, JLabel lblPageOf, JButton btnClose) {
    NLS nls = NLS_FACTORY.nls();

    lblCustomerName.setText(nls.get("customer.name"));
    lblStreet.setText(nls.get(Address.class, "street"));
    lblPageOf.setText(nls.get("page_counter", 3, 5));
    btnClose.setText(nls.get("btn.close"));
  }

  // ...

Another example

The tests in the core module provides a really simple implementation for a Adapter using a fix Map storing the translations (see com.codepulsar.nils.core.testadapter).