0
点赞
收藏
分享

微信扫一扫

Flutter之国际化语言


资料

宁皓网 20 Flutter移动应用:国际化
Flutter实战*第二版 第十三章 国际化我的GIT仓库 / 分支: learn-localizations-ninghao

环境

pubspec.yaml

name: flutter_project
description: A new Flutter project.

publish_to: 'none' # Remove this line if you wish to publish to pub.dev

version: 1.0.0+1

environment:
  sdk: '>=2.12.0 <3.0.0'

dependencies:
  dio: ^4.0.4
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  intl: ^0.17.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  intl_generator: ^0.1.0+0
#  intl_translation: ^0.17.10

flutter:
  uses-material-design: true

Flutter环境

Flutter 2.6.0-6.0.pre.6 • channel master • https://github.com/flutter/flutter.git
Framework • revision 0c5431d99c (5 months ago) • 2021-09-05 22:31:02 -0400
Engine • revision b9c633900e
Tools • Dart 2.15.0 (build 2.15.0-82.0.dev)

android studio

Flutter之国际化语言_ios

项目结构

Flutter之国际化语言_Text_02

设置国际化参数

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_project/localizations_const.dart';
import 'package:flutter_localizations/flutter_localizations.dart';

import 'i18n/i18n_demo.dart';

// 自动生成的
import 'i18n/intl/ninghao_demo_localizations.dart';

// 手动生成的
// import 'i18n/ninghao_demo_localizations.dart';

void main() => runApp(Home());

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      //locale: locale_enUs,
      // 系统回调回来的语言设置
      localeResolutionCallback: (
        Locale? locale,
        Iterable<Locale> supportedLocales,
      ) {
        print('localeResolutionCallback locale = $locale');
        print('localeResolutionCallback supportedLocales = $supportedLocales');
        return locale_enUs;
      },
      localizationsDelegates: [
        // 本地化的代理类
        // 为Material组件库提供的本地化的字符串和其他值,它可以使Material组建支持多语言
        GlobalMaterialLocalizations.delegate,
        // 定义组件默认的文本方向,从左到右或从右到左,这是因为有些语言的阅读习惯不是从左到右
        GlobalWidgetsLocalizations.delegate,
        // 注册我们自己的Delegate
        DemoLocalizationsDelegate(),
        NinghaoDemoLocalizationDelegate(),
      ],
      supportedLocales: mapLocals,
      title: 'Woolha.com Flutter Tutorial',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: MyApp(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class MyApp extends StatefulWidget {
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  LOCAL_TYPE local_type = LOCAL_TYPE.CH;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(DemoLocalizations.of(context).title),
        centerTitle: true,
        backgroundColor: Colors.green,
        brightness: Brightness.dark,
        //automaticallyImplyLeading: false,
        leading: Icon(Icons.add),
        actions: [
          IconButton(
            onPressed: () {
              setState(() {
                //local_type = toggleLocal(local_type);
                _showDatePicker1(context);
              });
            },
            icon: Icon(Icons.toggle_on),
          ),
        ],
      ),
      body: I18nDemo(),
      // body: Center(
      //   child: Text(getLocalName(local_type)),
      // ),
    );
  }

  // 日历选择
  Future<DateTime?> _showDatePicker1(BuildContext context) {
    bool useIOS = true;
    var date = DateTime.now();
    return useIOS
        ? showDatePicker(
            context: context,
            initialDate: date,
            firstDate: date,
            lastDate: date.add(Duration(days: 30)),
          )
        : showCupertinoModalPopup(
            context: context,
            builder: (ctx) {
              return Container(
                height: 200,
                color: Colors.white,
                child: CupertinoDatePicker(
                  mode: CupertinoDatePickerMode.dateAndTime,
                  minimumDate: date,
                  maximumDate: date.add(Duration(days: 30)),
                  onDateTimeChanged: (DateTime value) {
                    print(value);
                  },
                  maximumYear: date.year + 1,
                ),
              );
            },
          );
  }
}

设置固定的Locale

  • 设置locale参数

