Skip to content

Add language setting #1461

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
8 changes: 8 additions & 0 deletions assets/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -883,5 +883,13 @@
"zulipAppTitle": "Zulip",
"@zulipAppTitle": {
"description": "The name of Zulip. This should be either 'Zulip' or a transliteration."
},
"languageSettingsTitle": "Language",
"@languageSettingsTitle": {
"description": "Title for the language settings section in the app settings."
},
"systemDefaultLanguage": "System default",
"@systemDefaultLanguage": {
"description": "Option to use the system default language setting."
}
}
12 changes: 12 additions & 0 deletions lib/generated/l10n/zulip_localizations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1303,6 +1303,18 @@ abstract class ZulipLocalizations {
/// In en, this message translates to:
/// **'Zulip'**
String get zulipAppTitle;

/// Title for the language settings section in the app settings.
///
/// In en, this message translates to:
/// **'Language'**
String get languageSettingsTitle;

/// Option to use the system default language setting.
///
/// In en, this message translates to:
/// **'System default'**
String get systemDefaultLanguage;
}

class _ZulipLocalizationsDelegate
Expand Down
6 changes: 6 additions & 0 deletions lib/generated/l10n/zulip_localizations_ar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -717,4 +717,10 @@ class ZulipLocalizationsAr extends ZulipLocalizations {

@override
String get zulipAppTitle => 'Zulip';

@override
String get languageSettingsTitle => 'Language';

@override
String get systemDefaultLanguage => 'System default';
}
6 changes: 6 additions & 0 deletions lib/generated/l10n/zulip_localizations_en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -717,4 +717,10 @@ class ZulipLocalizationsEn extends ZulipLocalizations {

@override
String get zulipAppTitle => 'Zulip';

@override
String get languageSettingsTitle => 'Language';

@override
String get systemDefaultLanguage => 'System default';
}
6 changes: 6 additions & 0 deletions lib/generated/l10n/zulip_localizations_ja.dart
Original file line number Diff line number Diff line change
Expand Up @@ -717,4 +717,10 @@ class ZulipLocalizationsJa extends ZulipLocalizations {

@override
String get zulipAppTitle => 'Zulip';

@override
String get languageSettingsTitle => 'Language';

@override
String get systemDefaultLanguage => 'System default';
}
6 changes: 6 additions & 0 deletions lib/generated/l10n/zulip_localizations_nb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -717,4 +717,10 @@ class ZulipLocalizationsNb extends ZulipLocalizations {

@override
String get zulipAppTitle => 'Zulip';

@override
String get languageSettingsTitle => 'Language';

@override
String get systemDefaultLanguage => 'System default';
}
6 changes: 6 additions & 0 deletions lib/generated/l10n/zulip_localizations_pl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -728,4 +728,10 @@ class ZulipLocalizationsPl extends ZulipLocalizations {

@override
String get zulipAppTitle => 'Zulip';

@override
String get languageSettingsTitle => 'Language';

@override
String get systemDefaultLanguage => 'System default';
}
6 changes: 6 additions & 0 deletions lib/generated/l10n/zulip_localizations_ru.dart
Original file line number Diff line number Diff line change
Expand Up @@ -731,4 +731,10 @@ class ZulipLocalizationsRu extends ZulipLocalizations {

@override
String get zulipAppTitle => 'Zulip';

@override
String get languageSettingsTitle => 'Language';

@override
String get systemDefaultLanguage => 'System default';
}
6 changes: 6 additions & 0 deletions lib/generated/l10n/zulip_localizations_sk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -719,4 +719,10 @@ class ZulipLocalizationsSk extends ZulipLocalizations {

@override
String get zulipAppTitle => 'Zulip';

@override
String get languageSettingsTitle => 'Language';

@override
String get systemDefaultLanguage => 'System default';
}
6 changes: 6 additions & 0 deletions lib/generated/l10n/zulip_localizations_uk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -731,4 +731,10 @@ class ZulipLocalizationsUk extends ZulipLocalizations {

@override
String get zulipAppTitle => 'Zulip';

@override
String get languageSettingsTitle => 'Language';

@override
String get systemDefaultLanguage => 'System default';
}
73 changes: 73 additions & 0 deletions lib/widgets/app.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:path_provider/path_provider.dart';

import '../generated/l10n/zulip_localizations.dart';
import '../log.dart';
Expand Down Expand Up @@ -47,6 +50,63 @@ class ZulipApp extends StatefulWidget {
return completer.future;
}

// static Locale? currentLocale;
// static final ValueNotifier<Locale?> _localeNotifier = ValueNotifier(currentLocale);
//
// static void setLocale(Locale? locale) {
// currentLocale = locale;
// _localeNotifier.value = locale;
// }

static Locale? currentLocale;
static final ValueNotifier<Locale?> _localeNotifier = ValueNotifier(currentLocale);
static File? _prefsFile;

static Future<File> _getPrefsFile() async {
if (_prefsFile == null) {
final dir = await getApplicationDocumentsDirectory();
_prefsFile = File('${dir.path}/language_prefs.json');
if (!await _prefsFile!.exists()) {
await _prefsFile!.create();
}
}
return _prefsFile!;
}

static Future<void> setLocale(Locale? locale) async {
currentLocale = locale;
_localeNotifier.value = locale;

try {
final file = await _getPrefsFile();
await file.writeAsString(
jsonEncode({'locale': locale?.toString()}),
flush: true,
);
} catch (e) {
debugPrint('Error saving locale: $e');
}
}

static Future<void> loadSavedLocale() async {
try {
final file = await _getPrefsFile();
final content = await file.readAsString();
if (content.isNotEmpty) {
final data = jsonDecode(content) as Map<String, dynamic>;
final localeString = data['locale'] as String?;
if (localeString != null && localeString.isNotEmpty) {
final parts = localeString.split('_');
currentLocale = parts.length == 2
? Locale(parts[0], parts[1])
: Locale(parts[0]);
_localeNotifier.value = currentLocale;
}
}
} catch (e) {
debugPrint('Error loading locale: $e');
}
}
/// A key for the navigator for the whole app.
///
/// For code that exists entirely outside the widget tree and has no natural
Expand Down Expand Up @@ -160,14 +220,26 @@ class _ZulipAppState extends State<ZulipApp> with WidgetsBindingObserver {
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
ZulipApp._localeNotifier.addListener(_handleLocaleChange);
_initializeApp();
}

Future<void> _initializeApp() async {
await ZulipApp.loadSavedLocale(); // Load saved locale first
ZulipApp._localeNotifier.addListener(_handleLocaleChange);
}

@override
void dispose() {
ZulipApp._localeNotifier.removeListener(_handleLocaleChange);
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}

void _handleLocaleChange() {
if (mounted) setState(() {});
}

List<Route<dynamic>> _handleGenerateInitialRoutes(String initialRoute) {
// The `_ZulipAppState.context` lacks the required ancestors. Instead
// we use the Navigator which should be available when this callback is
Expand Down Expand Up @@ -220,6 +292,7 @@ class _ZulipAppState extends State<ZulipApp> with WidgetsBindingObserver {
return GlobalStoreWidget(
child: Builder(builder: (context) {
return MaterialApp(
locale: ZulipApp.currentLocale,
onGenerateTitle: (BuildContext context) {
return ZulipLocalizations.of(context).zulipAppTitle;
},
Expand Down
Loading