esskar / vscode-flutter-i18n-json

VS Code extension to create a binding between your translations from .json files and your Flutter app.
92 stars 22 forks source link

Plugin always uses the standard language #36

Closed Xentraxx closed 4 years ago

Xentraxx commented 5 years ago

Hey guys,

I just can't get this to work. The Plugin is always using the standard language. I am sure the solution is very simple but I think I really need the decisive tipp. Thanks in advance!

This is my code:

import 'package:flutter/material.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:linkyou/generated/i18n.dart';
import 'package:linkyou/ui/login/sign_up_page.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'dart:ui';

void main() {
  final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
  _firebaseMessaging.requestNotificationPermissions();
  FlutterError.onError = Crashlytics.instance.recordFlutterError;
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}
//TODO I18n is not changing the language.
class _MyAppState extends State<MyApp> {
  final i18n = I18n.delegate;

  @override
  void initState() {
    super.initState();
    I18n.onLocaleChanged = onLocaleChange;
  }

  void onLocaleChange(Locale locale) {
    setState(() {
      I18n.locale = locale;
    });
  }

  @override
  Widget build(BuildContext context) {
    I18n.locale = Locale(window.locale.languageCode, window.locale.countryCode);
    I18n.onLocaleChanged(Locale(window.locale.languageCode, window.locale.countryCode));
    return MaterialApp(
      title: 'MyApp',
      theme: ThemeData(
        primaryColor: Colors.white,
      ),
      localizationsDelegates: [
        i18n,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      localeResolutionCallback:
          i18n.resolution(fallback: new Locale("en", "US")),
      supportedLocales: i18n.supportedLocales,
      home: SignUpPage(title: I18n().Sign_Up_Page_LogInOrSignUp),
    );
  }
}
nohli commented 4 years ago

What do you mean by standard language? The language that is set in device settings?

Or always English? If so, do you have the desired language in your generated i18n.dart?

Try putting this in the build method above 'return Scaffold': I18n.locale = Localizations.localeOf(context) ?? Locale('en', 'US');

Xentraxx commented 4 years ago

@nohli I mean the default language (in my case English). My device language is German though. I provided the German translation and everything has been generated properly in the i18n.dart file. I tried your suggestion, which results in the following error: 'package:flutter/src/widgets/localizations.dart': Failed assertion: line 417 pos 12: 'scope != null': a locatization ancestor was not found. When I put your provided code into the build method of the first actual page before the scaffold then I don't get this error, but the language doesn't change as well.

nohli commented 4 years ago

For me your code is hard to read because it's not formatted as code, but text. Maybe you can edit the first post?

I'm also German :)

What I can see is that I have a different widget structure: The MaterialApp(... is in a StatelessWidget and the initState and onLocaleChange in a StatefulWidget beneath:

import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:remember/generated/i18n.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final i18n = I18n.delegate;

    return MaterialApp(
      localizationsDelegates: [
        i18n,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate
      ],
      supportedLocales: i18n.supportedLocales,
      localeResolutionCallback: i18n.resolution(fallback: Locale('en', 'US')),
      title: '...',
      home: MyHomePage(title: '...'),
      ),
    );
  }
}

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

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  initState() {
    super.initState();

    I18n.onLocaleChanged = onLocaleChange;
  }

  void onLocaleChange(Locale _locale) {
    if (mounted)
      setState(() {
        I18n.locale = _locale;
      });
  }

  @override
  Widget build(BuildContext context) {

    I18n.locale = Localizations.localeOf(context) ?? Locale('en', 'US');

    return Scaffold(...);
  }
}

Hope, this will help you. Works for me at least.

Xentraxx commented 4 years ago

Danke :) , but it still didn't work. So I created a new App to try your code and to be sure that all other factors are out of the way but the result is the same.

I created a project which is called "myapp" and just contains this code in the main.dart:

