Flutter Intl plugin used with dynamic Strings
Asked Answered
R

2

9

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.

Rodmann answered 6/6, 2020 at 21:31 Comment(0)
M
18

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),
                  ),
                },
Mordacious answered 8/6, 2020 at 15:14 Comment(5)
That is what I was looking for!Rodmann
Great, I'm glad it helped!Mordacious
It's hard to understand the first code snippet. It would be easier with some explanationKerwinn
@Kerwinn I know it's a bit late, but here (link) is the explanation of the Select format. Basically it goes like this: {varName, select, optionOne {translation of 1st option} secondOption {2nd option's translation} other {whatever doesn't get matched before gives this text}}Burr
@ZoranLuledzija hvala Zorane!Burr
B
1

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.

Behavior answered 7/6, 2020 at 2:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.