Lightweight i18n solution for Flutter

Overview

featured

fast_i18n

pub package Awesome Flutter ci License: MIT

Lightweight i18n solution. Use JSON, YAML or CSV files to create typesafe translations.

About this library

  • πŸš€ Minimal setup, create JSON files and get started! No configuration needed.
  • πŸ“¦ Self-contained, you can remove this library after generation.
  • 🐞 Bug-resistant, no typos or missing arguments possible due to compiler errors.
  • ⚑ Fast, you get translations using native dart method calls, zero parsing!
  • πŸ”¨ Configurable, English is not the default language? Configure it in build.yaml!

You can see an example of the generated file here.

This is how you access the translations:

final t = Translations.of(context); // optional, there is also a static getter without context

String a = t.mainScreen.title;                         // simple use case
String b = t.game.end.highscore(score: 32.6);          // with parameters
String c = t.items(count: 2);                          // with pluralization (using count)
String d = t.greet(name: 'Tom', context: Gender.male); // with custom context
String e = t.intro.step[4];                            // with index
String f = t.error.type['WARNING'];                    // with dynamic key
String g = t['mainScreen.title'];                      // with fully dynamic key

PageData titlePage = t.onboarding.titlePage;
PageData page = t.onboarding.pages[2];
String h = page.title;                                 // with interfaces

Table of Contents

Getting Started

Step 1: Add dependencies

It is recommended to add fast_i18n to dev_dependencies.

dev_dependencies:
  build_runner: any
  fast_i18n: 5.7.0

Step 2: Create JSON files

Create these files inside your lib directory. For example, lib/i18n.

YAML and CSV files are also supported (see File Types).

Writing translations into assets folder requires extra configuration (see FAQ).

Format:

<namespace>_<locale?>.<ext>

Example:

lib/
 └── i18n/
      └── strings.i18n.json
      └── strings_de.i18n.json
      └── strings_zh-CN.i18n.json
// File: strings.i18n.json (mandatory, base locale)
{
  "hello": "Hello $name",
  "save": "Save",
  "login": {
    "success": "Logged in successfully",
    "fail": "Logged in failed"
  }
}
// File: strings_de.i18n.json
{
  "hello": "Hallo $name",
  "save": "Speichern",
  "login": {
    "success": "Login erfolgreich",
    "fail": "Login fehlgeschlagen"
  }
}

Step 3: Generate the dart code

flutter pub run fast_i18n

alternative (but slower):

flutter pub run build_runner build --delete-conflicting-outputs

Step 4: Initialize

a) use device locale

void main() {
  WidgetsFlutterBinding.ensureInitialized(); // add this
  LocaleSettings.useDeviceLocale(); // and this
  runApp(MyApp());
}

b) use specific locale

@override
void initState() {
  super.initState();
  String storedLocale = loadFromStorage(); // your logic here
  LocaleSettings.setLocaleRaw(storedLocale);
}

Step 4a: Flutter locale

This is optional but recommended.

Standard flutter controls (e.g. back button's tooltip) will also pick the right locale.

# File: pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  flutter_localizations: # add this
    sdk: flutter
void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(TranslationProvider(child: MyApp())); // Wrap your app with TranslationProvider
}
MaterialApp(
  locale: TranslationProvider.of(context).flutterLocale, // use provider
  supportedLocales: LocaleSettings.supportedLocales,
  localizationsDelegates: GlobalMaterialLocalizations.delegates,
  child: YourFirstScreen(),
)

Step 4b: iOS configuration

File: ios/Runner/Info.plist

<key>CFBundleLocalizations</key>
<array>
   <string>en</string>
   <string>de</string>
</array>

Step 5: Use your translations

import 'package:my_app/i18n/strings.g.dart'; // import

String a = t.login.success; // get translation

Configuration

This is optional. This library works without any configuration (in most cases).

For customization, you can create the build.yaml file. Place it in the root directory.

targets:
  $default:
    builders:
      fast_i18n:
        options:
          base_locale: fr
          fallback_strategy: base_locale
          input_directory: lib/i18n
          input_file_pattern: .i18n.json
          output_directory: lib/i18n
          output_file_pattern: .g.dart # deprecated, use output_file_name
          output_file_name: translations.g.dart
          output_format: single_file
          namespaces: false
          translate_var: t
          enum_name: AppLocale
          translation_class_visibility: private
          key_case: snake
          key_map_case: camel
          param_case: pascal
          string_interpolation: double_braces
          flat_map: false
          timestamp: true
          maps:
            - error.codes
            - category
            - iconNames
          pluralization:
            auto: cardinal
            cardinal:
              - someKey.apple
            ordinal:
              - someKey.place
          contexts:
            gender_context:
              enum:
                - male
                - female
              auto: false
              paths:
                - my.path.to.greet
          interfaces:
            PageData: onboarding.pages.*
            PageData2:
              paths:
                - my.path
                - cool.pages.*
              attributes:
                - String title
                - String? content
Key Type Usage Default
base_locale String locale of default json en
fallback_strategy none, base_locale handle missing translations (i) none
input_directory String path to input directory null
input_file_pattern String input file pattern, must end with .json, .yaml or .csv .i18n.json
output_directory String path to output directory null
output_file_pattern String deprecated: output file pattern .g.dart
output_file_name String output file name null
output_format single_file, multiple_files split output files (i) single_file
namespaces Boolean split input files (i) false
translate_var String translate variable name t
enum_name String enum name AppLocale
translation_class_visibility private, public class visibility private
key_case camel, pascal, snake transform keys (optional) (i) null
key_map_case camel, pascal, snake transform keys for maps (optional) (i) null
param_case camel, pascal, snake transform parameters (optional) (i) null
string_interpolation dart, braces, double_braces string interpolation mode (i) dart
flat_map Boolean generate flat map (i) true
timestamp Boolean write "Built on" timestamp true
maps List<String> entries which should be accessed via keys (i) []
pluralization/auto off, cardinal, ordinal detect plurals automatically (i) cardinal
pluralization/cardinal List<String> entries which have cardinals []
pluralization/ordinal List<String> entries which have ordinals []
<context>/enum List<String> context forms (i) no default
<context>/auto Boolean auto detect context true
<context>/paths List<String> entries using this context []
children of interfaces Pairs of Alias:Path alias interfaces (i) null