MaterialApp(
      locale: locale_enUs,
      ....

  • 通过获取系统语言的回调监听设置

MaterialApp(
      // 系统回调回来的语言设置
      localeResolutionCallback: (
        Locale? locale,
        Iterable<Locale> supportedLocales,
      ) {
        print('localeResolutionCallback locale = $locale');
        print('localeResolutionCallback supportedLocales = $supportedLocales');
        return locale_enUs; // 此时默认的是英文, 可以根据具体要求修改
      },
      ...
    );

其中:Locale? locale 返回系统修改的语言
Iterable supportedLocales 为APP中所支持的语言

  • 设置国际化的代理lo

MaterialApp(
	...
      localizationsDelegates: [
        // 本地化的代理类
        // 为Material组件库提供的本地化的字符串和其他值,它可以使Material组建支持多语言
        GlobalMaterialLocalizations.delegate,
        // 定义组件默认的文本方向,从左到右或从右到左,这是因为有些语言的阅读习惯不是从左到右
        GlobalWidgetsLocalizations.delegate,
        // 注册我们自己的Delegate
        DemoLocalizationsDelegate(),
        NinghaoDemoLocalizationDelegate(),
      ],
	...
    );

设置代理, 所有的代理都继承LocalizationsDelegate, 可以使用系统的+自定义的

  • 所有支持的语言

const locale_enUs = const Locale('en', 'US');
const locale_zhCN = const Locale('zh', 'CN');
const locale_zhHK = const Locale('zh', 'HK');

// 这里放所有能支持的语言
const List<Locale> mapLocals = [
  locale_enUs, // 美国英语
  locale_zhCN, // 中文简体
  locale_zhHK,
];

MaterialApp(
	...
      supportedLocales: mapLocals,
	...
    )

手写国际化

import 'dart:ui';

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

import '../localizations_const.dart';

// 手动版本
class NinghaoDemoLocalizations {
  //传入要使用的Local 
  final Locale locale;
  NinghaoDemoLocalizations(this.locale);

  // 工具方法, 通过Localizations.of<T>(context, T) 来获取相对应的语言
  static NinghaoDemoLocalizations? of(BuildContext context) {
    return Localizations.of<NinghaoDemoLocalizations>(
        context, NinghaoDemoLocalizations);
  }

  // 'en'就是语言的名字
  // 每个map中, 都有具体要使用的字段
  static Map<String, Map<String, String>> _localized = {
    'en': {
      'title': 'hello',
    },
    'zh': {
      'title': '您好',
    },
  };

  // 通过传入的locale.languageCode取出对应的字段
  String? get title {
    Map<String, String>? map = _localized[locale.languageCode];
    return map == null ? null : map['title'];
  }
}

class NinghaoDemoLocalizationDelegate
    extends LocalizationsDelegate<NinghaoDemoLocalizations> {
  NinghaoDemoLocalizationDelegate();

  // 判断是否支持这个语言
  @override
  bool isSupported(Locale locale) {
    return isContainsThisLanguage(locale);
  }

  // 载入对应的语言资源包
  @override
  Future<NinghaoDemoLocalizations> load(Locale locale) {
    return SynchronousFuture<NinghaoDemoLocalizations>(
        NinghaoDemoLocalizations(locale));
  }

  // 是否每次重新加载资源
  @override
  bool shouldReload(
      covariant LocalizationsDelegate<NinghaoDemoLocalizations> old) {
    return false; // 是否加载本地资源
  }
}

使用

class I18nDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Locale locale = Localizations.localeOf(context);
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text('${locale.toString()}'),
          Text(
            '${Localizations.of(context, NinghaoDemoLocalizations).title}', // 使用手动创建title字段
            style: Theme.of(context).textTheme.headline4,
          ),
        ],
      ),
    );
  }
}

}

自动生成国际化

在我本地的环境使用

dev_dependencies:
  intl_generator: ^0.1.0+0
  ...

先创建一个类,作为要生成arb的模版

class NinghaoDemoLocalizations {
  String get title =>
      Intl.message(
        'hello',
        name: 'title',
        desc: 'demo localizations.',
      );

  String greet(String name) =>
      Intl.message(
        'hello $name',
        name: 'greet',
        desc: 'greet someone.',
        args: [name],
      );

}

通过命令行生成arb文件

flutter pub run intl_generator:extract_to_arb --output-dir=lib/i18n/intl/ lib/i18n/intl/ninghao_demo_localizations.dart

分解:

flutter pub run intl_generator:extract_to_arb 
	--output-dir=lib/i18n/intl/    // 要生成arb文件的目录
	lib/i18n/intl/ninghao_demo_localizations.dart // 生成arb文件使用的模板

会生成intl_messages.arb文件

