Archivo xml de cadena en Flutter

8 minutos de lectura

Avatar de usuario de Magesh Pandian
Magesh Pandian

En flutter string, el texto se establece directamente en el TextField widget como:

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

¿Es la forma correcta? o podemos mantener todas las cadenas en un archivo y usarlo como:

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

Es posible ?

Avatar de usuario de MSpeed
MVelocidad

Flutter actualmente no tiene un sistema similar a recursos dedicados para cadenas. Por el momento, la mejor práctica es mantener su copia de texto en una clase como campos estáticos y acceder a ellos desde allí. Por ejemplo:

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

Luego, en su código, puede acceder a sus cadenas como tales:

Text(Strings.welcomeMessage)

fuente


Edición de mayo de 2019:

ahora hay este paquete que le permite crear archivos json con sus cadenas. Le permitirá crear cadenas para plurales, géneros e idiomas, etc.

Puede crear un archivo json separado para cada idioma de la siguiente manera:

string_en.json

{
"thanks": "Thanks."
}

cadena_nl.json

{    
"thanks": "Dankjewel."
}

Y luego usa esto para acceder a él.

S.of(context).thanks;

Sabrá qué idioma elegir según el idioma predeterminado de su teléfono.

  • Tal vez se pueda mejorar haciéndolo singleton también

    – atascado desbordamiento

    13 de marzo de 2019 a las 7:37

  • Sugiero hacer cada cadena static const

    – André Sousa

    18 mayo 2019 a las 22:11

Avatar de usuario de CopsOnRoad
policíasencarretera

Captura de pantalla:

Complementaré la respuesta de Mantas.


Código completo (seguro nulo):

Para aquellos de ustedes que no quieren usar ningún complemento de terceros, así es como pueden hacerlo.

  1. crear una carpeta strings en assets. Ponga su archivo de idioma en él.

    assets
      strings
      - en.json // for english 
      - ru.json  // for russian
    
  2. Ahora en en.jsonescriba su cadena, por ejemplo.

    {
      "text1": "Hello",
      "text2": "World"
    }
    

    Del mismo modo, en ru.json,

    {
      "text1": "Привет",
      "text2": "Мир"
    }
    
  3. Añadir esto a pubspec.yaml archivo (cuidado con los espacios)

    flutter:
      uses-material-design: true
    
      assets:
        - assets/strings/en.json
        - assets/strings/ru.json
    
    flutter_localizations:
      sdk: flutter
    
  4. Ahora ya está todo listo para usar estas cadenas en su aplicación. Aquí está el código de muestra, el AppBar muestra el texto traducido.

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

  • al llamar al método getText() recibo un error como si el método no estuviera definido

    –Maaz Patel

    27 de mayo de 2020 a las 10:41

  • @MaazPatel ¿Está utilizando el código completo, sin modificarlo?

    – Policías en la carretera

    27 de mayo de 2020 a las 11:10

  • Actualmente, estoy siguiendo este código completo. más tarde agregaré mis cadenas

    –Maaz Patel

    27 de mayo de 2020 a las 11:31

  • @MaazPatel No estoy seguro de qué error está cometiendo, pero este es el código completo (probado por otros)

    – Policías en la carretera

    27 de mayo de 2020 a las 11:34

  • @Fatimaayaa ¿Quiere decir que desea pasar un argumento del archivo json local? Lamentablemente, no puede hacerlo.

    – Policías en la carretera

    20 de julio de 2021 a las 15:04

Puede utilizar los métodos representados en las secciones de internacionalización de la documentación para controlar tanto la gestión centralizada de cadenas como las traducciones (si necesita traducciones)

https://flutter.io/tutorials/internacionalización/

Sin embargo, podría ser excesivo para una aplicación simple con solo unas pocas cadenas.

Avatar de usuario de Cícero Moura
Cícero Moura

Separaría estas clases en archivos individuales, pero solo para explicar mi enfoque para esta pregunta.

Tengo una clase base que tiene mis captadores de cadenas. Cada idioma que quiero admitir, tengo que crear una clase que se extienda desde esta clase y anule sus captadores. Por lo tanto, cada vez que creo una cadena, debo anular cada implementación de esta clase base. Es útil evitar olvidarse de crear una cadena específica de configuración regional.

/// 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á';
}

Después de eso, en un ámbito global de su aplicación, puede declarar una instancia única de la configuración regional que desea usar (usar un singleton es una buena opción).

Solo mostrando un breve ejemplo de su uso:

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

Y finalmente, usándolo en algún widget:

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

Usando una extensión de BuildContext

Puede extender BuildContext para crear algunas características particulares y darle más poder a su aplicación.
Esto está disponible desde Dardo 2.7. Ver más.

app_context_extension.dart

extension AppContext on BuildContext {

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

}

página_favoritos.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);
  }
}

Uso de clave global

Junto con una extensión de BuildContext como se muestra arriba, también puede usar GlobalKey. Básicamente, puede usarlo cuando no tiene una instancia de contexto. Este último tiene una buena ventaja. Puede usar cadenas en cualquier parte de su aplicación. En otras palabras, si usa algún patrón como MVC, por ejemplo, y quiere usar cadenas en sus controladores, podría hacerlo fácilmente.

Puedes declarar algo como esto:

aplicacion.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;
  }
}

dardo principal

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: Application.navKey,
...

Y luego:

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

¡Espero eso ayude!

En primer lugar, cree una nueva carpeta de cadenas en assets y agregue sus archivos JSON de idioma.

assets
  strings
    - en.json
    - ar.json

Esta es tu en.json archivo

{
  "title": "Flutter app"
}

Y este es tu ar.json archivo

{
  "title": "تطبيق Flutter"
}

Entonces, cambia tu pubspec.yaml archivo como a continuación.

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

Después de eso, crea AppLocalizations.dart clase

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

Finalmente en tu main.dart archivo haga los cambios a continuación

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

  • ¡Esta es una buena solución! Extendí su solución para proporcionar una mejor usabilidad mientras codificaba con esa solución, vea mi respuesta.

    –Marcel Hofgesang

    16 de abril de 2022 a las 14:03


avatar de usuario de jebran
Jebran

  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

  • ¡Esta es una buena solución! Extendí su solución para proporcionar una mejor usabilidad mientras codificaba con esa solución, vea mi respuesta.

    –Marcel Hofgesang

    16 de abril de 2022 a las 14:03


Avatar de usuario de Irfandi D. Vendy
Irfandi D. Vendy

Uso este método en lugar de usar lib de terceros. Básicamente, creo una clase que contiene esos valores (cadena, colores, dimensiones, etc.)

recursos.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]);
  }
}

Para usarlo, simplemente llame al método get

dardo principal

import 'package:my_app/resources.dart';
...
    return Container(
      color: ResColor().get('colorPrimary')
    );
...

¿Ha sido útil esta solución?