Строковый XML-файл во Флаттере

Привет, я Android-разработчик, плохо знакомый с трепетом. В тексте строки флаттера прямо устанавливаются текстовые поля виджета.

(То есть)

new Text('Hello,  How are you?')

Это правильный путь? или мы можем сохранить всю строку в одном файле и использовать ее.

(То есть)

<string name="name_hint">Hello, How are you?</string>

Возможно ли это? Любая помощь будет оценена, спасибо заранее.

10 ответов

Flutter в настоящее время не имеет выделенной ресурсной системы для строк. На данный момент лучше всего хранить текст в классе как статические поля и получать к ним доступ оттуда. Например:

class Strings {
  static String welcomeMessage = "Welcome To Flutter";
}

Затем в вашем коде вы можете получить доступ к своим строкам как таковым:

Text(Strings.welcomeMessage)

источник

Для тех из вас, кто не хочет использовать какой-либо сторонний плагин, вот как вы можете это сделать.

  1. Создать папку strings в asset, Поместите в него свой языковой файл.

    asset
      strings
      - en.json // for english 
      - ru.json  // for russian
    
  2. Сейчас в en.json напишите свою строку, например.

    {
      "text1": "Hello",
      "text2": "World"
    }
    

    Точно так же в ru.json,

    {
      "text1": "Привет",
      "text2": "Мир"
    }
    
  3. Добавьте это к pubspec.yaml файл (обратите внимание на пробелы)

    flutter:
    
      uses-material-design: true
    
      assets:
        - assets/json/en.json
        - assets/json/ru.json
    
  4. Теперь все готово для использования этих строк в вашем приложении. Вот пример кода, AppBar показывает переведенный текст.

    void main() {
      runApp(
        MaterialApp(
          locale: Locale("ru"), // switch between en and ru to see effect
          localizationsDelegates: [const DemoLocalizationsDelegate(), GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate],
          supportedLocales: [const Locale('en', ''), const Locale('ru', '')],
          home: HomePage(),
        ),
      );
    }
    
    class HomePage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: Text(DemoLocalizations.of(context).getText("text2") ?? "Error")),
        );
      }
    }
    
    // this class is used for localizations
    class DemoLocalizations {
      static DemoLocalizations of(BuildContext context) {
        return Localizations.of<DemoLocalizations>(context, DemoLocalizations);
      }
    
      String getText(String key) => language[key];
    }
    
    Map<String, dynamic> language;
    
    class DemoLocalizationsDelegate extends LocalizationsDelegate<DemoLocalizations> {
      const DemoLocalizationsDelegate();
    
      @override
      bool isSupported(Locale locale) => ['en', 'ru'].contains(locale.languageCode);
    
      @override
      Future<DemoLocalizations> load(Locale locale) async {
        String string = await rootBundle.loadString("assets/json/${locale.languageCode}.json");
        language = json.decode(string);
        return SynchronousFuture<DemoLocalizations>(DemoLocalizations());
      }
    
      @override
      bool shouldReload(DemoLocalizationsDelegate old) => false;
    }
    

Вы можете использовать методы, представленные в разделах интернационализации документации, для управления как централизованным управлением строками, так и переводами (если вам нужны переводы)

https://flutter.io/tutorials/internationalization/

Это может быть излишним для простого приложения с несколькими строками.

Я бы разделил эти классы на отдельные файлы, но просто чтобы объяснить свой подход к этому вопросу.

У меня есть базовый класс, в котором есть геттеры строк. Для каждого языка, который я хочу поддерживать, мне нужно создать класс, расширяющий этот класс, и переопределить его методы получения. Таким образом, всякий раз, когда я создаю строку, я должен переопределить в каждой реализации этого базового класса. Полезно не забыть создать строку, специфичную для локали.

      /// Interface strings
class Strings {

  String get hello;
}


/// English strings
class StringsEnglish extends Strings {
   
  @override
  String get hello => 'Hello';
}

/// Russian strings
class StringsRussian extends Strings {
  @override
  String get hello => 'Привет';
}

/// Portuguese strings
class StringsPortuguese extends Strings {
  @override
  String get hello => 'Olá';
}

После этого в глобальной области вашего приложения вы можете объявить уникальный экземпляр языкового стандарта, который хотите использовать (использование синглтона - хороший вариант).

Просто покажу краткий пример его использования:

       class Resources {
  BuildContext _context;

  Resources(this._context);

  Strings get strings {
    // It could be from the user preferences or even from the current locale
    Locale locale = Localizations.localeOf(_context);
    switch (locale.languageCode) {
      case 'pt':
        return StringsPortuguese();
      case 'ru':
        return StringsRussian();
      default:
        return StringsEnglish();
    }
  }

  static Resources from(BuildContext context){
    return Resources(context);
  }
}

И наконец, используя его в каком-нибудь виджете:

      Text(Resources.from(context).strings.hello)

Использование расширения из BuildContext

Вы можете расширить BuildContext для создания некоторых конкретных функций и придания большей мощности вашему приложению. Это доступно в Dart 2.7 . Увидеть больше .

app_context_extension.dart

      extension AppContext on BuildContext {

  Resources get resources => Resources.from(this);

}

избранное_page.dart

      import 'package:flutter/material.dart';
// you have to import it yourself. The auto import does not work in this case
import 'package:myapp/ui/extensions/app_context_extension.dart';

class FavoritesPage extends StatefulWidget {
  @override
  _FavoritesPageState createState() => _FavoritesPageState();
}