{
  "@@last_modified": "2022-02-09T15:56:37.677571",
  "title": "hello",
  "@title": {
    "description": "demo localizations.",
    "type": "text",
    "placeholders": {}
  },
  "greet": "hello {name}",
  "@greet": {
    "description": "greet someone.",
    "type": "text",
    "placeholders": {
      "name": {}
    }
  }
}

通过粘贴复制改名,创建多个语言的文件intl_en.arb和intl_zh.arb

intl_en.arb

{
  "@@last_modified": "2022-02-09T15:56:37.677571",
  "title": "hello",
  "@title": {
    "description": "demo localizations.",
    "type": "text",
    "placeholders": {}
  },
  "greet": "hello {name}",
  "@greet": {
    "description": "greet someone.",
    "type": "text",
    "placeholders": {
      "name": {}
    }
  }
}

intl_zh.arb

{
  "@@last_modified": "2022-02-09T15:56:37.677571",
  "title": "您好",
  "@title": {
    "description": "演示本地化.",
    "type": "text",
    "placeholders": {}
  },
  "greet": "您好 {name}",
  "@greet": {
    "description": "问候某人.",
    "type": "text",
    "placeholders": {
      "name": {}
    }
  }
}

通过命令,将所有的arb文件生成对应的dart文件,及dart管理文件

以下都是自动生成的
ninghao_demo_messages_all.dart

// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
// This is a library that looks up messages for specific locales by
// delegating to the appropriate library.

// Ignore issues from commonly used lints in this file.
// ignore_for_file:implementation_imports, file_names
// ignore_for_file:unnecessary_brace_in_string_interps, directives_ordering
// ignore_for_file:argument_type_not_assignable, invalid_assignment
// ignore_for_file:prefer_single_quotes, prefer_generic_function_type_aliases
// ignore_for_file:comment_references
// ignore_for_file:avoid_catches_without_on_clauses

import 'dart:async';

import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart';
import 'package:intl/src/intl_helpers.dart';

import 'ninghao_demo_messages_en.dart' as messages_en;
import 'ninghao_demo_messages_messages.dart' as messages_messages;
import 'ninghao_demo_messages_zh.dart' as messages_zh;

typedef Future<dynamic> LibraryLoader();
Map<String, LibraryLoader> _deferredLibraries = {
  'en': () => Future.value(null),
  'messages': () => Future.value(null),
  'zh': () => Future.value(null),
};

MessageLookupByLibrary? _findExact(String localeName) {
  switch (localeName) {
    case 'en':
      return messages_en.messages;
    case 'messages':
      return messages_messages.messages;
    case 'zh':
      return messages_zh.messages;
    default:
      return null;
  }
}

/// User programs should call this before using [localeName] for messages.
Future<bool> initializeMessages(String localeName) async {
  // 验证是否是有效的Local
  final availableLocale = Intl.verifiedLocale(
    localeName,
    (locale) => _deferredLibraries[locale] != null,
    onFailure: (_) => null);
  if (availableLocale == null) {
    return Future.value(false);
  }
  final lib = _deferredLibraries[availableLocale];
  await (lib == null ? Future.value(false) : lib());
  initializeInternalMessageLookup(() => CompositeMessageLookup());
  messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor);
  return Future.value(true);
}

bool _messagesExistFor(String locale) {
  try {
    return _findExact(locale) != null;
  } catch (e) {
    return false;
  }
}

MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) {
  final actualLocale = Intl.verifiedLocale(locale, _messagesExistFor,
      onFailure: (_) => null);
  if (actualLocale == null) return null;
  return _findExact(actualLocale);
}

ninghao_demo_messages_en.dart

// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
// This is a library that provides messages for a en locale. All the
// messages from the main program should be duplicated here with the same
// function name.

// Ignore issues from commonly used lints in this file.
// ignore_for_file:unnecessary_brace_in_string_interps
// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering
// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases
// ignore_for_file:unused_import, file_names, always_declare_return_types

import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart';

final messages = MessageLookup();

typedef String MessageIfAbsent(String? messageStr, List<Object>? args);

class MessageLookup extends MessageLookupByLibrary {
  String get localeName => 'en';

  static m0(name) => "hello ${name}";

  final messages = _notInlinedMessages(_notInlinedMessages);
  static Map<String, Function> _notInlinedMessages(_) => <String, Function> {
    "greet" : m0,
    "title" : MessageLookupByLibrary.simpleMessage("hello")
  };
}

