Строковый 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)
Для тех из вас, кто не хочет использовать какой-либо сторонний плагин, вот как вы можете это сделать.
Создать папку
strings
вasset
, Поместите в него свой языковой файл.asset strings - en.json // for english - ru.json // for russian
Сейчас в
en.json
напишите свою строку, например.{ "text1": "Hello", "text2": "World" }
Точно так же в
ru.json
,{ "text1": "Привет", "text2": "Мир" }
Добавьте это к
pubspec.yaml
файл (обратите внимание на пробелы)flutter: uses-material-design: true assets: - assets/json/en.json - assets/json/ru.json
Теперь все готово для использования этих строк в вашем приложении. Вот пример кода,
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
файлы для управления вашим макетом / вещи.
Все управляется с помощью кода дротика. Что делает все намного проще.