Плагин Flutter Intl, используемый с динамическими строками

Я использую плагин Flutter Intl от Localizely для локализации своего приложения. Я сгенерировал файлы arb для нужных мне языков и начал вводить переводы.

Например:

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

Каждый раз, когда я хочу локализовать текст, который использую:

S.of(context).favouritesSection;

И работает отлично.

Однако, когда у меня есть такой список:

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

И я нахожусь внутри цикла itemBuilder, подобного этому:

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

Очевидно, что это не работает, поскольку "sectionName" не является ключом в файле произвольной настройки. Но я думаю, что код выражает то, чего я хочу достичь. Может кто мне поможет. Заранее спасибо.

3 ответа

Решение

Другой способ решить эту проблему - использовать сообщения типа Select ICU format.
Обратите внимание, это решение может вводить некоторые ограничения, но, с другой стороны, оно более элегантно.

Объявление строкового ключа:

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

Использование строкового ключа:

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

Я думаю, есть два способа добиться желаемого.

Первый - это создание функции, которая отображает ваши sectionTitles в ваши строки intl, примерно так:

  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;
    }
  }

И используя вот так:

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

Второй - создание массива с вашими строками intl:

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

Но вам нужно будет создать это внутри вашей функции сборки, потому что вам нужен контекст:

  @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],
            );
          },
    ...
  }

Другой способ добиться этого без использования контекста из вашей функции сборки - использовать didChangeDependencies метод доступен на StatefulWidgets, нравится:

 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],
            );
          },
    ...
  }

Обратите внимание, что в этом случае вы не можете использовать initState потому что он не предоставит контекст с уже доступными строками intl, поэтому мы используем didChangeDependencies.

Если вам интересно, что ??= делает, он просто проверяет, есть ли у переменной (в данном случае sectionTitles) имеет значение null, и если это так, он присвоит ему значения. Мы используем его здесь, чтобы не переопределятьsectionTitles каждый раз.

Вы пробовали использовать S.of(context)[sectionName] вместо?

Другие вопросы по тегам