ninghao_demo_messages_messages.dart

// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
// This is a library that provides messages for a messages locale. All the
// messages from the main program should be duplicated here with the same
// function name.

// Ignore issues from commonly used lints in this file.
// ignore_for_file:unnecessary_brace_in_string_interps
// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering
// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases
// ignore_for_file:unused_import, file_names, always_declare_return_types

import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart';

final messages = MessageLookup();

typedef String MessageIfAbsent(String? messageStr, List<Object>? args);

class MessageLookup extends MessageLookupByLibrary {
  String get localeName => 'messages';

  static m0(name) => "hello ${name}";

  final messages = _notInlinedMessages(_notInlinedMessages);
  static Map<String, Function> _notInlinedMessages(_) => <String, Function> {
    "greet" : m0,
    "title" : MessageLookupByLibrary.simpleMessage("hello")
  };
}

ninghao_demo_messages_zh.dart

// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
// This is a library that provides messages for a zh locale. All the
// messages from the main program should be duplicated here with the same
// function name.

// Ignore issues from commonly used lints in this file.
// ignore_for_file:unnecessary_brace_in_string_interps
// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering
// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases
// ignore_for_file:unused_import, file_names, always_declare_return_types

import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart';

final messages = MessageLookup();

typedef String MessageIfAbsent(String? messageStr, List<Object>? args);

class MessageLookup extends MessageLookupByLibrary {
  String get localeName => 'zh';

  static m0(name) => "您好 ${name}";

  final messages = _notInlinedMessages(_notInlinedMessages);
  static Map<String, Function> _notInlinedMessages(_) => <String, Function> {
    "greet" : m0,
    "title" : MessageLookupByLibrary.simpleMessage("您好")
  };
}

在ninghao_demo_localization.dart中使用自动生成的文件

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

import '../../localizations_const.dart';
import 'ninghao_demo_messages_all.dart';

// 自动版本

// 宁皓网教程
// flutter pub pub run intl_translation:extract_to_arb
// --output-dir=lib/demo/i18n/intl/
// lib/demo/i18n/intl/ninghao_demo_localizations.dart
// 自己摸索
// flutter pub run intl_generator:extract_to_arb --output-dir=lib/i18n/intl/ lib/i18n/intl/ninghao_demo_localizations.dart
class NinghaoDemoLocalizations {

	// 通过Localizations.of<T>(context, T)使用国际化
  static NinghaoDemoLocalizations? of(BuildContext context) {
    return Localizations.of<NinghaoDemoLocalizations>(
        context,
        NinghaoDemoLocalizations
    );
  }

  // 加载要使用的资源包
  static Future<NinghaoDemoLocalizations> load(Locale locale) {
    // 当前要使用的Local
    final String name = locale.countryCode?.isEmpty == true
        ? locale.languageCode
        : locale.toString();
	// 带有格式化的local string   localName = "en_US"
    final String localeName = Intl.canonicalizedLocale(name);

    return initializeMessages(localeName).then((bool _) {
      Intl.defaultLocale = localeName;
      return NinghaoDemoLocalizations();
    });
  }

  String get title =>
      Intl.message(
        'hello',
        name: 'title',
        desc: 'demo localizations.',
      );

  String greet(String name) =>
      Intl.message(
        'hello $name',
        name: 'greet',
        desc: 'greet someone.',
        args: [name],
      );

}

// 通过arb反过来生成dart文件
// flutter pub pub run intl_translation:generate_from_arb
// --generated-file-prefix=ninghao_demo_ --output-dir=lib/demo/i18n/intl
// --no-use-deferred-loading lib/demo/i18n/intl/ninghao_demo_localizations.dart
// lib/demo/i18n/int/intl_*.arb
// 自己摸索
//flutter pub run intl_generator:generate_from_arb --generated-file-prefix=ninghao_demo_ --output-dir=lib/i18n/intl/ --no-use-deferred-loading lib/i18n/intl/ninghao_demo_localizations.dart lib/i18n/intl/intl_*.arb


class NinghaoDemoLocalizationDelegate extends LocalizationsDelegate<NinghaoDemoLocalizations> {
  NinghaoDemoLocalizationDelegate();

  @override
  bool isSupported(Locale locale) {
    return isContainsThisLanguage(locale);
  }

