-
Notifications
You must be signed in to change notification settings - Fork 14
Integration with GetX
This sample shows how to integrate fts with GetX.
Use the following template as starting point.
It uses GetMaterialApp
and a local HomePageController
to control the counter.
Click to expand
If you come from the Setup Wiki, delete the following folders and their contents so you can start clean:
- /strings/
- /assets/
- /lib/i18n/
Add the needed dependencies in pubspec.yaml
, as stated in the docs:
dependencies:
flutter:
sdk: flutter
get:
Let's take the Strings from the template app.
Open your terminal and execute:
fts extract -s -p lib/ -o strings/strings.yaml
show sample
extract searches recursively in --path lib/
for any dart files (check fts extract --help
to define other extensions), and tries to capture the Strings it finds, by default creating the keys based on a counter (textN
) and a folder-file structure.
strings/strings.yaml
main:
text1: "{{value}}"
text2: A beautiful counter
text3: "You have pushed the button this many times:"
text4: Increment
The Counter App template is very basic, just a few lines of code. But in real projects,
extract
can truly help to keep the keys and strings in a single place very fast.
Clean, and rename keys in the master strings file to keep what we will use:
appbarTitle: A beautiful counter
message: "You have pushed the button this many times:"
tooltip: Increment
Configure the output from trconfig.yaml
Open trconfig.yaml and comment (or remove) the following line:
#output_arb_template: lib/l10n/intl_*
We will not use .arb files this time.
Also make these changes:
entry_file: strings/strings.yaml
dart:
## let's make use of hardcoded generated Maps for messages.
use_maps: true.
With comments removed, trconfig.yaml should look like this:
output_json_template: assets/i18n/*.json
entry_file: strings/strings.yaml
param_output_pattern: "{*}"
dart:
output_dir: lib/i18n
keys_id: TKeys
translations_id: TData
use_maps: true
locales:
- en
- es
- ja
gsheets:
use_iterative_cache: false
credentials_path: credentials.json
spreadsheet_id: {SHEET_ID} ## Sheet id from Configuration setup page.
worksheet: Sheet1
In the Terminal execute fts run
again. The output might be a little verbose, but shows you the progress while it tries to sync the data, clearing some, now, inexistent keys from the sheet and creating new rows for the data we just defined in strings.yaml
.
The worksheet should look like this:
And your project should have new files and folders generated:
Open lib/main.dart
and modify GetMaterialApp
to support locales:
import 'i18n/i18n.dart';
/// ...
return GetMaterialApp(
debugShowCheckedModeBanner: false,
localeResolutionCallback: (_, __) => const Locale('en'),
locale: Locale('es'), /// new
supportedLocales: AppLocales.supportedLocales, /// new
translationsKeys: TData.byText, /// new
home: HomePageView(),
);
Warning: In Flutter >= 2.2.3, setting
localeResolutionCallback
avoids the exception "No MaterialLocalizations found." when not usingflutter_localizations
dependency.
Set an existing locale to GetMaterialApp
... the default template already generated en, es and ja if you didn't modify it.
Getx localization works with a simple key/value Map... that's why we defined use_maps: true
in trconfig.yaml.
Yet, with this simple approach, we will be able to load external .json files and use the same code.
By using TData.byText
we will associate the master text to the yaml keys, instead of consuming the keys. So just append .tr
to your Strings. Let's change the AppBar's title:
appBar: AppBar(
title: Text('A beautiful counter'.tr),
),
After hot-restart you should see:
Is really easy to get a String translated in this way; yet, we should agree that relying on existing Strings in the app as keys is dangerous, and doesn't scale well. Just know that you have the option to quickly localize your Strings this way.
To be safe, we'll use the keys instead.
Change in GetMaterialApp
:
translationsKeys: TData.byKeys,
Using the keys defined in trconfig.yaml, in step 2, we access the Map
associated with the current locale.
Let's change the AppBar's title again:
appBar: AppBar(
// title: Text('A beautiful counter'.tr),
title: Text('appbarTitle'.tr), // new
),
You should see exactly the same text. Using keys like this allow us to change the master text independently from the code, and scale without issues. But in bigger apps, when you have hundreds of localized strings, becomes tedious very soon to look which key is the correct one for specific UI element.
Also, hardcoded Strings are error-prone, let's say we make a typo and write appbarTitl
or appbartitle
... the key doesn't exists in the translation Map
, and even if the missing key error will be visible on screen while you test your app; if the app is big enough, with several nested Routes, it will become risky to make a mistake you will not notice.
That's why we have keys_id: TKeys
in trconfig.yaml.
It resolves the key access in a Type-safe way, navigating through the objects, replicating the master text structure in strings.yaml
appBar: AppBar(
// title: Text('A beautiful counter'.tr),
// title: Text('appbarTitle'.tr),
title: Text(TKeys.appbarTitle.tr), // new
),
Now, we have code hints in the IDE for the keys (remember it just resolves the actual key String, so you have to add the .tr
)
Maybe you notice we need to add the variable counter
in our Strings
In getx you have 2 ways to add the placeholders:
- using positional arguments
List<String>
- or parameters
Map<String,String>
.
The translation parameters in GetX are interpreted as @variable
, so we need to modify trconfig.yaml to generate placeholders in that fashion. That's the purpose of param_output_pattern
:
## param_output_pattern: "{*}"
param_output_pattern: "@*" ## new
As we don't change our master data structure in strings.yaml, you can run fts fetch
.
Let's change the code to take parameters:
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Obx(
() => Text(
TKeys.message.trParams({'counter': controller.counterText}),
),
),
],
),
),
... hot-restart:
As we noticed, fts
generates some utility code at lib/i18n/i18n.dart
to simplify part of the integration.
AppLocales
contains the available Locales and LangVo
objects (LangVo
(ValueObjects models) holds some useful properties: english name, native name, emoji flag and locale id and instance) of the current available locales.
For quick tests switching languages, SimpleLangPicker
, is a dropdown menu that automatically fills the items with AppLocales.available
.
In order to change Locale (language), we need to re-build GetMaterialApp
, with Getx is pretty simple, just call Get.updateLocale()
and the Widgets will rebuild.
Let's add the language selector:
appBar: AppBar(
title: Text(TKeys.appbarTitle.tr),
actions: [
SimpleLangPicker(
onSelected: Get.updateLocale,
selected: Get.locale,
),
],
),
The power of fts is the simplicity to keep a single structured data source. Add a a few more languages to trconfig.yaml.
locales:
- en
- es
- ja
- fa # Persian
- el # Greek
- ru # Russian
- zh # simplified Chinese
open Terminal and run:
fts run
Right away, new columns in your worksheet will hold the new available locales with the automatic translations and everything will be synced (also the app bundles.)
... hot-restart
If you speak Spanish, you can spot the inaccurate translations in the es
column in the worksheet.
When you try to edit the cell's text, you will see the translate formula instead:
Although you can type right away and replace the cell's content with the raw text, might be more practical to have the raw translated text:
- Select all cells (⌘+A or Ctrl+A)
- Copy (⌘+C or Ctrl+C)
- Paste "special" (⌘+Shift+V or Ctrl+Shift+V)
Or right click on the selection and find the context menu item:
Every row requires a modification:
- "Un hermoso mostrador" > "Un hermoso contador"
- "Has presionado el botón {{0}} Times:" > "Has presionado el botón {{0}} veces:"
- "Incremento:" > "Incrementar"
fts
needs to get the updated strings from the sheet...
Instead of using the run
command, we can use fetch
, as there's no need to sync the source data into the sheet... only retrieve the values, so overall, it's a faster and lighter process, as long as you didn't change the keys or master text in strings.yaml
. In that case your data will end up out of sync.
Run in your terminal:
fts fetch
And the output files (dart files in this case) will be updated:
Later we will show how to use the generated json files to load your localized texts at runtime.