Features

➀ File Types

Type Supported Note
JSON βœ” by default
YAML βœ” update input_file_pattern
CSV βœ” update input_file_pattern

To change to YAML or CSV, please modify input file pattern

# File: build.yaml
targets:
  $default:
    builders:
      fast_i18n:
        options:
          input_directory: assets/i18n
          input_file_pattern: .i18n.yaml # must end with .json, .yaml or .csv

JSON Example

{
  "welcome": {
    "title": "Welcome $name"
  }
}

YAML Example

welcome:
  title: Welcome $name # some comment

CSV Example

welcome.title,Welcome $name
welcome.pages.0.title,First Page
welcome.pages.1.title,Second Page

Use integers to specify lists.

You can also combine multiple locales (see Compact CSV).

➀ Namespaces

You can split the translations into multiple files. Each file represents a namespace.

This feature is disabled by default for single-file usage. You must enable it.

# File: build.yaml
targets:
  $default:
    builders:
      fast_i18n:
        options:
          namespaces: true # enable this feature
          output_directory: lib/i18n # optional
          output_file_name: translations.g.dart # set file name (mandatory)

Let's create two namespaces called widgets and dialogs.

<namespace>_<locale?>.<ext>
i18n/
 └── widgets.i18n.json
 └── widgets_fr.i18n.json
 └── dialogs.i18n.json
 └── dialogs_fr.i18n.json

You can also use different folders. Only file name matters!

i18n/
 └── widgets/
      └── widgets.i18n.json
      └── widgets_fr.i18n.json
 └── dialogs/
      └── dialogs.i18n.json
      └── dialogs_fr.i18n.json
i18n/
 └── base/
      └── widgets.i18n.json
      └── dialogs.i18n.json
 └── fr/
      └── widgets_fr.i18n.json
      └── dialogs_fr.i18n.json

Now access the translations:

// t.<namespace>.<path>
String a = t.widgets.welcomeCard.title;
String b = t.dialogs.logout.title;

➀ String Interpolation

There are three modes configurable via string_interpolation in build.yaml.

You can always escape them by adding a backslash, e.g. \{notAnArgument}.

Mode Example
dart (default) Hello $name. I am ${height}m.
braces Hello {name}
double_braces Hello {{name}}

➀ Lists

Lists are fully supported. No configuration needed. You can also put lists or maps inside lists!

{
  "niceList": [
    "hello",
    "nice",
    [
      "first item in nested list",
      "second item in nested list"
    ],
    {
      "wow": "WOW!",
      "ok": "OK!"
    },
    {
      "a map entry": "access via key",
      "another entry": "access via second key"
    }
  ]
}
String a = t.niceList[1]; // "nice"
String b = t.niceList[2][0]; // "first item in nested list"
String c = t.niceList[3].ok; // "OK!"
String d = t.niceList[4]['a map entry']; // "access via key"

➀ Linked Translations

You can link one translation to another. Add the prefix @: followed by the translation key.

{
  "fields": {
    "name": "my name is {firstName}",
    "age": "I am {age} years old"
  },
  "introduce": "Hello, @:fields.name and @:fields.age"
}
String s = t.introduce(firstName: 'Tom', age: 27); // Hello, my name is Tom and I am 27 years old.

➀ Interfaces

Often, multiple maps have the same structure. You can create a common super class for that.

{
  "onboarding": {
    "whatsNew": {
      "v2": {
        "title": "New in 2.0",
        "rows": [
          "Add sync"
        ]
      },
      "v3": {
        "title": "New in 3.0",
        "rows": [
          "New game modes",
          "And a lot more!"
        ]
      }
    }
  }
}

Here we know that all objects inside whatsNew have the same attributes. Let's name these objects ChangeData.

# File: build.yaml
targets:
  $default:
    builders:
      fast_i18n:
        options:
          interfaces:
            ChangeData: onboarding.whatsNew.*
void myFunction(ChangeData changes) {
  String title = changes.title;
  List<String> rows = changes.rows;
}

void main() {
  myFunction(t.onboarding.whatsNew.v2);
  myFunction(t.onboarding.whatsNew.v3);
}

You can customize the attributes and use different node selectors.

Please read the Wiki.

➀ Locale Enum

Typesafety is one of the main advantages of this library. No typos. Enjoy exhausted switch-cases!

// this enum is generated automatically for you
enum AppLocale {
  en,
  fr,
  zhCn,
}
// use cases
LocaleSettings.setLocale(AppLocale.en); // set locale
List<AppLocale> locales = AppLocale.values; // list all supported locales
Locale locale = AppLocale.en.flutterLocale; // convert to native flutter locale
String tag = AppLocale.en.languageTag; // convert to string tag (e.g. en-US)
final t = AppLocale.en.translations; // get translations of one locale

➀ Dependency Injection

A follow-up feature of locale enums.

You can use your own dependency injection and inject the required translations!

Please set the translations classes public:

# File: build.yaml
targets:
  $default:
    builders:
      fast_i18n:
        options:
          translation_class_visibility: public
final englishTranslations = AppLocale.en.translations;
final germanTranslations = AppLocale.de.translations;

final String a = germanTranslations.welcome.title; // access the translation

// using get_it
final getIt = GetIt.instance;
getIt.registerSingleton<StringsEn>(AppLocale.de.translations); // set German
final String b = getIt<StringsEn>().welcome.title; // access the translation

➀ Pluralization

This library uses the concept defined here.

Some languages have support out of the box. See here.