class _FavoritesPageState extends State<FavoritesPage> {
  @override
  Widget build(BuildContext context) {
    return Text(context.resources.strings.hello);
  }
}

Использование GlobalKey

Наряду с расширением BuildContext, как показано выше, вы также можете использовать GlobalKey. В принципе, вы можете использовать его, когда у вас нет экземпляра контекста. У последнего есть хорошее преимущество. Вы можете использовать строки в любом месте вашего приложения. Другими словами, если вы используете какой-то шаблон, например, MVC, и хотите использовать строки в своих контроллерах, вы можете легко это сделать.

Вы можете объявить что-то вроде этого:

application.dart

      import 'package:myapp/ui/extensions/app_context_extension.dart';
import 'package:myapp/ui/values/resources.dart';
import 'package:flutter/material.dart';

class Application {
  static GlobalKey<NavigatorState> navKey = GlobalKey();

  static Resources get resources {
    return navKey.currentContext.resources;
  }
}

main.dart

      class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: Application.navKey,
...

А потом:

      import 'package:flutter/material.dart';
import 'package:myapp/application/application.dart';

class FavoritesPage extends StatefulWidget {
  @override
  _FavoritesPageState createState() => _FavoritesPageState();
}

class _FavoritesPageState extends State<FavoritesPage> {
  @override
  Widget build(BuildContext context) {
    return Text(Application.resources.strings.hello);
  }
}

Надеюсь, поможет!

Прежде всего, создайте новую папку strings в assetsи добавьте свои языковые файлы JSON.

      assets
  strings
    - en.json
    - ar.json

Это ваш en.jsonфайл

      {
  "title": "Flutter app"
}

И это твой ar.jsonфайл

      {
  "title": "تطبيق Flutter"
}

Затем измените свой pubspec.yamlфайл, как показано ниже.

      dependencies:
  # your other codes
  intl: ^0.17.0
  flutter_localizations:
    sdk: flutter


  # your other codes

flutter:
  uses-material-design: true

  assets:
    - assets/strings/en.json
    - assets/strings/ar.json

После этого создайте AppLocalizations.dartучебный класс

      import 'dart:convert';

import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';

class AppLocalizations {
  static AppLocalizations of(BuildContext context) {
    return Localizations.of<AppLocalizations>(context, AppLocalizations);
  }

  String getText(String key) => language[key];
}

Map<String, dynamic> language;

class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
  const AppLocalizationsDelegate();

  @override
  bool isSupported(Locale locale) => ['en', 'ar'].contains(locale.languageCode);

  @override
  Future<AppLocalizations> load(Locale locale) async {
    String string = await rootBundle.loadString("assets/strings/${locale.languageCode}.json");
    language = json.decode(string);
    return SynchronousFuture<AppLocalizations>(AppLocalizations());
  }

  @override
  bool shouldReload(AppLocalizationsDelegate old) => false;
}

Наконец в вашем main.dartфайл внесите следующие изменения

      void main() async {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: AppLocalizations.of(context).getText("title"),
      locale: Locale("en"),
      localizationsDelegates: [const AppLocalizationsDelegate()],
      supportedLocales: [const Locale('en', ''), const Locale('ar', '')],  
      home: HomeScreen(),
    );
  }
}

Я использую этот метод вместо сторонней библиотеки. По сути, я создаю класс, содержащий эти значения (строка, цвета, размеры и т. Д.).

resources.dart

import 'dart:ui';

class ResString{
  var data = {
    'url' : 'https://facebook.com/',
    'welcome' : 'Welcome Home',
  };

  String get(String key){
    return data[key];
  }
}

class ResColor{
  var data = {
    'colorPrimary' : 0xff652A04,
    'colorPrimaryDark' : 0xffFFFFFF,
    'colorPrimaryLight' : 0xffF6EDDD,
  };

  Color get(String key){
    return Color(data[key]);
  }
}

Чтобы использовать его, просто вызовите метод get

main.dart

import 'package:my_app/resources.dart';
...
    return Container(
      color: ResColor().get('colorPrimary')
    );
...
  create "Strings.dart" file and add the below line==>


 class Strings
 {
      static String welcomeScreen="WelCome Page";
      static String loadingMessage="Loading Please Wait...!";
 }

 And then call the file using the below line using the widget
 Text(Strings.loadingMessage)

 Make sure that the String.dart file has been imported

Совсем не смешно управлять языками, в Android Studio есть встроенный плагин Transalte the words, который позволяет вам легко управлять, поэтому вы можете видеть в таблице ключ слова и результат на каждом языке, который вы только что добавить, вручную конечно. Надеюсь, скоро во Flutter!

Я попробовал некоторые из решений, предложенных в этом посте, но тот, что из @Fakhriddin Abdullaevбыл тот, который работал хорошо для меня. Но мне не понравилось то, что нужно всегда искать ключ каждой строки в файлах.

Поэтому я создал strings.dart:

      import 'package:/AppLocalizations.dart';

class Strings {
  static String error =  "Error Message";
  static AppLocalizations? locator = AppLocalizations();

  // ignore: non_constant_identifier_names
  static String app_name = locator?.getText("app_name") ?? error;

}

При наличии записи в .jsonфайлы, такие как:

      {
  "app_name" : "My awesome AppName",
}

вам просто нужно позвонить strings.и завершение кода предложит нужную строку:

Но не забудьте инициализировать Strings.locatorс правильным контекстом:

          Strings.locator = AppLocalizations.of(context);

Это правильный путь. В трепетании не нужно .xml или же .css файлы для управления вашим макетом / вещи.

Все управляется с помощью кода дротика. Что делает все намного проще.

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