美文网首页
2024-02-26 flutter国际化

2024-02-26 flutter国际化

作者: 我是小胡胡123 | 来源:发表于2024-02-25 21:09 被阅读0次

本节主要介绍如何对 Flutter 应用进行国际化
使用3种方式来介绍国际化的使用

  • 方法1: 编写DemoLocalizations本地化类 ,定义每种语言的 Map
  • 方法2: 编写DemoLocalizations本地化类,使用 import 'package:intl/intl.dart';调用 Intl.message获取本地化,使用intl_translation命令,扫描项目中用到的intl.message生成 arb,然后配置arb文件添加不同语言

  • 方法3: 先编写xxx_xx.arb,flutter gen-l10n 命令生成本地化代码 AppLocalizations本地化类. 拆分成不同的文件

编写DemoLocalizations 类 本地化,使用Intl.message使用intl_translation

是指一个不依赖于 intl package 的 示例。手写一个语言资源的类,来代替intl pcakge基于arb json文件资源生成的类。

为app的本地化资源定义一个类DemoLocalizations


//选择自己的方法来管理本地化的值
//一个不依赖于 intl package 的 示例。
// #docregion Demo

//为 app 的本地化资源定义一个类
class DemoLocalizations {
  DemoLocalizations(this.locale);

  final Locale locale; //通过appMaterialApp创建时候,app启动时候,app获取系统的locale首选设置语言

  static DemoLocalizations of(BuildContext context) {
    //查看 app 当前的语言环境:
    Locale myLocale = Localizations.localeOf(context);

    //获取DemoLocalizations 实例
    return Localizations.of<DemoLocalizations>(context, DemoLocalizations)!;
  }

  //这里是手动编写代码
  static const _localizedValues = <String, Map<String, String>>{
    //定义每种语言的 Map
    'en': {
      'title': 'Hello World',
    },
    'es': {
      'title': 'Hola Mundo',
    },
  };

  static List<String> languages() => _localizedValues.keys.toList();

  String get title {
    //这里手动编写的代码, 在map中获取对应文字
    return _localizedValues[locale.languageCode]![
        'title']!; //这个app启动时候获取到的locale
  }
}
// #enddocregion Demo

