Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter Intl plugin used with dynamic Strings

I am using the Flutter Intl plugin by Localizely to localize my App. I generated arb files for the languages I want and begin to introduces the translations.

For example:

{
  "documentsSection": "All the documents",
  "favouritesSection": "Favourites",
  "newsSection": "News",
  "settingsSection": "Settings"
}

Everytime I want to localize a text I use:

S.of(context).favouritesSection;

And it works perfectly.

However, when I have a List like this:

List<Strings> sectionTitles = ["documentsSection","favouritesSection","newsSection","settingsSection"]

And I am inside an itemBuilder loop like this one:

itemBuilder: (context, index) {
                  String sectionName = sectionTitles[index];
                  return Text(
                      S.of(context).sectionName,
                  ),
                },

Obviously this doens't work, as "sectionName" is not a key in the arb file. But I think that the code express what I want to achieve. May be someone can help me. Thanks in advance.

like image 291
jRuMoL Avatar asked Jun 06 '20 21:06

jRuMoL


People also ask

How do you use Intl flutter?

Select the starter folder in the project directory then, on the menu bar, select Tools ▸ Flutter Intl ▸ Initialize for the Project. The command above added a flutter_intl section to your pubspec. yaml. Add main_locale: en_US to it, below and in the same indentation level of enabled: true .

What is Flutter_localizations?

Setting up an internationalized app: the Flutter_localizations package. By default, Flutter only provides US English localizations. To add support for other languages, an application must specify additional MaterialApp (or CupertinoApp ) properties, and include a package called flutter_localizations .


2 Answers

Another way to solve this is by using the Select ICU format kind of messages.
Note, this solution may introduce some constraints, but on the other hand, it is more elegant.

String key declaration:

"sectionTitles": "{section, select, documentsSection {Documents section} favouritesSection {Favourites section} newsSection {News section} settingsSection {Settings section} other {Section}}",
"@sectionTitles": {
  "placeholders": {
    "section": {}
  }
}

String key usage:

itemBuilder: (context, index) {
                  String sectionName = sectionTitles[index];
                  return Text(
                      S.of(context).sectionTitles(sectionName),
                  ),
                },
like image 160
Zoran Luledzija Avatar answered Sep 22 '22 07:09

Zoran Luledzija


I think there are two ways to achieve what you want.

The first is creating a function that maps your sectionTitles to your intl strings, something like this:

  String getSectionTitle(BuildContext context, String title) {
    if (title == "documentsSection") {
      return S.of(context).documentsSection;
    } else if (title == "favouritesSection") {
      return S.of(context).favouritesSection;
    } else if (title == "newsSection") {
      return S.of(context).newsSection;
    } else if (title == "settingsSection") {
      return S.of(context).settingsSection;
    }
  }

And using like this:

...
itemBuilder: (context, index) {
  return Text(
    getSectionTitle(context, sectionTitles[index]),
  );
},
...

The second is making an array with your intl strings:

List<String> sectionTitles = [
      S.of(context).documentsSection,
      S.of(context).favouritesSection,
      S.of(context).newsSection,
      S.of(context).settingsSection,
];

But you would need to create this inside your build function because you need a context:

  @override
  Widget build(BuildContext context) {
    List<String> sectionTitles = [
      S.of(context).documentsSection,
      S.of(context).favouritesSection,
      S.of(context).newsSection,
      S.of(context).settingsSection,
    ];
    return ...
          itemBuilder: (context, index) {
            return Text(
              sectionTitles[index],
            );
          },
    ...
  }

Another way of achieving this without using the context from your build function is by using the didChangeDependencies method available on StatefulWidgets, like this:

 List<String> sectionTitles;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    sectionTitles ??= [
      S.of(context).documentsSection,
      S.of(context).favouritesSection,
      S.of(context).newsSection,
      S.of(context).settingsSection,
    ];
  }

  @override
  Widget build(BuildContext context) {
    return ...       
          itemBuilder: (context, index) {
            return Text(
              sectionTitles[index],
            );
          },
    ...
  }

Note that in this case, you cannot use initState because it wouldn't provide a context with the intl strings already available, thus we use didChangeDependencies.

If you are wondering what does the ??= does, it simply checks if a variable (in this case sectionTitles) is null, and if it is, it will assign the values to it. We use it here to avoid redefining the sectionTitles every time.

like image 32
EdYuTo Avatar answered Sep 26 '22 07:09

EdYuTo