Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


Simple and cross platform internationalization/translations for Xamarin and .NET

NuGet NuGet AppVeyor Codecov

  • Cross platform
  • Simple to use: "key".Translate().
  • Simple and fluent initialization setup.
  • Readable locale files (.txt with key/value pairs).
  • Support for custom file formats (json, xml, etc)
  • Light weight
  • No dependencies.
  • Well tested


Install it on your PCL and platform projects. From nuget package manager console:

PM> Install-Package I18NPortable

Setup locales

  • In your PCL/Core project, create a directory called "Locales".
  • Create a {languageCode}.txt file for each language you want to support. languageCode can be a two letter ISO code or a culture name like "en-US". See full list here.
  • Set "Build Action" to "Embedded Resource" on the properties of each file

Locale content sample

# key = value (the key will be the same across locales)
one = uno
two = dos
three = tres 
four = cuatro
five = cinco
# Enums are supported
Animals.Dog = Perro
Animals.Cat = Gato
Animals.Rat = Rata
Animals.Tiger = Tigre
Animals.Monkey = Mono
# Support for string.Format()
stars.count = Tienes {0} estrellas
TextWithLineBreakCharacters = Line One\nLine Two\r\nLine Three
Multiline = Line One
    Line Two
    Line Three

Other file formats (including custom) supported

Fluent initialization

    .SetNotFoundSymbol("$") // Optional: when a key is not found, it will appear as $key$ (defaults to "$")
    .SetFallbackLocale("en") // Optional but recommended: locale to load in case the system locale is not supported
    .SetThrowWhenKeyNotFound(true) // Optional: Throw an exception when keys are not found (recommended only for debugging)
    .SetLogger(text => Debug.WriteLine(text)) // action to output traces
    .SetResourcesFolder("OtherLocales") // Optional: The directory containing the resource files (defaults to "Locales")
    .Init(GetType().GetTypeInfo().Assembly); // assembly where locales live


string one = "one".Translate();
string notification = "Mailbox.Notification".Translate("Diego", 3); // same as string.Format(params). Output: Hello Diego, you've got 3 emails
string missingKey = "missing".Translate(); // if the key is not found the output will be $key$. Output: $missing$
string giveMeNull = "missing".TranslateOrNull(); // Output: null

string dog = Animals.Dog.Translate(); // translate enum value (Animals is an Enum backed up in the locale file with "Animals.Dog = Perro")

List<string> animals = I18N.Current.TranslateEnumToList<Animals>(); 

List<Tuple<Animals, string>> animals = I18N.Current.TranslateEnumToTupleList<Animals>();
string dog = animals[0].Item2; // Perro

Dictionary<Animals, string> animals = I18N.Current.TranslateEnumToDictionary<Animals>();
string dog = animals[Animals.Dog]; // Perro

// List of supported languages (present in the "Locales" folder) in case you need to show a picker list
List<PortableLanguage> languages = I18N.Current.Languages; // Each `PortableLanguage` has 2 strings: Locale and DisplayName

// change language on runtime
I18N.Current.Language = language; // instance of PortableLanguage

// change language on runtime (option 2)
I18N.Current.Locale = "fr";

Data binding

I18N implements INotifyPropertyChanged and it has an indexer to translate keys. For instance, you could translate a key like:

string three = I18N.Current["three"]; 

With that said, the easiest way to bind your views to I18N translations is to use the built-in indexer by creating a proxy object in your ViewModel:

public abstract class BaseViewModel
    public II18N Strings => I18N.Current;

Xaml sample

<Button Content="{Binding Strings[key]}" />

Xamarin.Forms sample

<Button Text="{Binding Strings[key]}" />`

Android/MvvmCross sample

<TextView local:MvxBind="Text Strings[key]" />

iOS/MvvmCross sample

var set = this.CreateBindingSet<YourView, YourViewModel>();

Supported formats

The library ships with a single format reader/parser that is TextKvpReader. Any other reader will be isolated in a different nuget/plugin to keep the library as simple as possible.

Reader Format Source
TextKvpReader See sample I18NPortable
JsonKvpReader See sample I18NPortable.JsonReader I18NPortable.JsonReader
JsonListReader See sample I18NPortable.JsonReader I18NPortable.JsonReader

To use any non-default format, it needs to be added on initialization:

    .AddLocaleReader(new JsonKvpReader(), ".json") // ILocaleReader, file extension
    // add more readers here if you need to

Creating a custom reader for another file format:

It's very easy to create custom readers/parsers for any file format you wish. For instance, lets take a loot at the above mentioned JsonKvpReader:

Given this en.json file

  "one": "uno",
  "two": "dos",
  "three": "tres"

Creating a custom reader is as simple as implementing ILocaleReader:

public interface ILocaleReader
    Dictionary<string, string> Read(Stream stream);
public class JsonKvpReader : ILocaleReader
    public Dictionary<string, string> Read(Stream stream)
        using (var streamReader = new StreamReader(stream))
            var json = streamReader.ReadToEnd();

            return JsonConvert
                .DeserializeObject<Dictionary<string, string>>(json)
                .ToDictionary(x => x.Key.Trim(), x => x.Value.Trim().UnescapeLineBreaks());

Contributing new readers

If you implemented a new reader for another file format and you want to contribute, feel free to make a pull request. Any new reader will live in their own project in the solution and will produce a different nuget as a plugin to I18NPortable.


Simple and cross platform internationalization/translations for Xamarin and .NET








No packages published