Plurals are detected by the following keywords: zero, one, two, few, many, other.

You can access the num count but it is optional.

// File: strings.i18n.json
{
  "someKey": {
    "apple": {
      "one": "I have $count apple.",
      "other": "I have $count apples."
    }
  }
}
String a = t.someKey.apple(count: 1); // I have 1 apple.
String b = t.someKey.apple(count: 2); // I have 2 apples.

Plurals are interpreted as cardinals by default. You can configure or disable it.

// File: strings.i18n.json
{
  "someKey": {
    "apple": {
      "one": "I have $count apple.",
      "other": "I have $count apples."
    },
    "place": {
      "one": "${count}st place.",
      "two": "${count}nd place.",
      "few": "${count}rd place.",
      "other": "${count}th place."
    }
  }
}
# File: build.yaml
targets:
  $default:
    builders:
      fast_i18n:
        options:
          pluralization:
            auto: off
            cardinal:
              - someKey.apple
            ordinal:
              - someKey.place

In case your language is not supported, you must provide a custom pluralization resolver:

// add this before you call the pluralization strings. Otherwise an exception will be thrown.
// you don't need to specify both
LocaleSettings.setPluralResolver(
  language: 'en',
  cardinalResolver: (num n, {String? zero, String? one, String? two, String? few, String? many, String? other}) {
    if (n == 0)
      return zero ?? other!;
    if (n == 1)
      return one ?? other!;
    return other!;
  },
  ordinalResolver: (num n, {String? zero, String? one, String? two, String? few, String? many, String? other}) {
    if (n % 10 == 1 && n % 100 != 11)
      return one ?? other!;
    if (n % 10 == 2 && n % 100 != 12)
      return two ?? other!;
    if (n % 10 == 3 && n % 100 != 13)
      return few ?? other!;
    return other!;
  },
);

➀ Custom Contexts

You can utilize custom contexts to differentiate between male and female forms.

// File: strings.i18n.json
{
  "greet": {
    "male": "Hello Mr $name",
    "female": "Hello Ms $name"
  }
}
# File: build.yaml
targets:
  $default:
    builders:
      fast_i18n:
        options:
          contexts:
            gender_context:
              enum:
                - male
                - female
            polite_context:
              enum:
                - polite
                - rude
String a = t.greet(name: 'Maria', context: GenderContext.female);

Auto detection is on by default. You can disable auto detection. This may speed up build time.

# File: build.yaml
targets:
  $default:
    builders:
      fast_i18n:
        options:
          contexts:
            gender_context:
              enum:
                - male
                - female
              auto: false # disable auto detection
              paths: # now you must specify paths manually
                - my.path.to.greet

In contrast to pluralization, you must provide all forms. Collapse it to save space.

// File: strings.i18n.json
{
  "greet": {
    "male,female": "Hello $name"
  }
}

➀ Maps

You can access each translation via string keys by defining maps.

Define the maps in your build.yaml. Each configuration item represents the translation tree separated by dots.

Keep in mind that all nice features like autocompletion are gone.

// File: strings.i18n.json
{
  "a": {
    "hello world": "hello"
  },
  "b": {
    "b0": "hey",
    "b1": {
      "hi there": "hi"
    }
  }
}
# File: build.yaml
targets:
  $default:
    builders:
      fast_i18n:
        options:
          maps:
            - a
            - b.b1

Now you can access the translations via keys:

String a = t.a['hello world']; // "hello"
String b = t.b.b0; // "hey"
String c = t.b.b1['hi there']; // "hi"

➀ Dynamic Keys / Flat Map

A more general solution to Maps. ALL translations are accessible via an one-dimensional map.

It is supported out of the box. No configuration needed.

This can be disabled globally by setting flat_map: false.

String a = t['myPath.anotherPath'];
String b = t['myPath.anotherPath.3']; // with index for arrays
String c = t['myPath.anotherPath'](name: 'Tom'); // with arguments

➀ Fallback

By default, you must provide all translations for all locales. Otherwise, you cannot compile it.

In case of rapid development, you can turn off this feature. Missing translations will fallback to base locale.

targets:
  $default:
    builders:
      fast_i18n:
        options:
          base_locale: en
          fallback_strategy: base_locale  # add this
// English
{
  "hello": "Hello",
  "bye": "Bye"
}
// French
{
  "hello": "Salut",
  // "bye" is missing, fallback to English version
}

➀ Recasing

By default, no transformations will be applied.

You can change that by specifying key_case, key_map_case or param_case.

Possible cases are: camel, snake and pascal.

{
  "must_be_camel_case": "The parameter is in {snakeCase}",
  "my_map": {
    "this_should_be_in_pascal": "hi"
  }
}
targets:
  $default:
    builders:
      fast_i18n:
        options:
          key_case: camel
          key_map_case: pascal
          param_case: snake
          maps:
            - myMap # all paths must be cased accordingly
String a = t.mustBeCamelCase(snake_case: 'nice');
String b = t.myMap['ThisShouldBeInPascal'];

➀ Output Format

By default, a single .g.dart file will be generated.

You can split this file into multiple ones to improve readability and IDE performance.

targets:
  $default:
    builders:
      fast_i18n:
        options:
          output_file_name: translations.g.dart
          output_format: multiple_files # set this

This will generate the following files:

translations.g.dart - main file
translations_<locale>.g.dart - translation classes
translations_map.g.dart - flat translation maps

You only need to import the main file!

➀ Compact CSV

Normally, you create a new csv file for each locale: strings.i18n.csv, strings_fr.i18n.csv, etc.

You can also merge multiple locales into one single csv file! To do this, you need at least 3 columns. The first row contains the locale names. Please avoid locales in file names!

key,en,de-DE
welcome.title,Welcome $name,Willkommen $name

➀ Auto Rebuild

You can let the library rebuild automatically for you. The watch function from build_runner is NOT maintained.

