easy_localization

轻松快速地国际化您的 Flutter 应用,此包使用 JSON 文件简化了国际化过程。

为什么选择 easy_localization

  • 简化 Flutter 中的国际化过程。
  • 使用 JSON 文件。
  • 从远程或后端加载翻译。
  • 保存应用程序状态。
  • 支持 复数
  • 支持 性别
  • 支持 Flutter 扩展。

更新日志

[1.4.1]

  • 优化且干净的代码

  • 修复了许多问题

  • 为字符串添加了扩展

    // after 1.4.1
    Text('title'.tr()),
    Text('switch'.tr( gender: _gender ? "female" : "male")),
    Text('counter'.plural(counter)),
    

[1.4.0]

  • 重构代码,将调用 AppLocalizations.of(context).tr() AppLocalizations.of(context).plural() 改为 tr()plural()

    // after 1.4.0
    Text(
      tr('switch', gender: _gender ? "female" : "male"),
    ),
    
    // before 1.4.0
    Text(
      AppLocalizations.of(context).tr('switch', gender: _gender ? "female" : "male"),
    ),
    
  • 为 Text widget 添加了 Flutter 扩展

    // after 1.4.0
    Text('switch').tr( gender: _gender ? "female" : "male"),
    Text('counter').plural(counter),
    

[1.3.5]

  • 合并了 gender()tr()

    {
      "switch":{
        "male": "Hi man ;)",
        "female": "Hello girl :)"
      }
    }
    
    Text(
      AppLocalizations.of(context).tr('switch', gender: _gender ? "female" : "male"),
    ),
    
  • 使用参数 args 来处理性别。

    {
      "switch":{
        "male": "Hi man ;) {}",
        "female": "Hello girl :) {}"
      }
    }
    
    Text(
      AppLocalizations.of(context).tr('switch', args:["Naama"] gender: _gender ? "female" : "male"),
    ),
    
    

[1.3.4]

  • 添加了性别 [女性,男性] gender()

    {
      "switch":{
        "male": "Hi man ;)",
        "female": "Hello girl :)"
      }
    }
    
    Text(
      AppLocalizations.of(context).gender('switch', _gender ? "female" : "male"),
    ),
    

[1.3.3+1]

  • 更新了 plural(),感谢 shushper

    {
      "text": {
        "day": {
          "zero":"{} дней",
          "one": "{} день",
          "two": "{} дня",
          "few": "{} дня",
          "many": "{} дней",
          "other": "{} дней"
        }
      }
    }
    

[1.3.3]

  • 移除了 data.savedLocale
  • 优化且干净的代码
  • 修复了许多问题

[1.3.2]

  • plural() 添加了嵌套键翻译的属性解析器

    {
    "text": {
      "day": {
        "zero": "day",
        "one": "day",
        "other": "days"
        }
      }
    }
    
    new Text(
      AppLocalizations.of(context).plural("text.day", 2),
    ),
    
  • 修复了许多问题

[1.3.1]

  • 添加 useOnlyLangCode 标志

[1.3.0]

  • 从远程或后端加载翻译
  • 修复了许多问题

[1.2.1]

  • 支持 shared_preferences
  • 保存选定的本地化

[1.2.0]

  • 添加了嵌套键翻译的属性解析器
  • 如果元素或路径不存在,则返回翻译键
{
  "title": "Hello",
  "msg": "Hello {} in the {} world ",
  "clickMe": "Click me",
  "profile": {
    "reset_password": {
      "title": "Reset Password",
      "username": "Username",
      "password": "password"
    }
  },
  "clicked": {
    "zero": "You clicked {} times!",
    "one": "You clicked {} time!",
    "two":"You clicked {} times!",
    "few":"You clicked {} times!",
    "many":"You clicked {} times!",
    "other": "You clicked {} times!"
  }
}
new Text(
  AppLocalizations.of(context).tr('profile.reset_password.title'),
 ),

[1.0.4]

  • 添加了对国家代码的支持

[1.0.3]

  • 更新了 tr() 函数,添加了多参数

[1.0.2]

  • 添加了字符串复数化。
  • tr() 函数添加了参数。

入门

配置

将此添加到您的 package 的 pubspec.yaml 文件中

dependencies:
  # stable version install from https://pub.dev/packages
  easy_localization: <last_version>

  # Dev version install from git REPO
  easy_localization:
    git: https://github.com/aissat/easy_localization.git

从本地资源加载翻译

你必须在项目的根目录创建一个文件夹:path。一些例子

/assets/"langs", "i18n", "locale" 或任何名称...

/resources/"langs", "i18n", "locale" 或任何名称...

在此文件夹内,必须放置包含翻译键的 *json* 文件。

path/${languageCode}-${countryCode}.json

示例

  • en.json 到 en-US.json
  • ar.json 到 ar-DZ.json
  • zh.json 到 zh-CN.json
  • zh.json 到 zh-TW.json

必须在 pubspec.yaml 文件中将子目录声明为资源。

flutter:
  assets:
    - {`path`/{languageCode}-{countryCode}.json}

下一步

import 'package:example/my_flutter_app_icons.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:easy_localization/easy_localization.dart';

