Skip to content

Commit 0208bbf

Browse files
committed
db: Store language global setting in database
An alternative to implementing _fromLanguageTag is using the LocaleParser from package:intl/locale.dart. In this case though, the values to parse always come from `toLanguageTag`, so we can utilize that knowledge to get away with a more simple implementation, that should also be handy upstream. The locale stored in the database is not guaranteed to be one of our supported value, especially if we need to rename locales in the future. See discussion: zulip#1513 (comment)
1 parent 4305fe1 commit 0208bbf

File tree

10 files changed

+1215
-7
lines changed

10 files changed

+1215
-7
lines changed

lib/model/database.dart

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import 'dart:ui';
2+
13
import 'package:drift/drift.dart';
24
import 'package:drift/internal/versioned_schema.dart';
35
import 'package:drift/remote.dart';
@@ -24,6 +26,8 @@ class GlobalSettings extends Table {
2426
Column<String> get browserPreference => textEnum<BrowserPreference>()
2527
.nullable()();
2628

29+
Column<String> get language => text().map(const LocaleConverter()).nullable()();
30+
2731
// If adding a new column to this table, consider whether [BoolGlobalSettings]
2832
// can do the job instead (by adding a value to the [BoolGlobalSetting] enum).
2933
// That way is more convenient, when it works, because
@@ -119,7 +123,7 @@ class AppDatabase extends _$AppDatabase {
119123
// information on using the build_runner.
120124
// * Write a migration in `_migrationSteps` below.
121125
// * Write tests.
122-
static const int latestSchemaVersion = 6; // See note.
126+
static const int latestSchemaVersion = 7; // See note.
123127

124128
@override
125129
int get schemaVersion => latestSchemaVersion;
@@ -174,6 +178,9 @@ class AppDatabase extends _$AppDatabase {
174178
from5To6: (m, schema) async {
175179
await m.createTable(schema.boolGlobalSettings);
176180
},
181+
from6To7: (m, schema) async {
182+
await m.addColumn(schema.globalSettings, schema.globalSettings.language);
183+
}
177184
);
178185

179186
Future<void> _createLatestSchema(Migrator m) async {
@@ -243,3 +250,55 @@ class AppDatabase extends _$AppDatabase {
243250
}
244251

245252
class AccountAlreadyExistsException implements Exception {}
253+
254+
class LocaleConverter extends TypeConverter<Locale, String> {
255+
const LocaleConverter();
256+
257+
/// Parse a Unicode BCP 47 Language Identifier into [Locale].
258+
///
259+
/// Throw when it fails to convert [languageTag] into a [Locale].
260+
///
261+
/// This supports parsing a Unicode Language Identifier returned from
262+
/// [Locale.toLanguageTag].
263+
///
264+
/// This implementation refers to a part of
265+
/// [this EBNF grammar](https://www.unicode.org/reports/tr35/#Unicode_language_identifier),
266+
/// assuming the identifier is valid without
267+
/// [unicode_variant_subtag](https://www.unicode.org/reports/tr35/#unicode_variant_subtag).
268+
///
269+
/// This doesn't check if the [languageTag] is a valid identifier, (i.e., when
270+
/// this returns without errors, the identifier is not necessarily
271+
/// syntactically well-formed or valid).
272+
// TODO(upstream): send this as a factory Locale.fromLanguageTag
273+
// https://github.com/flutter/flutter/issues/143491
274+
Locale _fromLanguageTag(String languageTag) {
275+
final subtags = languageTag.replaceAll('_', '-').split('-');
276+
277+
return switch (subtags) {
278+
[final language, final script, final region] =>
279+
Locale.fromSubtags(
280+
languageCode: language, scriptCode: script, countryCode: region),
281+
282+
[final language, final script] when script.length == 4 =>
283+
Locale.fromSubtags(languageCode: language, scriptCode: script),
284+
285+
[final language, final region] =>
286+
Locale(language, region),
287+
288+
[final language] =>
289+
Locale(language),
290+
291+
_ => throw ArgumentError.value(languageTag, 'languageTag'),
292+
};
293+
}
294+
295+
@override
296+
Locale fromSql(String fromDb) {
297+
return _fromLanguageTag(fromDb);
298+
}
299+
300+
@override
301+
String toSql(Locale value) {
302+
return value.toLanguageTag();
303+
}
304+
}

lib/model/database.g.dart

Lines changed: 82 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)