Just run this command:

flutter pub run fast_i18n watch

API

When the dart code has been generated, you will see some useful classes and functions

t - the translate variable for simple translations

Translations.of(context) - translations which reacts to locale changes

TranslationProvider - App wrapper, used for Translations.of(context)

LocaleSettings.useDeviceLocale() - use the locale of the device

LocaleSettings.setLocale(AppLocale.en) - change the locale

LocaleSettings.setLocaleRaw('de') - change the locale

LocaleSettings.currentLocale - get the current locale

LocaleSettings.baseLocale - get the base locale

LocaleSettings.supportedLocalesRaw - get the supported locales

LocaleSettings.supportedLocales - see step 4a

LocaleSettings.setPluralResolver - set pluralization resolver for unsupported languages

FAQ

Can I write the json files in the asset folder?

Yes. Specify input_directory and output_directory in build.yaml.

targets:
  $default:
    builders:
      fast_i18n:
        options:
          input_directory: assets/i18n
          output_directory: lib/i18n

Can I skip translations or use them from base locale?

Yes. Please set fallback_strategy: base_locale in build.yaml.

Now you can leave out translations in secondary languages. Missing translations will fallback to base locale.

Can I prevent the timestamp Built on from updating?

No, but you can disable the timestamp altogether. Set timestamp: false in build.yaml.

Why setLocale doesn't work?

In most cases, you forgot the setState call.

A more elegant solution is to use TranslationProvider(child: MyApp()) and then get your translation variable with final t = Translations.of(context). It will automatically trigger a rebuild on setLocale for all affected widgets.

My plural resolver is not specified?

An exception is thrown by _missingPluralResolver because you missed to add LocaleSettings.setPluralResolver for the specific language.

See Pluralization.

How does plural / context detection work?

You can let the library detect plurals or contexts.

For plurals, it checks if any json node has zero, one, two, few, many or other as children.

As soon as an unknown item has been detected, then this json node is not a pluralization.

{
  "fake": {
    "one": "One apple",
    "two": "Two apples",
    "three": "Three apples" // unknown key word 'three', 'fake' is not a pluralization
  }
}

For contexts, all enum values must exist.

License

MIT License