import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter/material.dart';
import 'generated/i18n.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final i18n = I18n.delegate;

    return MaterialApp(
      localizationsDelegates: [
        i18n,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate
      ],
      supportedLocales: i18n.supportedLocales,
      localeResolutionCallback: i18n.resolution(fallback: Locale('en', 'US')),
      title: '...',
      home: MyHomePage(title: '...'),
    );
  }
}

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

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  i
```nitState() {
    super.initState();

    I18n.onLocaleChanged = onLocaleChange;
  }

  void onLocaleChange(Locale _locale) {
    if (mounted)
      setState(() {
        I18n.locale = _locale;
      });
  }

  @override
  Widget build(BuildContext context) {
    I18n.locale = Localizations.localeOf(context) ?? Locale('en', 'US');

    return Scaffold(
      body: Center(
        child: Text(I18n().test),
      ),
    );
  }
}

I created a German and English translation and my Phone is in German. By debugging I could see that the App is receiving the German context. Nevertheless the App is displaying the text from the English .json. I'm really lost. Pls help.

Here's the content of my generated i18n.dart file:

import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: camel_case_types
// ignore_for_file: prefer_single_quotes
// ignore_for_file: unnecessary_brace_in_string_interps

//WARNING: This file is automatically generated. DO NOT EDIT, all your changes would be lost.

typedef void LocaleChangeCallback(Locale locale);

class I18n implements WidgetsLocalizations {
  const I18n();
  static Locale _locale;
  static bool _shouldReload = false;

  static set locale(Locale _newLocale) {
    _shouldReload = true;
    I18n._locale = _newLocale;
  }

  static const GeneratedLocalizationsDelegate delegate =
    const GeneratedLocalizationsDelegate();

  /// function to be invoked when changing the language
  static LocaleChangeCallback onLocaleChanged;

  static I18n of(BuildContext context) =>
    Localizations.of<I18n>(context, WidgetsLocalizations);

  @override
  TextDirection get textDirection => TextDirection.ltr;

  /// "English"
  String get test => "English";
}

class _I18n_en_US extends I18n {
  const _I18n_en_US();

  @override
  TextDirection get textDirection => TextDirection.ltr;
}

class _I18n_de_DE extends I18n {
  const _I18n_de_DE();

  /// "German"
  @override
  String get test => "German";

  @override
  TextDirection get textDirection => TextDirection.ltr;
}

class GeneratedLocalizationsDelegate extends LocalizationsDelegate<WidgetsLocalizations> {
  const GeneratedLocalizationsDelegate();
  List<Locale> get supportedLocales {
    return const <Locale>[
      const Locale("en", "US"),
      const Locale("de", "DE")
    ];
  }

  LocaleResolutionCallback resolution({Locale fallback}) {
    return (Locale locale, Iterable<Locale> supported) {
      if (this.isSupported(locale)) {
        return locale;
      }
      final Locale fallbackLocale = fallback ?? supported.first;
      return fallbackLocale;
    };
  }

  @override
  Future<WidgetsLocalizations> load(Locale _locale) {
    I18n._locale ??= _locale;
    I18n._shouldReload = false;
    final Locale locale = I18n._locale;
    final String lang = locale != null ? locale.toString() : "";
    final String languageCode = locale != null ? locale.languageCode : "";
    if ("en_US" == lang) {
      return new SynchronousFuture<WidgetsLocalizations>(const _I18n_en_US());
    }
    else if ("de_DE" == lang) {
      return new SynchronousFuture<WidgetsLocalizations>(const _I18n_de_DE());
    }
    else if ("en" == languageCode) {
      return new SynchronousFuture<WidgetsLocalizations>(const _I18n_en_US());
    }
    else if ("de" == languageCode) {
      return new SynchronousFuture<WidgetsLocalizations>(const _I18n_de_DE());
    }

    return new SynchronousFuture<WidgetsLocalizations>(const I18n());
  }

  @override
  bool isSupported(Locale locale) {
    for (var i = 0; i < supportedLocales.length && locale != null; i++) {
      final l = supportedLocales[i];
      if (l.languageCode == locale.languageCode) {
        return true;
      }
    }
    return false;
  }

  @override
  bool shouldReload(GeneratedLocalizationsDelegate old) => I18n._shouldReload;
}

My i18nconfig.json:

{
    "defaultLocale": "en-US",
    "locales": [
        "en-US",
        "de-DE"
    ],
    "localePath": "i18n",
    "generatedPath": "lib/generated",
    "ltr": [
        "en-US",
        "de-DE"
    ],
    "rtl": []
}

I'm getting the following Error which could be related: E/AccessibilityBridge(16060): VirtualView node must not be the root node.

esskar commented 4 years ago

Einfach zu viele Deutsche hier. ;)

Have you added german as an ios language (within the info.plist)?

Xentraxx commented 4 years ago

Ja, echt schlimm :P Not yet, but I actually experience this behavior on Android (I'm using mainly android to debug).

Xentraxx commented 4 years ago

@esskar Do you have any other idea? Every help is appreachiated. Can you reconstruct the problem with my provided code above?

esskar commented 4 years ago

Sorry that it took me so long to have a look, but anyways. You cannot use I18n() as this will always be the default language. You need to get the I18n.of the current context, as of I18n.of(context)

so, in main.dart use

return Scaffold(
      body: Center(
        child: Text(I18n.of(context).test),
      ),
    );