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.

2 Answers 2

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),
                  ),
                },
Sign up to request clarification or add additional context in comments.

5 Comments

That is what I was looking for!
Great, I'm glad it helped!
It's hard to understand the first code snippet. It would be easier with some explanation
@Ced 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}}
@ZoranLuledzija hvala Zorane!
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.