void main() => runApp(EasyLocalization(child: MyApp()));

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var data = EasyLocalizationProvider.of(context).data;
    return EasyLocalizationProvider(
      data: data,
      child: MaterialApp(
        title: 'Flutter Demo',
        localizationsDelegates: [
          GlobalMaterialLocalizations.delegate,
          GlobalWidgetsLocalizations.delegate,
          //app-specific localization
          EasyLocalizationDelegate(
            locale: data.locale,
            path: 'resources/langs',
            //useOnlyLangCode: true,
            // loadPath: 'https://raw.githubusercontent.com/aissat/easy_localization/master/example/resources/langs'
          ),
        ],
        supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')],
        locale: data.locale,
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: MyHomePage(title: 'Easy localization'),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int counter = 0;
  bool _gender = true;

  incrementCounter() {
    setState(() {
      counter++;
    });
  }

  switchGender(bool val) {
    setState(() {
      _gender = val;
    });
  }

  @override
  Widget build(BuildContext context) {
    var data = EasyLocalizationProvider.of(context).data;
    return EasyLocalizationProvider(
      data: data,
      child: Scaffold(
        appBar: AppBar(
          title: Text(tr("title")),
          actions: <Widget>[
            FlatButton(
              child: Text("English"),
              color: Localizations.localeOf(context).languageCode == "en"
                  ? Colors.lightBlueAccent
                  : Colors.blue,
              onPressed: () {
                this.setState(() {
                  data.changeLocale(Locale("en", "US"));
                  print(Localizations.localeOf(context).languageCode);
                });
              },
            ),
            FlatButton(
              child: Text("عربي"),
              color: Localizations.localeOf(context).languageCode == "ar"
                  ? Colors.lightBlueAccent
                  : Colors.blue,
              onPressed: () {
                this.setState(() {
                  data.changeLocale(Locale("ar", "DZ"));
                  print(Localizations.localeOf(context).languageCode);
                });
              },
            )
          ],
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Spacer(
                flex: 1,
              ),
              Text(
                'switch.with_arg',
                style: TextStyle(
                    color: Colors.grey.shade600,
                    fontSize: 19,
                    fontWeight: FontWeight.bold),
              ).tr(args: ["aissat"], gender:  _gender ? "female" : "male"),
              Text(
                tr('switch', gender:  _gender ? "female" : "male"),
                style: TextStyle(
                    color: Colors.grey.shade600,
                    fontSize: 15,
                    fontWeight: FontWeight.bold),
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Icon(MyFlutterApp.male_1),
                  Switch(value: _gender, onChanged: switchGender),
                  Icon(MyFlutterApp.female_1),
                ],
              ),
              Spacer(
                flex: 1,
              ),
              Text(tr('msg', args: ['aissat', 'Flutter'])),
              // Text(plural('clicked', counter)),
              Text('clicked').plural(counter),
              FlatButton(
                onPressed: () {
                  incrementCounter();
                },
                child: Text('clickMe').tr(),
              ),
              SizedBox(height: 15,),
              Text(
                plural('amount', counter,
                    format: NumberFormat.currency(
                        locale: Localizations.localeOf(context).toString(),
                        symbol: "€")),
                style: TextStyle(
                    color: Colors.grey.shade900,
                    fontSize: 18,
                    fontWeight: FontWeight.bold)
              ),
              SizedBox(height: 20,),
              Text('profile.reset_password.title').tr(),
              Spacer(
                flex: 2,
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: incrementCounter,
          child: Text('+1'),
        ),
      ),
    );
  }
}

从后端加载翻译

你需要有一个后端端点 (loadPath) 来加载资源,并且你的端点必须包含翻译键。

示例

String loadPath = 'https://raw.githubusercontent.com/aissat/easy_localization/master/example/resources/langs'

'${loadPath}/${languageCode}-${countryCode}.json'

下一步

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:easy_localization/easy_localization.dart';

void main() => runApp(EasyLocalization(child: MyApp()));

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var data = EasyLocalizationProvider.of(context).data;
    return EasyLocalizationProvider(
      data: data,
      child: MaterialApp(
        title: 'Flutter Demo',
        localizationsDelegates: [
          GlobalMaterialLocalizations.delegate,
          GlobalWidgetsLocalizations.delegate,
          //app-specific localization
          EasyLocalizationDelegate(
              locale: data.locale,
              loadPath: 'https://raw.githubusercontent.com/aissat/easy_localization/master/example/resources/langs'),
        ],
        supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')],
        locale: data.locale,
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: MyHomePage(title: 'Easy localization'),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int counter = 0;
  incrementCounter() {
    setState(() {
      counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    var data = EasyLocalizationProvider.of(context).data;
    return EasyLocalizationProvider(
      data: data,
      child: Scaffold(
        appBar: AppBar(
          title: Text(tr('title')),
          actions: <Widget>[
            FlatButton(
              child: Text("English"),
              color: Localizations.localeOf(context).languageCode == "en"
                  ? Colors.lightBlueAccent
                  : Colors.blue,
              onPressed: () {
                this.setState(() {
                  data.changeLocale(Locale("en","US"));
                  print(Localizations.localeOf(context).languageCode);
                });
              },
            ),
            FlatButton(
              child: Text("عربي"),
              color: Localizations.localeOf(context).languageCode == "ar"
                  ? Colors.lightBlueAccent
                  : Colors.blue,
              onPressed: () {
                this.setState(() {
                  data.changeLocale(Locale("ar","DZ"));
                  print(Localizations.localeOf(context).languageCode);
                });
              },
            )
          ],
        ),
        body: Center(
          child: new Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              new Text(AppLocalizations.of(context)
                  .tr('msg', args: ['aissat', 'Flutter'])),
              new Text(plural('clicked', counter)),
              new FlatButton(
                onPressed: () async {
                  incrementCounter();
                },
                child: new Text(tr('clickMe')),
              ),
              new Text(
                tr('profile.reset_password.title'),
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: incrementCounter,
          child: Text('+1'),
        ),
      ),
    );
  }
}

屏幕截图

阿拉伯语 RTL 英语 LTR
Screenshot_ar Screenshot_en

GitHub

https://github.com/aissat/easy_localization