Flutter 中的字符串 xml 文件

String xml file in Flutter

在 flutter 中,字符串文本直接设置为 TextField 小部件,例如:

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

是正确的方法吗?或者我们可以将所有字符串保存在一个文件中并像这样使用它:

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

可能吗?

这是正确的方法。在 flutter 中,您不需要 .xml.css 文件来管理您的 layout/stuff.

一切都使用飞镖代码进行管理。这让一切变得更简单。

您可以使用文档国际化部分中介绍的方法来控制集中式字符串管理和翻译(如果您需要翻译)

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

不过,对于只有几个字符串的简单应用程序来说,这可能有点矫枉过正。

Flutter 目前没有专门的字符串类资源系统。目前,最佳做法是将您的副本文本作为静态字段保存在 class 中,并从那里访问它们。例如:

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

然后在您的代码中,您可以这样访问您的字符串:

Text(Strings.welcomeMessage)

source


编辑 19 年 5 月:

现在 this package 允许您使用字符串创建 json 文件。它将允许您为复数、性别和语言等创建字符串

您可以像这样为每种语言创建单独的 json 文件:

string_en.json

{
"thanks": "Thanks."
}

string_nl.json

{    
"thanks": "Dankjewel."
}

然后用这个访问它

S.of(context).thanks;

它会根据您phone的默认语言知道选择哪种语言。

  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

截图:


完整代码(空安全):

对于那些不想使用任何第 3 方插件的人,这里是您可以使用的方法。

  1. assets 中创建文件夹 strings。将你的语言文件放入其中。

    assets
      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/strings/en.json
        - assets/strings/ru.json
    
    flutter_localizations:
      sdk: flutter
    
  4. 现在您已准备好在您的应用程序中使用这些字符串。这是示例代码,AppBar 显示翻译后的文本。

     void main() {
       runApp(
         MaterialApp(
           locale: Locale("ru"), // switch between en and ru to see effect
           localizationsDelegates: [const DemoLocalizationsDelegate()],
           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];
     }
    
     late 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/strings/${locale.languageCode}.json");
         language = json.decode(string);
         return SynchronousFuture<DemoLocalizations>(DemoLocalizations());
       }
    
       @override
       bool shouldReload(DemoLocalizationsDelegate old) => false;
     }
    

我用的是这个方法,没有用第三方库。基本上,我创建了一个 class 来保存这些值(字符串、颜色、维度等)

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')
    );
...

我会将这些 class 分成单独的文件,但只是为了解释我对这个问题的处理方法。

我有一个基础 class,它有我的字符串吸气剂。我想支持的每一种语言都必须创建一个 class,它从 class 扩展并覆盖它的 getter。因此,每当我创建一个字符串时,我都必须重写这个基础 class 的每个实现。这有助于避免忘记创建一些特定于语言环境的字符串。

/// Interface strings
class Strings {

  String get hello;
}


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

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

/// Portuguese strings
class PortugueseStrings 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 PortugueseStrings();
      case 'ru':
        return RussianStrings();
      default:
        return EnglishStrings();
    }
  }

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

最后,在一些小部件中使用它:

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

使用 BuildContext 的扩展

您可以扩展 BuildContext 以创建一些特定功能并为您的应用程序提供更多功能。 这可以从 Dart 2.7. See more.

获得

app_context_extension.dart

extension AppContext on BuildContext {

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

}

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

希望对您有所帮助!

管理语言一点都不有趣,AndroidStudio 有一个内置的 Transalte 插件,让您轻松管理,所以您可以在 table 中看到单词的关键字,以及您刚刚添加的每种语言的结果,当然是手动添加的。我希望 Flutter 很快就会出现!

首先,在 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.dartclass

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

我尝试了此 post 中建议的一些解决方案,但 @Fakhriddin Abdullaev 中的解决方案对我来说效果很好。但我不喜欢这样一个事实,即必须始终在 .json 文件中查找每个字符串的键。

所以我创建了一个 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);