Copyright (c) 2020-2021 Tien Do Nam

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Comments
  • Generate enum keys

    Generate enum keys

    Example:

    someKey:
      apple: Apple Pie
      orange: Orange Juice
      rpi: Raspberry PI!
    

    with pre-defined enum

    enum Thing { apple, orange, rpi }
    

    Hope slang could generate something like:

    String get(Thing thing) => {
      Thing.apple: 'Apple Pie',
      Thing.orange: 'Orange Juice',
      Thing.rpi: 'Raspberry PI!',
    }[thing]!
    
    enhancement 
    opened by fzyzcjy 14
  • Different case in flat map

    Different case in flat map

    Affected version: 5.6.0

    Setting following in build.yaml does not seem to have effect on generated maps case:

          key_map_case: pascal
          flat_map: false
          maps:
            - ProjectActivityType
            - AddressBookType
    
    1. When flat_map is false it does not generate any maps in strings.g.dart
    2. Even when flat_map is enabled to true than the key_map_case case transformation is ignored.

    JSON:

    {
      "AddressBookType": {
        "COMPANY": "Company",
        "PERSON": "Person"
      }
    }
    

    will produce nin strings.g.dart:

    AppLocale.cs: {
      'addressBookType.company': 'Firma',
      'addressBookType.person': 'Osoba',
    }
    wontfix 
    opened by vladaman 7
  • Support for multiple json files

    Support for multiple json files

    Hello,

    my translation files are getting big very fast. I really like to have a json file for components, for services etc. split up and not in one file per language. I dont want to write my own service which merges multiple files into one to compile it with the runner afterwards.

    Are you planning on introducing multiple file support per language?

    Best regards

    enhancement 
    opened by Kaysen98 7
  • Split languages into separate files

    Split languages into separate files

    My project has over 7k source keys and over 14 languages. This makes the generated file over 2.5 MB in size, thus the IDE has problems caching/indexing the file. Maybe it is better to split the classes into separate files?

    enhancement 
    opened by offline-first 6
  • Dollar symbol is not escaped for braces string interpolations

    Dollar symbol is not escaped for braces string interpolations

    Without build.yaml config command flutter pub run fast_i18n generate this class: image

    But when I add build.yaml with:

    targets:
      $default:
        builders:
          fast_i18n:
            options:
              base_locale: cs
              translate_var: translate
              key_case: camel
              string_interpolation: double_braces
    

    so it generate: image

    Where name is undefined variable because $ symbol is not escaped by \$.

    My strings.i18n.json is:

    {
      "title": "Scanner pro vΓ‘ΕΎenΓ­ balΓ­kΕ―",
      "scanner_informations": "Scanner informations",
      "scale_informations": "Scale informations",
      "hello": "Hello $name",
      "save": "Save",
      "login": {
        "fail": "Logged in failed"
      }
    }
    
    
    bug 
    opened by mjablecnik 5
  • How to change language from view model

    How to change language from view model

    Hi @Tienisto, Thanks for making this amazing library, I want to update the language for the whole app from the settings page. I used LocaleSettings.setLocale('es'); in main page and it's working fine. But I'm using MVVM architecture and I want to change the language from my view-model any suggestions from your side.

    enhancement 
    opened by sadabwasim 5
  • Generator not working

    Generator not working

    Tried the steps in the description. I have 2 json files, fast-i18n dependencies are added,flutter packages pub run build_runner build produces no output (except those ones by Hive which also uses build_runner).

    image

    Contents of strings.i18n.json

    {
      "entries": "esntries",
      "search": "Search",
      "type-in": "Type-in text below"
    }
    

    Part of the pubspec.yaml:

    version: 1.0.0+1
    
    environment:
      sdk: ">=2.7.0 <3.0.0"
    
    dependencies:
      flutter:
        sdk: flutter
      
      provider: ^4.0.2
      shared_preferences: 
      flutter_html: ^1.0.0
      hive: ^1.4.1+1
      hive_flutter: ^0.3.0+2
      sprintf: "^4.0.0"
      archive: ^2.0.13
      flutter_sticky_header: ^0.4.2
      reorderables: ^0.3.2
      double_back_to_close_app: ^1.2.0
      fluttertoast: ^7.0.1
      file_picker: ^1.13.0+1
      fast_i18n: ^1.4.0
    
      # The following adds the Cupertino Icons font to your application.
      # Use with the CupertinoIcons class for iOS style icons.
      cupertino_icons: ^0.1.3
    
    dependency_overrides:
      flutter_svg: 0.18.0 #Flutter 1.20 and flutter_html issue
      path: 1.6.4
      hive: # custom version remove box key assertion to be ASCII string not greater than 255 chars
        path: ./plugins/hive-1.4.1+1/
      reorderables:
        path: ./plugins/reorderables-0.3.2/
    
    dev_dependencies:
      flutter_test:
        sdk: flutter
      hive_generator: ^0.7.0+2
      build_runner: ^1.10.0
      flutter_launcher_icons: ^0.7.3
      flutter_native_splash: ^0.1.9
    

    And that's flutter packages pub run build_runner build output:

    [INFO] Generating build script...
    [INFO] Generating build script completed, took 549ms
    
    [WARNING] Deleted previous snapshot due to missing asset graph.
    [INFO] Creating build script snapshot......
    [INFO] Creating build script snapshot... completed, took 15.0s
    
    [INFO] Initializing inputs
    [INFO] Building new asset graph...
    [INFO] Building new asset graph completed, took 902ms
    
    [INFO] Checking for unexpected pre-existing outputs....
    [INFO] Found 1 declared outputs which already exist on disk. This is likely because the`.dart_tool/build` folder was deleted, or you are submitting generated files to your source repository.
    [SEVERE] Conflicting outputs were detected and the build is unable to prompt for permission to remove them. These outputs must be removed manually or the build can be run with `--delete-conflicting-outputs`. The outputs are: lib/models/indexedDictionary.g.dart
    
    bug 
    opened by maxim-saplin 5
  • Why does it force me to use t.translations.?

    Why does it force me to use t.translations.?

    Hi, I've been using slang and I have a question, why does the example use t.mainScreen.title and when generating the translations it forces me to use t.translations.mainScreen.title?

    question 
    opened by AlejandroEsquivel666 4
  • Slang watch recursive

    Slang watch recursive

    Motivation Because the langfiles can become quite the list I group modules in their own directory. Slang watch does not trigger on the files in thje directories.

    assets/i18n
    β”œβ”€β”€ alerts
    β”‚Β Β  β”œβ”€β”€ alerts.i18n.yaml
    β”‚Β Β  └── alerts_nl.i18n.yaml
    β”œβ”€β”€ bottomBarPage
    β”‚Β Β  β”œβ”€β”€ bottomBarPage.i18n.yaml
    β”‚Β Β  └── bottomBarPage_nl.i18n.yaml
    β”œβ”€β”€ errors
    β”‚Β Β  β”œβ”€β”€ errors.i18n.yaml
    β”‚Β Β  └── errors_nl.i18n.yaml
    β”œβ”€β”€ login
    β”‚Β Β  β”œβ”€β”€ login.i18n.yaml
    β”‚Β Β  └── login_nl.i18n.yaml
    └── maintenancePage
        β”œβ”€β”€ maintenancePage.i18n.yaml
        └── maintenancePage_nl.i18n.yaml
    

    Developer Experience Adding a -r / --recursive option to the arguments of watch would be nice.

    enhancement 
    opened by Roboroads 4
  • Is possible to have constant values?

    Is possible to have constant values?

    Hi, thanks for your amazing package. I'm wondering if is possible to generate constant variables instead of getters in cases where we don't have interpolation and another dynamic features.

    wontfix 
    opened by BenevidesLecontes 4
  • TextSpan is not found after updating to 2.4.1

    TextSpan is not found after updating to 2.4.1

    Describe the bug

    packages/locale/lib/translations/strings.g.dart:254:9: Error: Couldn't find constructor 'TextSpan'.
    		const TextSpan(text: ' sent you notification'),
    		      ^^^^^^^^
    
     - '_StringsNotificationsEn' is from 'package:locale/translations/strings.g.dart' ('packages/locale/lib/translations/strings.g.dart').
    Try correcting the name to the name of an existing method, or defining a method named 'TextSpan'.
    	InlineSpan unknown({required InlineSpan name}) => TextSpan(children: [ ....
    

    To Reproduce Steps to reproduce the behavior:

    1. use below:
    "notifications": {
        "message(rich)": "$name sent you a message",
        "liked(rich)": "$name liked your post",
        "commented(rich)": "$name commented on your post",
        "follow(rich)": "$name is now following you",
        "unknown(rich)": "$name sent you notification"
      },
    
    1. call flutter pub run slang

    Expected behavior No exception/error.

    Temp-Fix: adding package:flutter/widgets.dart manually to file fixes the issue.

    bug invalid 
    opened by k0shk0sh 4
  • Make the namespace types public

    Make the namespace types public

    I store the namespace for a widget in a var to make it easier to access like this (simple example):

    final transBook = t.book;

    image

    The type here is "_TranslationsBookEn" but I can't import that, so if I want to pass transBook as an argument I can't. Is there some reason why the namespace types can't be public?

    I'm new to flutter and dart so maybe this is how it should be and i shouldn't be passing transBook around/using slang incorrectly.

    question 
    opened by sketchbuch 1
  • Dynamic parameter map

    Dynamic parameter map

    Motivation When I have both key for t map and params map from server, I need call like this:

    final value = t[key];
    final s = value.replaceWithParam(params);
    

    So map value need to be like 'my name is {{name}}' not ({required Object name}) => 'my name is ${name}'

    enhancement 
    opened by hamberluo 5
  • option to specify csvSettingsDetector

    option to specify csvSettingsDetector

    Motivation I am using a different text delimiter. Slang cannot parse my csv.

    Developer Experience There should be an option to specify csvSettingsDetector.

    var d = new FirstOccurrenceSettingsDetector(eols: ['\r\n', '\n'], textDelimiters: ['"', "'"]);
    new CsvToListConverter(csvSettingsDetector: d);
    
    enhancement 
    opened by deadsoul44 3
  • What about l10n?

    What about l10n?

    Hi there, thank you for this awesome lib.

    I realize that slang is about i18n, but are there any plans to move this library towards a l10n approach? It might sound like this is an "out-of-scope" proposal, but hear me out for a bit.

    Motivation, Use cases

    Most of the motivation arises from the necessity to properly format numbers, and maybe add some global or per-string configuration.

    Take this example from the docs

    # File: strings.i18n.yaml
    someKey:
      apple:
        one: "I have $n apple.",
        other: "I have $n apples."
    

    Now, say that such quantitative number that needs a proper formatting; there's a good chance that this most likely depends on where you're translating that sentence, even in the same language.

    Say we have a thousands apples. Here's how you would count them in London: 1.000,00 apples. Here's how you could count them in Dublin: 1,000.00 apples.

    And that's weird enough, thinking it's the same lang and the two cities are 450km apart (: Well, to be fair this also depends on personal preference, culture and context usage; thus the distinction line in this use case is thin.

    Nonetheless, when you have a currency instead of simple apples; things get interesting.

    # File: strings.i18n.yaml
    someCurrencyKey:
      amount: "I feel rich, since I have $n $currency." # warn: pseudocode that doesn't make much sense, but bear with me
    

    I'd expect amount to be properly formatted, or at least I'd expect our tool to give me some degree of freedom when formatting such number (different contexts may or may not follow their locale conventions).

    Say we are rich and we want to show it off with an explicit format. Here's how you would do that in London: Β£ 1,000,000.00 GBP. Here's how you would do that in Dublin: 1.000.000,00 € EUR.

    Current state

    Can we achieve this at this point in time?

    Here's my guess (and I'm not sure, so let me know if there're better alternatives):

    1. Rely on intl
    2. Carefully write reusable boilerplate code for your use cases
    3. Inject it into slang strings

    The proposal

    Shortly, this proposal is about easening our developer experience when creating translatable sentences that involve numbers and their formatting. The default should be the following: current locale settings should apply first, then global settings kick in (build.yaml config file) and finally per-string settings apply.

    Here's a heavily personalized string example:

    # File: strings.i18n.yaml
    someKey:
      # warn: pseudocode
      sentence: "Where lambo? I have $n!"
        - type: number
        - format: currency
        - decimalDigits: 2
        - name: GBP
        - symbol: Β£
        - customPattern: "Β€ #,##0.00"
    

    Usage:

    final lambo = t.someKey.sentence(0xFFFFFF);
    print(lambo); // "Where lambo? I have Β£ 16,777,215.00!"
    

    Note how this example relies onto dart APIs from the intl package, which (if I'm not mistaken) are ISO-like conventions. Obviously the previous example would be tedious to repeat for each string. That's were global configs and current locale would kick in as default fall-offs.

    Beyond simple numbers

    Another l10n topic is date formatting. Even here, we could rely on intl and give a similar configuration API and usage:

    # File: strings.i18n.yaml
    someKey:
      # warn: pseudocode
      sentence1: "Morning! Oh, today it's $date!"
        - type: datetime
        - format: MMMMEEEEd # MONTH_WEEKDAY_DAY from intl package
      sentence2: "Good Heavens, just look at the time! It's $time!"
        - type: datetime
        - format: Hm # HOUR24_MINUTE from intl package
    

    Usage:

    const myValue = const DateTime.utc(2022, 10, 29, 03, 30, 00);
    
    // The following is a mock of running this code in a GMT-5 time zone
    final dateAlabama = t.someKey.sentence1(myValue);
    print(morningAlabama); // "Morning! Oh, today it's Friday, October 28"
    final timeAlabama = t.someKey.sentence2(myValue);
    print(timeAlabama); // "Good Heavens, just look at the time! It's 22:30!"
    
    
    // The following is a mock of running this code in a GMT+1 time zone
    final dateEurope = t.someKey.sentence1(myValue);
    print(morningAlabama); // "Morning! Oh, today it's Saturday, October 29"
    final timeEurope = t.someKey.sentence2(myValue);
    print(timeAlabama); // "Good Heavens, just look at the time! It's 04:30!"
    

    Let me know what you think about this.

    enhancement 
    opened by lucavenir 6
  • Default parameters for non-rich nodes

    Default parameters for non-rich nodes

    Motivation RichText has default parameters. Normal ones (StringText) shall have this feature too.

    Developer Experience Similar to RichText using brackets (...), e.g. Welcome {name(User)}

    String a = t.welcome(name: 'Tom'); // Welcome Tom
    String b = t.welcome(); // Welcome User
    
    enhancement 
    opened by Tienisto 0
  • Unsure how to use slang with riverpod + locale preference

    Unsure how to use slang with riverpod + locale preference

    For my app the Locale comes out of a riverpod provider (ref.watch(settingsControllerProvider.select((s) => s.appLocale())) and I don't know how to connect this to the slang interface.

    For the intl module, you just make your top-level widget a ConsumerWidget, it uses ref.watch as above, then passes that locale to the MaterialApp locale argument. Then whenever the locale is changed, the entire widget tree is rebuilt with the new language.

    With slang, when if I update the locale, the widget tree is not rebuilt, and stays in English.

    I am not sure what I am doing wrong here. My widget tree is main() -> runApp(TranslationProvider(child: MyApp())) where MyApp calls appLocale = ref.watch(...) and returns MaterialApp(locale: appLocale). Debug print shows the MaterialApp is being created with a new locale, but nothing is updated.

    If I manually call LocaleSettings.setLocale( in the build method of MyApp, I get the error FlutterError (setState() or markNeedsBuild() called during build. This TranslationProvider widget cannot be marked as needing to build because the framework is already in the process of building widgets. ....

    question 
    opened by richardjharris 3
Releases(v3.7.0)
  • v3.7.0(Dec 19, 2022)

  • v3.6.0(Dec 15, 2022)

  • v3.5.0(Nov 24, 2022)

    • feat: csv decoding now support both CRLF and LF, " and '
    • fix: LocaleSettings.setPluralResolver should not throw an assertion error
    • fix: flutter pub run slang migrate should also work without : in command
    Source code(tar.gz)
    Source code(zip)
  • v3.4.0(Nov 12, 2022)

    • feat: add --locale=<locale> argument to flutter pub run slang apply to only apply a specific locale
    • BREAKING (TOOL): --flat argument for flutter pub run slang analyze and apply is no longer available
    Source code(tar.gz)
    Source code(zip)
  • v3.3.1(Nov 2, 2022)

  • v3.3.0(Oct 29, 2022)

    • feat: flutter pub run slang analyze now also checks unused translations (on top of missing translations)
    • docs: prefer slang analyze over slang:analyze (and for all other commands); both styles are supported however
    Source code(tar.gz)
    Source code(zip)
  • v3.2.0(Oct 27, 2022)

    • feat: add command flutter pub run slang:apply to add translations from the slang:analyze result
    • fix: handle isFlatMap parameter when overriding translations correctly
    • fix: update arb migration tool to respect new modifier syntax
    Source code(tar.gz)
    Source code(zip)
  • v3.1.0(Oct 8, 2022)

  • v3.0.0(Sep 20, 2022)

    Translation Overrides and Enhanced Modifiers

    • feat: it is now possible to override translations via LocaleSettings.overrideTranslations (checkout updated README)
    • feat: there is a new modifier syntax which allows for multiple modifiers e.g. myKey(plural, rich)
    • feat: improve file scan (now only checks top-level directory for any config files)
    • Breaking: default plural parameter is now n; you can revert this by setting pluralization/default_parameter: count
    • Breaking: custom plural/context parameter must follow syntax apples(param=appleCount)

    All breaking changes will result in a compile-time error, so don't worry for "hidden" bugs :)

    You can read the detailed migration guide here.

    Source code(tar.gz)
    Source code(zip)
  • v2.8.0(Sep 16, 2022)

    • feat: add AppLocaleUtils.parseLocaleParts
    • fix: LocaleSettings.useDeviceLocale now does not complain of weird locales on Linux
    • fix: rich text now handles all characters
    • fix: rich text properly applies param_case
    • fix: empty nodes are rendered as classes instead of claiming them as plurals
    Source code(tar.gz)
    Source code(zip)
  • v2.7.0(Aug 8, 2022)

    • feat: ignore empty plural / context nodes when fallback_strategy: base_locale is used
    • feat: add coverage:ignore-file to generated file and ignore every lint
    Source code(tar.gz)
    Source code(zip)
  • v2.6.2(Jul 28, 2022)

  • v2.6.1(Jun 14, 2022)

  • v2.6.0(Jun 13, 2022)

    • feat: render context enum values as is, instead of forcing to camel case
    • feat: add additional lint ignores to generated file
    • fix: generate correct ordinal (plural) call
    • fix: handle rich texts containing linked translations
    Source code(tar.gz)
    Source code(zip)
  • v2.5.0(Jun 7, 2022)

    • feat: add extension method shorthand (e.g. context.tr.someKey.anotherKey)
    • feat: add LocaleSettings.getLocaleStream to keep track of every locale change
    • feat: return more specific TextSpan instead of InlineSpan for rich texts
    Source code(tar.gz)
    Source code(zip)
  • v2.4.1(May 31, 2022)

  • v2.4.0(May 31, 2022)

    • feat: allow external enums for context feature (add generate_enum and imports config)
    • feat: add default context parameter name (default_parameter)
    • feat: add export statement in generated file to avoid imports of extension methods
    Source code(tar.gz)
    Source code(zip)
  • v2.3.1(May 22, 2022)

  • v2.3.0(May 18, 2022)

    • feat: use tight version for slang_flutter and slang_build_runner
    • fix: throw error if base locale not found
    • fix: TranslationProvider should use current locale
    • fix: use more strict locale regex to avoid false-positives when detecting locale of directory name
    Source code(tar.gz)
    Source code(zip)
  • v2.2.0(May 16, 2022)

  • v2.1.0(May 13, 2022)

  • fast_i18n-v5.12.4(May 13, 2022)

  • v2.0.0(May 11, 2022)

    Transition to a federated package structure

    • Breaking: rebranding to slang
    • Breaking: add slang_build_runner, slang_flutter depending on your use case
    • Breaking: remove output_file_pattern (was deprecated)
    • feat: dart-only support (flutter_integration: false)
    • feat: multiple package support
    • feat: RichText support

    Thanks to @fzyzcjy.

    You can read the detailed migration guide here.

    Source code(tar.gz)
    Source code(zip)
  • fast_i18n-v5.12.3(May 6, 2022)

  • fast_i18n-v5.12.2(Apr 23, 2022)

  • fast_i18n-v5.12.1(Apr 12, 2022)

  • fast_i18n-v5.12.0(Mar 18, 2022)

    • feat: add comments feature for json and csv files
    • feat: new command flutter pub run fast_i18n:migrate arb en.arb en.json to migrate ARB files
    Source code(tar.gz)
    Source code(zip)
  • fast_i18n-v5.11.0(Feb 20, 2022)

    • feat: new command flutter pub run fast_i18n stats to get number of words, characters, etc.
    • fix: create missing directories instead of throwing an error
    Source code(tar.gz)
    Source code(zip)
  • fast_i18n-v5.10.0(Feb 9, 2022)

  • fast_i18n-v5.9.0(Jan 19, 2022)

    Dependency Injection (optional)

    Plural resolvers are now part of the translation class.

    Meaning, you can now build your own instance without relying on LocaleSettings or any other side effects.

    This is entirely optional! You can still use the included LocaleSettings solution.

    // riverpod example
    final english = AppLocale.en.build(cardinalResolver: myEnResolver);
    final german = AppLocale.de.build(cardinalResolver: myDeResolver);
    final translationProvider = StateProvider<StringsEn>((ref) => german);
    
    // access the current instance
    final t = ref.watch(translationProvider);
    String a = t.welcome.title;
    

    For more information, checkout the full article.

    Source code(tar.gz)
    Source code(zip)
Owner
Tien Do Nam
Tien Do Nam
Alternative i18n tool for Dart and Flutter.

Simple internationalization (i18n) package for Dart and Flutter. Supports: AngularDart Flutter hot reload deferred loading of translations social dist

fnx.io 32 Dec 10, 2022
Small sample app to work on simplifying the i18n process

l10n_s12n A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if thi

Shi-Hao Hong 11 Jul 19, 2020
A lightweight flutter package to linkify texts containing urls, emails and hashtags

linkfy_text A lightweight flutter package to linkify texts containing urls, emails and hashtags. Usage To use this package, add linkfy_text as a depen

Stanley Akpama 14 Nov 23, 2022
Bhagavad Gita app using flutter & Bhagavad-Gita-API is A lightweight Node.js based Bhagavad Gita API [An open source rest api on indian Vedic Scripture Shrimad Bhagavad Gita].

Gita Bhagavad Gita flutter app. Download App - Playstore Web Application About Bhagavad Gita app using flutter & Bhagavad-Gita-API is A lightweight No

Ravi Kovind 7 Apr 5, 2022
A lightweight HTML-Richtext editor for Flutter

Flutter HTML Editor Flutter HTML Editor is a simple HTML-based Richtext editor, which is able to edit and parse a selected set of HTML tags into a Flu

Herry 14 Oct 19, 2022
A lightweight flutter plugin to check if your app is up-to-date on Google Play Store or Apple App Store

App Version Checker this package is used to check if your app has a new version on playstore or apple app store. or you can even check what is the lat

Iheb Briki 6 Dec 14, 2022
Easy to use, reliable and lightweight gesture detector for Flutter apps, exposing simple API for basic gestures

Simple Gesture Detector Easy to use, reliable and lightweight gesture detector for Flutter apps. Exposes simple API to react to basic gestures. Featur

Aleksander WoΕΊniak 26 Nov 4, 2022
A lightweight & effective Todo app made with Flutter

Blue Diary A lightweight & effective Todo app made with Flutter. Supports English and Korean. Screenshots β€’ Download β€’ Usage β€’ Architecture β€’ Feedback

Hansol Lee 152 Dec 6, 2022
Zerker is a lightweight and powerful flutter graphic animation library

What is Zerker Zerker is a flexible and lightweight flutter canvas graphic animation library. With Zerker, you can create a lot of seemingly cumbersom

FlutterKit 519 Dec 31, 2022
Fa-chapter-2 - Lightweight Recipe App Built With Flutter

Recipe App Our app will offer a hard-coded list of recipes and let us use a Slid

Siphumelelo Talent Qwabe 0 Jan 2, 2022
Bmprogresshud - A lightweight progress HUD for Flutter app

bmprogresshud A lightweight progress HUD for your Flutter app, Inspired by SVProgressHUD. Showcase Example local HUD place ProgressHud to you containe

bomo 34 Nov 19, 2021
The typesafe, reactive, and lightweight SQLite abstraction for your Flutter applications

See the project's website for the full documentation. Floor provides a neat SQLite abstraction for your Flutter applications inspired by the Room pers

Vitus 786 Dec 28, 2022
The lightweight and powerful wrapper library for Twitter Ads API written in Dart and Flutter 🐦

TODO: Put a short description of the package here that helps potential users know whether this package might be useful for them. Features TODO: List w

Twitter.dart 2 Aug 26, 2022
πŸ‘‘ The lightweight design pattern for small management applications.

Store Pattern ?? The lightweight design pattern for small management applications. Features | Structure | Install | Usage | Documents | Technologies |

UITers 71 Sep 26, 2022
Lightweight and blazing fast key-value database written in pure Dart.

Fast, Enjoyable & Secure NoSQL Database Hive is a lightweight and blazing fast key-value database written in pure Dart. Inspired by Bitcask. Documenta

HiveDB 3.4k Dec 30, 2022
A clean and lightweight progress HUD for your iOS and tvOS app.

SVProgressHUD SVProgressHUD is a clean and easy-to-use HUD meant to display the progress of an ongoing task on iOS and tvOS. Demo Try SVProgressHUD on

SVProgressHUD 12.4k Jan 3, 2023
Lightweight and blazing fast key-value database written in pure Dart.

Fast, Enjoyable & Secure NoSQL Database Hive is a lightweight and blazing fast key-value database written in pure Dart. Inspired by Bitcask. Documenta

HiveDB 3.4k Dec 30, 2022
dna, dart native access. A lightweight dart to native super channel plugin

dna, dart native access. A lightweight dart to native super channel plugin, You can use it to invoke any native code directly in contextual and chained dart code.

Assuner 14 Jul 11, 2022
Lightweight internet connection test, lookup a domain.

palestine_connection Lightweight internet connection test, lookup Google domain. Part of PalestineDevelopers project Features Periodic internet connec

Palestine Developers 5 Jun 26, 2022