定义一个DemoLocalizationsDelegate,给MaterialApp用,用于传递上述资源类

    // #docregion Delegate
    class DemoLocalizationsDelegate
        extends LocalizationsDelegate<DemoLocalizations> {
      const DemoLocalizationsDelegate();

      @override
      bool isSupported(Locale locale) =>
          DemoLocalizations.languages().contains(locale.languageCode);

      @override
      Future<DemoLocalizations> load(Locale locale) {
        // Returning a SynchronousFuture here because an async "load" operation
        // isn't needed to produce an instance of DemoLocalizations.
        //创建 DemoLocalizations实例,传入当前的locale对象,系统的语言类型
        return SynchronousFuture<DemoLocalizations>(DemoLocalizations(locale));
      }

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

MaterialApp中使用


class Demo extends StatefulWidget {
  Demo({super.key});

  @override
  State<Demo> createState() => _DemoState();
}

class _DemoState extends State<Demo> {
  Locale? myLocale1;

  @override
  Widget build(BuildContext context) {
 
    return MaterialApp(
      onGenerateTitle: (context) => DemoLocalizations.of(context).title,
  
      localizationsDelegates: const [
        //一个不依赖于 intl package 的 示例。
        DemoLocalizationsDelegate(),

        //创建 DemoLocalizations 实例,app获取系统 locale 传入DemoLocalizations
        //  //修改手机系统的语言后,所有后台app其实都被推出了,切换app触发冷启动
 

        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
 
      //语言环境定义
      supportedLocales: const [
        Locale('en', ''),
       Locale('es', ''),
    ],
 
      home: const DemoApp(),

     
    );
  }
}

void main() {
  runApp(Demo());
}

页面中使用


class DemoApp extends StatelessWidget {
  const DemoApp({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(DemoLocalizations.of(context).title), //获取实例
      ),
      body: Column(
        children: [
          Localizations.override(
            context: context,
            locale: const Locale('en'),
            //这里手动设置语言,app启动通过 delegate的load方法获取到的语言,会被这里的覆盖
            child: Builder(builder: (context) {
              return Column(
                children: [
                  Center(
              child: Text(DemoLocalizations.of(context).title),
 
                  ),
             
                ],
              );
            }),
          ),
          Container(
            height: 2,
            color: Colors.red,
            width: double.maxFinite,
          ),
          Localizations.override(
            context: context,
            locale: const Locale('es'),
            //这里手动设置语言,app启动通过 delegate的load方法获取到的语言,会被这里的覆盖
            child: Builder(builder: (context) {
              return Column(
                children: [
                  Center(
 
                    child: Text(AppLocalizations.of(context)!.helloWorld),
                  ),
               
                ],
              );
            }),
          ),
        ],
      ),
    );
  }
}

上面就完成了一个手写的方式实现的国际化文本的展示。

intl_translation扫描项目生成

实例:
intl_main.dart

// #docregion DemoLocalizations
class DemoLocalizations {
  DemoLocalizations(this.localeName);

  static Future<DemoLocalizations> load(Locale locale) {
    final String name =
    locale.countryCode == null || locale.countryCode!.isEmpty
        ? locale.languageCode
        : locale.toString();
    final String localeName = Intl.canonicalizedLocale(name);

    return initializeMessages(localeName).then((_) {
      return DemoLocalizations(localeName);
    });
  }

  static DemoLocalizations of(BuildContext context) {
    return Localizations.of<DemoLocalizations>(context, DemoLocalizations)!;
  }

  final String localeName;

  String get title {
    return Intl.message(
      'Hello World',
      name: 'title',
      desc: 'Title for the Demo application',
      locale: localeName,
    );
  }
}
// #enddocregion DemoLocalizations

class DemoLocalizationsDelegate
    extends LocalizationsDelegate<DemoLocalizations> {
  const DemoLocalizationsDelegate();

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

  @override
  Future<DemoLocalizations> load(Locale locale) =>
      DemoLocalizations.load(locale);

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

命令:

flutter pub get
dart run intl_translation:extract_to_arb --output-dir=lib/l10n lib/main.dart

结果,生成了intl_message.dart内容为:

{
  "@@last_modified": "2024-02-27T10:39:49.387951",
  "title": "Hello World",
  "@title": {
    "description": "Title for the Demo application",
    "type": "text",
    "placeholders": {}
  }
}

命令2:

dart run intl_translation:generate_from_arb --output-dir=lib/l10n --no-use-deferred-loading lib/main.dart lib/l10n/intl_*.arb

结果为 这3个文件:

45726-173e8e4e5a329258.jpeg

使用脚本自动生成代码

工程配置

pubspec.yaml添加intl库

    environment:
      sdk: ">=2.17.0 <3.0.0"
      flutter: ">=2.5.0 <4.0.0"


    dependencies:
      flutter:
        sdk: flutter
      flutter_localizations:
        sdk: flutter
      intl: any

生成的结果在.dart_tool目录下。

[图片上传失败...(image-3634de-1708952732637)]
通过

import 'package:flutter_gen/gen_l10n/app_localizations.dart';

可以使用生成的代码。

创建配置文件l10n.yaml

在项目目录根目录创建文件名 的 l10n.yaml 文件。

内容为:

arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart

在lib目录下创建文件夹名为l10n

在此文件夹下面添加语言资源文件

分别创建app_en.arb 和 app_es.arb

app_en.arb内容为:

    {
        "title": "Hello World",
        "@title":
        {
            "description": "Title for the Demo application",
            "type": "text"
        },
        "helloWorld": "Hello World!英文我修改了,直接pub get,只用一次 flutter gen-l10n ",
        "@helloWorld":
        {
            "description": "The conventional newborn programmer greeting"
        },
        "numberOfDataPoints": "Number of data points: {value}",
        "@numberOfDataPoints":
        {
            "description": "A message with a formatted int parameter",
            "placeholders":
            {
                "value":
                {
                    "type": "int",
                    "format": "compactCurrency",
                    "optionalParameters":
                    {
                        "decimalDigits": 2
                    }
                }
            }
        },
        "pronoun": "{gender, select, male{他} female{她} other{它}}",
        "@pronoun":
        {
            "description": "A gendered message",
            "placeholders":
            {
                "gender":
                {
                    "type": "String"
                }
            }
        },
        "nWombats": "{count, plural, =0{no wombats} =1{1 wombat} other{{count} wombats}}",
        "@nWombats":
        {
            "description": "A plural message",
            "placeholders":
            {
                "count":
                {
                    "type": "num",
                    "format": "compact"
                }
            }
        },
        "hello": "Hello {userName}",
        "@hello":
        {
            "description": "A message with a single parameter",
            "placeholders":
            {
                "userName":
                {
                    "type": "String",
                    "example": "Bob"
                }
            }
        }
    }

app_es.arb内容为:

    {
        "title": "Hola Mundo",
        "@title":
        {
            "description": "Title for the Demo application",
            "type": "text"
        },
        "helloWorld": "¡Hola Mundo!esessssss",
        "numberOfDataPoints": "Number of data points: {value}",
        "@numberOfDataPoints":
        {
            "description": "A message with a formatted int parameter",
            "placeholders":
            {
                "value":
                {
                    "type": "int",
                    "format": "compactCurrency",
                    "optionalParameters":
                    {
                        "decimalDigits": 2
                    }
                }
            }
        },
        "pronoun": "{gender, select, male{he} female{she} other{they}}",
        "@pronoun":
        {
            "description": "A gendered message",
            "placeholders":
            {
                "gender":
                {
                    "type": "String"
                }
            }
        },
        "nWombats": "{count, plural, =0{no wombats} =1{1 wombat} other{{count} wombats}}",
        "@nWombats":
        {
            "description": "A plural message",
            "placeholders":
            {
                "count":
                {
                    "type": "num",
                    "format": "compact"
                }
            }
        },
        "hello": "Hello {userName}",
        "@hello":
        {
            "description": "A message with a single parameter",
            "placeholders":
            {
                "userName":
                {
                    "type": "String",
                    "example": "Bob"
                }
            }
        }
    }

执行命令生成代码

flutter pub get
flutter gen-l10n

生成结果如下:


WX20240226-220243@2x.png

使用生成的代码

在main文件导入库:

 import 'package:flutter_gen/gen_l10n/app_localizations.dart';

MaterailApp初始化:

class Demo extends StatefulWidget {
  Demo({super.key});

  @override
  State<Demo> createState() => _DemoState();
}

class _DemoState extends State<Demo> {
 

@override
Widget build(BuildContext context) {
 
    return MaterialApp(
        onGenerateTitle: (context) => DemoLocalizations.of(context).title,

        localizationsDelegates: const [

          //这个示例是基于 intl package 提供的 API 和工具开发的, app 本地化资源的替代方法 里面讲解了
          AppLocalizations.delegate,

          GlobalMaterialLocalizations.delegate,
          GlobalWidgetsLocalizations.delegate,
        ],

         //语言环境定义 

        supportedLocales: [
            Locale('en', ''),
            Locale('es', ''),
        ],
        // intl工具也能生成,可以直接使用
        //localizationsDelegates: AppLocalizations.localizationsDelegates,
        //supportedLocales: AppLocalizations.supportedLocales,

        home: const DemoApp(),
      )
    }
}

void main() {
  runApp(Demo());
}

页面使用

class DemoApp extends StatelessWidget {
const DemoApp({super.key});

@override
Widget build(BuildContext context) {
return Scaffold(

      body: Column(
        children: [
          Localizations.override(
            context: context,
            locale: const Locale('en'),
            //这里手动设置语言,app启动通过 delegate的load方法获取到的语言,会被这里的覆盖
            child: Builder(builder: (context) {
              return Column(
                children: [
                  Center(

                    child: Text(AppLocalizations.of(context)!.helloWorld),
                  ),
                  Text(AppLocalizations.of(context)!.numberOfDataPoints(100)),
                  // Returns 'he'
                  Text(AppLocalizations.of(context)!.pronoun('male')),
                  // Returns 'she'
                  Text(AppLocalizations.of(context)!.pronoun('female')),
                  // Returns 'they'
                  Text(AppLocalizations.of(context)!.pronoun('other')),

                  // Returns 'no wombats'
                  Text(AppLocalizations.of(context)!.nWombats(0)),
                  // Returns '1 wombat'
                  Text(AppLocalizations.of(context)!.nWombats(1)),
                  // Returns '5 wombats'
                  Text(AppLocalizations.of(context)!.nWombats(5)),
                  Text(AppLocalizations.of(context)!.hello('John')),
                ],
              );
            }),
          ),
          Container(
            height: 2,
            color: Colors.red,
            width: double.maxFinite,
          ),
          Localizations.override(
            context: context,
            locale: const Locale('es'),
            //这里手动设置语言,app启动通过 delegate的load方法获取到的语言,会被这里的覆盖
            child: Builder(builder: (context) {
              return Column(
                children: [
                  Center(

                    child: Text(AppLocalizations.of(context)!.helloWorld),
                  ),
                  Text(AppLocalizations.of(context)!.numberOfDataPoints(100)),
                  // Returns 'he'
                  Text(AppLocalizations.of(context)!.pronoun('male')),
                  // Returns 'she'
                  Text(AppLocalizations.of(context)!.pronoun('female')),
                  // Returns 'they'
                  Text(AppLocalizations.of(context)!.pronoun('other')),

                  // Returns 'no wombats'
                  Text(AppLocalizations.of(context)!.nWombats(0)),
                  // Returns '1 wombat'
                  Text(AppLocalizations.of(context)!.nWombats(1)),
                  // Returns '5 wombats'
                  Text(AppLocalizations.of(context)!.nWombats(5)),
                  Text(AppLocalizations.of(context)!.hello('John')),
                ],
              );
            }),
          ),
        ],
      ),
    );

}
}

通过Localizations.override设置,覆盖系统中的语言环境

Localizations.override(
  context: context,
  locale: const Locale('es'),
  //这里手动设置语言,app启动通过 delegate的load方法获取到的语言,会被这里的覆盖
  child: Builder(builder: (context) {

  }
);

总结

本文2种方法国际化设置,一种基于intl库,编写_en.arb和_es.arb,通过 flutter gen-l10n
自动生成代码,程序中使用自动生成的代码类完成多语言的获取。通过pubspec.yaml添加的 generate: true 每次修改arb运行app都实时有效。
另一种方式是手写语言资源类。通过直接的dart代码中通过定义的map,语言环境定义的locale.languageCode获取对应的语言文本。

  • 方法1: 编写DemoLocalizations类 本地化,定义每种语言的 Map
  //这里是手动编写代码
  static const _localizedValues = <String, Map<String, String>>{
    //定义每种语言的 Map
    'en': {
      'title': 'Hello World',
    },
    'es': {
      'title': 'Hola Mundo',
    },
  };

  static List<String> languages() => _localizedValues.keys.toList();

  String get title {
    //这里手动编写的代码, 在map中获取对应文字
    return _localizedValues[locale.languageCode]![
        'title']!; //这个app启动时候获取到的locale
  }
  • 方法2: 编写DemoLocalizations 类,使用 import 'package:intl/intl.dart';调用 Intl.message获取本地化,使用intl_translation命令,扫描项目中用到的intl.message生成 arb,然后配置arb文件添加不同语言

  String get title {
    return Intl.message(
      'Hello World',
      name: 'title',
      desc: 'Title for the Demo application',
      locale: localeName,
    );
  }
  • 方法3: 先编写xxx_xx.arb,flutter gen-l10n 命令生成本地化代码 AppLocalizations. 拆分成不同的文件
  switch (locale.languageCode) {
    case 'en': return AppLocalizationsEn();
    case 'es': return AppLocalizationsEs();
  }

import 'package:flutter_gen/gen_l10n/app_localizations.dart';

最后demo效果如下:

45726-bbc326ff6e611fb3.jpeg

官方文档:Flutter 应用里的国际化

相关文章

网友评论

      本文标题:2024-02-26 flutter国际化

      本文链接:https://www.haomeiwen.com/subject/zcmaadtx.html