  @override
  Future<NinghaoDemoLocalizations> load(Locale locale) {
    return NinghaoDemoLocalizations.load(locale); // 使用自动生成的国际化语言包
  }

  @override
  bool shouldReload(
      covariant LocalizationsDelegate<NinghaoDemoLocalizations> old) {
    return false; // 是否每次重新加载本地资源
  }
}

自动国际化如何实现的

  1. 通过load进行加载

Future<bool> initializeMessages(String localeName) async {
  final availableLocale = Intl.verifiedLocale(
    localeName,
    (locale) => _deferredLibraries[locale] != null,
    onFailure: (_) => null);
  if (availableLocale == null) {
    return Future.value(false);
  }
  final lib = _deferredLibraries[availableLocale];
  await (lib == null ? Future.value(false) : lib());
  initializeInternalMessageLookup(() => CompositeMessageLookup());
  messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor);
  return Future.value(true);
}

MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) {
  final actualLocale = Intl.verifiedLocale(locale, _messagesExistFor,
      onFailure: (_) => null);
  if (actualLocale == null) return null;
  return _findExact(actualLocale);
}

MessageLookupByLibrary? _findExact(String localeName) {
  switch (localeName) {
    case 'en':
      return messages_en.messages;
    case 'messages':
      return messages_messages.messages;
    case 'zh':
      return messages_zh.messages;
    default:
      return null;
  }
}

// 是这么引用的
import 'ninghao_demo_messages_en.dart' as messages_en;
import 'ninghao_demo_messages_messages.dart' as messages_messages;
import 'ninghao_demo_messages_zh.dart' as messages_zh;

调用了就是自动生成的文件

Flutter之国际化语言_ide_03

-------一下是Old版本-------------------------------------------------------------
-------一下是Old版本-------------------------------------------------------------
-------一下是Old版本-------------------------------------------------------------
-------一下是Old版本-------------------------------------------------------------
-------一下是Old版本-------------------------------------------------------------

安装步骤

添加依赖

将intl package 添加到pubspec.yaml文件中

dependencies:
		  flutter:
		    sdk: flutter
		  flutter_localizations:
		    sdk: flutter
		  intl: ^0.17.0 # Add this line

在pubspec.yaml中,启用generate标志

# The following section is specific to Flutter.
		flutter:
		  generate: true # Add this line

在Flutter项目中的根目录中添加一个新的yaml文件,命名为l10n.yaml文件

arb-dir: lib/l10n                         # 文件存放的目录
		template-arb-file: intl_en.arb   # 依赖的模版文件 
		output-localization-file: app_localizations.dart   # 要生成的文件(自动生成,不清楚)

Flutter之国际化语言_ide_04

在${FLUTTER_PROJECT}/lib/l10n中,添加intl_en.arb模版文件。如下:

{
    "helloWorld": "Hello World!",
    "@helloWorld": {
      "description": "The conventional newborn programmer greeting"
    }
}

在同一目录中,添加一个intl_es.arb文件,对同一条信息做西班牙语的翻译

{
    "helloWorld": "Hola Mundo!"
}

自动生成generate目录

Flutter之国际化语言_ide_04


Flutter之国际化语言_flutter_06

正常使用

引入依赖

import 'package:flutter_localizations/flutter_localizations.dart'; // 国际化
 import 'package:flutter_helper/generated/l10n.dart';

添加代理

localizationsDelegates: [
        S.delegate, // 这个是自动生成的
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate
      ],

添加多语言支持

supportedLocales: [
        Locale('en', ''), //English, no country code
        Locale('ko', ''), //Spanish, no country code
        Locale('zh', ''), //Spanish, no country code
      ],

添加默认语言

locale: Locale('ko', ''),

总的添加Local

class LanguageApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    // var localization = AppLocalizationDelegate();
    // var support = localization.supportedLocales;
    return const MaterialApp(
      title: 'Localizations Sample App',
      locale: Locale('ko', ''),
      localizationsDelegates: [
        S.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate
      ],
      supportedLocales: [
        Locale('en', ''), //English, no country code
        Locale('ko', ''), //Spanish, no country code
        Locale('zh', ''), //Spanish, no country code
      ],
      home:  Scaffold(
        body: _MyHome(),
      ),
    );
  }
}

获取字符串资源

Text(S.of(context).helloWorld) // helloWorld是自动生成的方法


举报

相关推荐

0 条评论