...
 
Commits (2)
flutter pub run intl_translation:extract_to_arb \
--output-dir=lib/src/resources/intl lib/src/resources/intl/localizations.dart
mv lib/src/resources/intl/intl_messages.arb lib/src/resources/intl/intl_en.arb
flutter pub run intl_translation:generate_from_arb \
--output-dir=lib/src/resources/intl --no-use-deferred-loading \
lib/src/resources/intl/localizations.dart lib/src/resources/intl/*.arb
......@@ -26,7 +26,7 @@ import 'package:provider/provider.dart';
import 'auth/bloc.dart';
import 'matrix.dart';
import 'notifications/bloc.dart';
import 'resources/localizations.dart';
import 'resources/intl/localizations.dart';
import 'resources/theme.dart';
import 'section/main/chat/page.dart';
import 'section/main/chat/image/page.dart';
......@@ -156,9 +156,9 @@ class App extends StatelessWidget {
),
child: MaterialApp(
onGenerateTitle: (BuildContext context) =>
l(context).appName,
context.intl.appName,
localizationsDelegates: [
const AppLocalizationsDelegate(),
const PattleLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
......
{
"@@last_modified": "2020-03-22T18:31:30.071193",
"appName": "Pattle",
"@appName": {
"type": "text",
"placeholders": {}
},
"_Common_name": "Name",
"@_Common_name": {
"type": "text",
"placeholders": {}
},
"_Common_username": "Username",
"@_Common_username": {
"type": "text",
"placeholders": {}
},
"_Common_password": "Password",
"@_Common_password": {
"type": "text",
"placeholders": {}
},
"_Common_confirm": "Confirm",
"@_Common_confirm": {
"type": "text",
"placeholders": {}
},
"_Common_next": "Next",
"@_Common_next": {
"type": "text",
"placeholders": {}
},
"_Common_photo": "Photo",
"@_Common_photo": {
"type": "text",
"placeholders": {}
},
"_Common_you": "You",
"@_Common_you": {
"description": "Used to denote the user using the app instead of their name",
"type": "text",
"placeholders": {}
},
"_Start_advanced": "Advanced",
"@_Start_advanced": {
"type": "text",
"placeholders": {}
},
"_Start_login": "Login",
"@_Start_login": {
"type": "text",
"placeholders": {}
},
"_Start_register": "Register",
"@_Start_register": {
"type": "text",
"placeholders": {}
},
"_Start_homeserver": "Homeserver",
"@_Start_homeserver": {
"type": "text",
"placeholders": {}
},
"_Start_identityServer": "Identity server",
"@_Start_identityServer": {
"type": "text",
"placeholders": {}
},
"_Start_loginWithPhone": "Login with phone number",
"@_Start_loginWithPhone": {
"type": "text",
"placeholders": {}
},
"_Start_loginWithEmail": "Login with email",
"@_Start_loginWithEmail": {
"type": "text",
"placeholders": {}
},
"_Start_loginWithUsername": "Login with username",
"@_Start_loginWithUsername": {
"type": "text",
"placeholders": {}
},
"_StartUsername_title": "Enter username",
"@_StartUsername_title": {
"type": "text",
"placeholders": {}
},
"_StartUsername_usernameInvalidError": "Invalid username. May only contain letters, numbers, -, ., =, _ and /",
"@_StartUsername_usernameInvalidError": {
"type": "text",
"placeholders": {}
},
"_StartUsername_userIdInvalidError": "Invalid user ID. Must be in the format of '@name:server.tld'",
"@_StartUsername_userIdInvalidError": {
"type": "text",
"placeholders": {}
},
"_StartUsername_hostnameInvalidError": "Invalid hostname",
"@_StartUsername_hostnameInvalidError": {
"type": "text",
"placeholders": {}
},
"_StartUsername_unknownError": "An unknown error occured",
"@_StartUsername_unknownError": {
"type": "text",
"placeholders": {}
},
"_StartUsername_wrongPasswordError": "Wrong password. Please try again",
"@_StartUsername_wrongPasswordError": {
"type": "text",
"placeholders": {}
},
"_Chat_typeAMessage": "Type a message",
"@_Chat_typeAMessage": {
"description": "Hint for the chat input",
"type": "text",
"placeholders": {}
},
"_Chat_cantSendMessages": "You can't send messages to this group because you're no longer a participant.",
"@_Chat_cantSendMessages": {
"type": "text",
"placeholders": {}
},
"_Chat_typing": "typing...",
"@_Chat_typing": {
"type": "text",
"placeholders": {}
},
"_Chat_isTyping": "{name} is typing...",
"@_Chat_isTyping": {
"type": "text",
"placeholders": {
"name": {}
}
},
"_Chat_areTyping": "{andMore,select, false{{first} and {second} are typing...}true{{first}, {second} and more are typing...}}",
"@_Chat_areTyping": {
"type": "text",
"placeholders": {
"andMore": {},
"first": {},
"second": {}
}
},
"_ChatMessage_deletion": "{person,select, second{You deleted this message}third{{name} deleted this message}}",
"@_ChatMessage_deletion": {
"type": "text",
"placeholders": {
"person": {},
"name": {}
}
},
"_ChatMessage_creation": "{person,select, second{You created this group}third{{name} created this group}}",
"@_ChatMessage_creation": {
"type": "text",
"placeholders": {
"person": {},
"name": {}
}
},
"_ChatMessage_upgrade": "{person,select, second{You upgraded this group}third{{name} upgraded this group}}",
"@_ChatMessage_upgrade": {
"type": "text",
"placeholders": {
"person": {},
"name": {}
}
},
"_ChatMessage_descriptionChange": "{person,select, second{You changed the description of this group}third{{name} changed the description of this group}}",
"@_ChatMessage_descriptionChange": {
"type": "text",
"placeholders": {
"person": {},
"name": {}
}
},
"_ChatMessage_join": "{person,select, second{You joined}third{{name} joined}}",
"@_ChatMessage_join": {
"type": "text",
"placeholders": {
"person": {},
"name": {}
}
},
"_ChatMessage_leave": "{person,select, second{You left}third{{name} left}}",
"@_ChatMessage_leave": {
"type": "text",
"placeholders": {
"person": {},
"name": {}
}
},
"_ChatMessage_ban": "{person,select, secondOnSecond{You were banned by yourself}secondOnThird{You were banned by {banner}}thirdOnThird{{bannee} was banned by {banner}}thirdOnSecond{{bannee} was banned by you}}",
"@_ChatMessage_ban": {
"type": "text",
"placeholders": {
"person": {},
"bannee": {},
"banner": {}
}
},
"_ChatMessage_invite": "{person,select, secondOnSecond{You were invited by yourself}secondOnThird{You were invited by {inviter}}thirdOnThird{{invitee} was invited by {inviter}}thirdOnSecond{{invitee} was invited by you}}",
"@_ChatMessage_invite": {
"type": "text",
"placeholders": {
"person": {},
"invitee": {},
"inviter": {}
}
},
"_ChatDetails_description": "Description",
"@_ChatDetails_description": {
"type": "text",
"placeholders": {}
},
"_ChatDetails_noDescriptionSet": "No description has been set",
"@_ChatDetails_noDescriptionSet": {
"type": "text",
"placeholders": {}
},
"_ChatDetails_more": "{count} more",
"@_ChatDetails_more": {
"type": "text",
"placeholders": {
"count": {}
}
},
"Participants": "Participants",
"@Participants": {
"type": "text",
"placeholders": {}
},
"_ChatDetails_participants": "{count,plural, =0{No participants}=1{{count} participant}other{{count} participants}}",
"@_ChatDetails_participants": {
"type": "text",
"placeholders": {
"count": {}
}
},
"_Chats_personal": "Personal",
"@_Chats_personal": {
"type": "text",
"placeholders": {}
},
"_Chats_public": "Public",
"@_Chats_public": {
"type": "text",
"placeholders": {}
},
"_ChatsNewGroup_title": "New group",
"@_ChatsNewGroup_title": {
"type": "text",
"placeholders": {}
},
"_ChatsNewGroup_groupName": "Group name",
"@_ChatsNewGroup_groupName": {
"type": "text",
"placeholders": {}
},
"_Settings_title": "Settings",
"@_Settings_title": {
"description": "Settings page title",
"type": "text",
"placeholders": {}
},
"_Settings_accountTileTitle": "Account",
"@_Settings_accountTileTitle": {
"type": "text",
"placeholders": {}
},
"_Settings_accountTileSubtitle": "Privacy, security, change password",
"@_Settings_accountTileSubtitle": {
"type": "text",
"placeholders": {}
},
"_Settings_appearanceTileTitle": "Appearance",
"@_Settings_appearanceTileTitle": {
"type": "text",
"placeholders": {}
},
"_Settings_appearanceTileSubtitle": "Theme, font size",
"@_Settings_appearanceTileSubtitle": {
"type": "text",
"placeholders": {}
},
"_Settings_brightnessTileTitle": "Brightness",
"@_Settings_brightnessTileTitle": {
"type": "text",
"placeholders": {}
},
"_Settings_brightnessTileOptionLight": "Light",
"@_Settings_brightnessTileOptionLight": {
"type": "text",
"placeholders": {}
},
"_Settings_brightnessTileOptionDark": "Dark",
"@_Settings_brightnessTileOptionDark": {
"type": "text",
"placeholders": {}
},
"Profile": "Profile",
"@Profile": {
"type": "text",
"placeholders": {}
},
"_Settings_editNameDescription": "This is not your username. This is the name that will be visible to others.",
"@_Settings_editNameDescription": {
"type": "text",
"placeholders": {}
},
"_Error_connectionLost": "Connection has been lost.\nMake sure your phone has an active internet connection.",
"@_Error_connectionLost": {
"type": "text",
"placeholders": {}
},
"_Error_connectionFailed": "Connection failed. Check your internet connection",
"@_Error_connectionFailed": {
"type": "text",
"placeholders": {}
},
"_Error_connectionFailedServerOverloaded": "Connection failed. The server is probably overloaded.",
"@_Error_connectionFailedServerOverloaded": {
"type": "text",
"placeholders": {}
},
"_Error_anErrorHasOccurred": "An error has occurred:",
"@_Error_anErrorHasOccurred": {
"description": "After this message the error is displayed (hence the colon)",
"type": "text",
"placeholders": {}
},
"_Error_thisErrorHasBeenReported": "This error has been reported. Please restart Pattle.",
"@_Error_thisErrorHasBeenReported": {
"type": "text",
"placeholders": {}
},
"_Time_today": "Today",
"@_Time_today": {
"type": "text",
"placeholders": {}
},
"_Time_yesterday": "Yesterday",
"@_Time_yesterday": {
"type": "text",
"placeholders": {}
}
}
\ No newline at end of file
This diff is collapsed.
// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
// This is a library that looks up messages for specific locales by
// delegating to the appropriate library.
// Ignore issues from commonly used lints in this file.
// ignore_for_file:implementation_imports, file_names, unnecessary_new
// ignore_for_file:unnecessary_brace_in_string_interps, directives_ordering
// ignore_for_file:argument_type_not_assignable, invalid_assignment
// ignore_for_file:prefer_single_quotes, prefer_generic_function_type_aliases
// ignore_for_file:comment_references
import 'dart:async';
import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart';
import 'package:intl/src/intl_helpers.dart';
import 'messages_en.dart' as messages_en;
typedef Future<dynamic> LibraryLoader();
Map<String, LibraryLoader> _deferredLibraries = {
'en': () => new Future.value(null),
};
MessageLookupByLibrary _findExact(String localeName) {
switch (localeName) {
case 'en':
return messages_en.messages;
default:
return null;
}
}
/// User programs should call this before using [localeName] for messages.
Future<bool> initializeMessages(String localeName) async {
var availableLocale = Intl.verifiedLocale(
localeName,
(locale) => _deferredLibraries[locale] != null,
onFailure: (_) => null);
if (availableLocale == null) {
return new Future.value(false);
}
var lib = _deferredLibraries[availableLocale];
await (lib == null ? new Future.value(false) : lib());
initializeInternalMessageLookup(() => new CompositeMessageLookup());
messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor);
return new Future.value(true);
}
bool _messagesExistFor(String locale) {
try {
return _findExact(locale) != null;
} catch (e) {
return false;
}
}
MessageLookupByLibrary _findGeneratedMessagesFor(String locale) {
var actualLocale = Intl.verifiedLocale(locale, _messagesExistFor,
onFailure: (_) => null);
if (actualLocale == null) return null;
return _findExact(actualLocale);
}
// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
// This is a library that provides messages for a en locale. All the
// messages from the main program should be duplicated here with the same
// function name.
// Ignore issues from commonly used lints in this file.
// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new
// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering
// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases
// ignore_for_file:unused_import, file_names
import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart';
final messages = new MessageLookup();
typedef String MessageIfAbsent(String messageStr, List<dynamic> args);
class MessageLookup extends MessageLookupByLibrary {
String get localeName => 'en';
static m0(count) => "${count} more";
static m1(count) => "${Intl.plural(count, zero: 'No participants', one: '${count} participant', other: '${count} participants')}";
static m2(person, bannee, banner) => "${Intl.select(person, {'secondOnSecond': 'You were banned by yourself', 'secondOnThird': 'You were banned by ${banner}', 'thirdOnThird': '${bannee} was banned by ${banner}', 'thirdOnSecond': '${bannee} was banned by you', })}";
static m3(person, name) => "${Intl.select(person, {'second': 'You created this group', 'third': '${name} created this group', })}";
static m4(person, name) => "${Intl.select(person, {'second': 'You deleted this message', 'third': '${name} deleted this message', })}";
static m5(person, name) => "${Intl.select(person, {'second': 'You changed the description of this group', 'third': '${name} changed the description of this group', })}";
static m6(person, invitee, inviter) => "${Intl.select(person, {'secondOnSecond': 'You were invited by yourself', 'secondOnThird': 'You were invited by ${inviter}', 'thirdOnThird': '${invitee} was invited by ${inviter}', 'thirdOnSecond': '${invitee} was invited by you', })}";
static m7(person, name) => "${Intl.select(person, {'second': 'You joined', 'third': '${name} joined', })}";
static m8(person, name) => "${Intl.select(person, {'second': 'You left', 'third': '${name} left', })}";
static m9(person, name) => "${Intl.select(person, {'second': 'You upgraded this group', 'third': '${name} upgraded this group', })}";
static m10(andMore, first, second) => "${Intl.select(andMore, {'false': '${first} and ${second} are typing...', 'true': '${first}, ${second} and more are typing...', })}";
static m11(name) => "${name} is typing...";
final messages = _notInlinedMessages(_notInlinedMessages);
static _notInlinedMessages(_) => <String, Function> {
"Participants" : MessageLookupByLibrary.simpleMessage("Participants"),
"Profile" : MessageLookupByLibrary.simpleMessage("Profile"),
"_ChatDetails_description" : MessageLookupByLibrary.simpleMessage("Description"),
"_ChatDetails_more" : m0,
"_ChatDetails_noDescriptionSet" : MessageLookupByLibrary.simpleMessage("No description has been set"),
"_ChatDetails_participants" : m1,
"_ChatMessage_ban" : m2,
"_ChatMessage_creation" : m3,
"_ChatMessage_deletion" : m4,
"_ChatMessage_descriptionChange" : m5,
"_ChatMessage_invite" : m6,
"_ChatMessage_join" : m7,
"_ChatMessage_leave" : m8,
"_ChatMessage_upgrade" : m9,
"_Chat_areTyping" : m10,
"_Chat_cantSendMessages" : MessageLookupByLibrary.simpleMessage("You can\'t send messages to this group because you\'re no longer a participant."),
"_Chat_isTyping" : m11,
"_Chat_typeAMessage" : MessageLookupByLibrary.simpleMessage("Type a message"),
"_Chat_typing" : MessageLookupByLibrary.simpleMessage("typing..."),
"_ChatsNewGroup_groupName" : MessageLookupByLibrary.simpleMessage("Group name"),
"_ChatsNewGroup_title" : MessageLookupByLibrary.simpleMessage("New group"),
"_Chats_personal" : MessageLookupByLibrary.simpleMessage("Personal"),
"_Chats_public" : MessageLookupByLibrary.simpleMessage("Public"),
"_Common_confirm" : MessageLookupByLibrary.simpleMessage("Confirm"),
"_Common_name" : MessageLookupByLibrary.simpleMessage("Name"),
"_Common_next" : MessageLookupByLibrary.simpleMessage("Next"),
"_Common_password" : MessageLookupByLibrary.simpleMessage("Password"),
"_Common_photo" : MessageLookupByLibrary.simpleMessage("Photo"),
"_Common_username" : MessageLookupByLibrary.simpleMessage("Username"),
"_Common_you" : MessageLookupByLibrary.simpleMessage("You"),
"_Error_anErrorHasOccurred" : MessageLookupByLibrary.simpleMessage("An error has occurred:"),
"_Error_connectionFailed" : MessageLookupByLibrary.simpleMessage("Connection failed. Check your internet connection"),
"_Error_connectionFailedServerOverloaded" : MessageLookupByLibrary.simpleMessage("Connection failed. The server is probably overloaded."),
"_Error_connectionLost" : MessageLookupByLibrary.simpleMessage("Connection has been lost.\nMake sure your phone has an active internet connection."),
"_Error_thisErrorHasBeenReported" : MessageLookupByLibrary.simpleMessage("This error has been reported. Please restart Pattle."),
"_Settings_accountTileSubtitle" : MessageLookupByLibrary.simpleMessage("Privacy, security, change password"),
"_Settings_accountTileTitle" : MessageLookupByLibrary.simpleMessage("Account"),
"_Settings_appearanceTileSubtitle" : MessageLookupByLibrary.simpleMessage("Theme, font size"),
"_Settings_appearanceTileTitle" : MessageLookupByLibrary.simpleMessage("Appearance"),
"_Settings_brightnessTileOptionDark" : MessageLookupByLibrary.simpleMessage("Dark"),
"_Settings_brightnessTileOptionLight" : MessageLookupByLibrary.simpleMessage("Light"),
"_Settings_brightnessTileTitle" : MessageLookupByLibrary.simpleMessage("Brightness"),
"_Settings_editNameDescription" : MessageLookupByLibrary.simpleMessage("This is not your username. This is the name that will be visible to others."),
"_Settings_title" : MessageLookupByLibrary.simpleMessage("Settings"),
"_StartUsername_hostnameInvalidError" : MessageLookupByLibrary.simpleMessage("Invalid hostname"),
"_StartUsername_title" : MessageLookupByLibrary.simpleMessage("Enter username"),
"_StartUsername_unknownError" : MessageLookupByLibrary.simpleMessage("An unknown error occured"),
"_StartUsername_userIdInvalidError" : MessageLookupByLibrary.simpleMessage("Invalid user ID. Must be in the format of \'@name:server.tld\'"),
"_StartUsername_usernameInvalidError" : MessageLookupByLibrary.simpleMessage("Invalid username. May only contain letters, numbers, -, ., =, _ and /"),
"_StartUsername_wrongPasswordError" : MessageLookupByLibrary.simpleMessage("Wrong password. Please try again"),
"_Start_advanced" : MessageLookupByLibrary.simpleMessage("Advanced"),
"_Start_homeserver" : MessageLookupByLibrary.simpleMessage("Homeserver"),
"_Start_identityServer" : MessageLookupByLibrary.simpleMessage("Identity server"),
"_Start_login" : MessageLookupByLibrary.simpleMessage("Login"),
"_Start_loginWithEmail" : MessageLookupByLibrary.simpleMessage("Login with email"),
"_Start_loginWithPhone" : MessageLookupByLibrary.simpleMessage("Login with phone number"),
"_Start_loginWithUsername" : MessageLookupByLibrary.simpleMessage("Login with username"),
"_Start_register" : MessageLookupByLibrary.simpleMessage("Register"),
"_Time_today" : MessageLookupByLibrary.simpleMessage("Today"),
"_Time_yesterday" : MessageLookupByLibrary.simpleMessage("Yesterday"),
"appName" : MessageLookupByLibrary.simpleMessage("Pattle")
};
}
// Copyright (C) 2019 Wilko Manger
//
// This file is part of Pattle.
//
// Pattle is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Pattle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Pattle. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
Strings l(BuildContext context) => AppLocalizations.of(context).strings;
class Strings {
const Strings();
// Common //
final appName = 'Pattle';
final name = 'Name';
final advanced = 'Advanced';
final username = 'Username';
final password = 'Password';
final confirm = 'Confirm';
final login = 'Login';
final register = 'Register';
final next = 'Next';
final homeserver = 'Homeserver';
final identityServer = 'Identity server';
final today = 'Today';
final yesterday = 'Yesterday';
final photo = 'Photo';
final typeAMessage = 'Type a message';
final you = 'You';
final andOthers = 'and others';
final newGroup = 'New group';
final groupName = 'Group name';
final participants = 'Participants';
final profile = 'Profile';
final settings = 'Settings';
final personal = 'Personal';
final public = 'Public';
final calls = 'Calls';
final description = 'Description';
final noDescriptionSet = 'No description has been set';
final cantSendMessages =
'You can\'t send messages to this group because you\'re no longer a participant.';
final connectionLost = 'Connection has been lost.\n'
'Make sure your phone has an active internet connection.';
final connectionFailed = 'Connection failed. '
'Check your internet connection';
final connectionFailedServerOverloaded = 'Connection failed. '
'The server is probably overloaded.';
final anErrorHasOccurred = 'An error has occurred:';
final thisErrorHasBeenReported =
'This error has been reported. Please restart Pattle.';
final youDeletedThisMessage = 'You deleted this message';
List<TextSpan> hasDeletedThisMessage(TextSpan name) =>
[name, TextSpan(text: ' deleted this message')];
// StartPage //
final loginWithPhone = 'Login with phone number';
final loginWithEmail = 'Login with email';
final loginWithUsername = 'Login with username';
// StartPage: UsernamePage //
final enterUsername = 'Enter username';
final ifYouDontHaveAnAccount =
"If you don't have an account, we'll create one";
final usernameInvalidError =
"Invalid username. May only contain letters, numbers, -, ., =, _ and /";
final userIdInvalidError =
"Invalid user ID. Must be in the format of '@name:server.tld'";
final hostnameInvalidError = 'Invalid hostname';
final unknownError = 'An unknown error occured';
final failedUsernameCheckAvailableError =
'Failed to check if the username is available';
final wouldYouLikeLoginOrRegister = 'Would you like to login or register?';
// StartPage: PasswordPage //
final enterPassword = 'Enter password';
final wrongPasswordError = 'Wrong password. Please try again';
String loggingInAs(String name) => 'Logging in as $name';
// SettingsPage //
final account = 'Account';
final accountDescription = 'Privacy, security, change password';
final appearance = 'Appearance';
final appearanceDescription = 'Theme, font size';
final brightness = 'Brightness';
final light = 'Light';
final dark = 'Dark';
final editNameDescription = 'This is not your username.'
' This is the name that will be visible to others.';
// Room creation event
List<TextSpan> createdThisGroup(TextSpan name) =>
[name, TextSpan(text: ' created this group')];
// Room upgrade event
List<TextSpan> upgradedThisGroup(TextSpan name) =>
[name, TextSpan(text: ' upgraded this group')];
// Topic change event
List<TextSpan> changedDescriptionTapToView(TextSpan name) => [
name,
TextSpan(text: ' changed the description of this group. Tap to view')
];
List<TextSpan> changedDescription(TextSpan name) =>
[name, TextSpan(text: ' changed the description of this group')];
// Member change events
List<TextSpan> changedTheirNameTo(TextSpan oldName, TextSpan newName) =>
[oldName, TextSpan(text: ' changed their name to '), newName];
List<TextSpan> joined(TextSpan name) => [name, TextSpan(text: ' joined')];
List<TextSpan> left(TextSpan name) => [name, TextSpan(text: ' left')];
List<TextSpan> wasBannedBy(TextSpan banee, TextSpan banner) =>
[banee, TextSpan(text: ' was banned by '), banner];
List<TextSpan> wasInvitedBy(TextSpan invitee, TextSpan inviter) =>
[invitee, TextSpan(text: ' was invited by '), inviter];
// Typing events
List<TextSpan> get typing => [TextSpan(text: 'typing...')];
List<TextSpan> isTyping(TextSpan name) => [
name,
TextSpan(text: ' is typing...'),
];
List<TextSpan> areTyping(TextSpan first, TextSpan second) => [
first,
TextSpan(text: ' and '),
second,
TextSpan(text: ' are typing...')
];
List<TextSpan> andMoreAreTyping(TextSpan first, TextSpan second) => [
first,
TextSpan(text: ' and '),
second,
TextSpan(text: ' and more typing...')
];
String xMore(int count) => '$count more';
String xParticipants(int count) => '$count participants';
}
class AppLocalizations {
AppLocalizations(this.locale) {
switch (locale.languageCode) {
case 'en':
_strings = const Strings();
break;
default:
_strings = const Strings();
}
}
final Locale locale;
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
Strings _strings;
Strings get strings => _strings;
}
class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const AppLocalizationsDelegate();
@override
bool isSupported(Locale locale) => ['en'].contains(locale.languageCode);
@override
Future<AppLocalizations> load(Locale locale) {
return SynchronousFuture<AppLocalizations>(AppLocalizations(locale));
}
@override
bool shouldReload(AppLocalizationsDelegate old) => false;
}
......@@ -24,7 +24,7 @@ import 'package:image_picker/image_picker.dart';
import 'package:matrix_sdk/matrix_sdk.dart';
import 'package:pattle/src/app.dart';
import 'package:pattle/src/resources/localizations.dart';
import 'package:pattle/src/resources/intl/localizations.dart';
import 'package:pattle/src/resources/theme.dart';
import 'package:pattle/src/section/main/chats/models/chat.dart';
import 'package:pattle/src/section/main/chats/widgets/typing_content.dart';
......@@ -317,7 +317,7 @@ class _InputState extends State<_Input> {
),
),
filled: true,
hintText: l(context).typeAMessage,
hintText: context.intl.chat.typeAMessage,
prefixIcon: IconButton(
icon: Icon(Icons.attach_file),
onPressed: () async {
......@@ -350,7 +350,7 @@ class _InputState extends State<_Input> {
child: Padding(
padding: EdgeInsets.all(16),
child: Text(
l(context).cantSendMessages,
context.intl.chat.cantSendMessages,
textAlign: TextAlign.center,
),
),
......
......@@ -21,7 +21,7 @@ import 'package:flutter/rendering.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:matrix_sdk/matrix_sdk.dart';
import 'package:pattle/src/resources/localizations.dart';
import 'package:pattle/src/resources/intl/localizations.dart';
import 'package:pattle/src/resources/theme.dart';
import 'package:pattle/src/section/main/chats/models/chat.dart';
import 'package:pattle/src/section/main/models/chat_member.dart';
......@@ -132,7 +132,7 @@ class _Description extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
l(context).description,
context.intl.chat.details.description,
style: TextStyle(
color: redOnBackground(context),
fontSize: 16,
......@@ -141,7 +141,7 @@ class _Description extends StatelessWidget {
),
SizedBox(height: 4),
Text(
description ?? l(context).noDescriptionSet,
description ?? context.intl.chat.details.description,
style: TextStyle(
fontStyle: description == null
? FontStyle.italic
......@@ -188,7 +188,9 @@ class _MemberListState extends State<_MemberList> {
Padding(
padding: EdgeInsets.only(left: 16, top: 16),
child: Text(
l(context).xParticipants(widget.room.members.count),
context.intl.chat.details.participants(
widget.room.members.count,
),
style: TextStyle(
color: redOnBackground(context),
fontSize: 16,
......@@ -270,7 +272,11 @@ class _ShowMoreItem extends StatelessWidget {
Widget build(BuildContext context) {
return ListTile(
leading: Icon(Icons.keyboard_arrow_down, size: 32),
title: Text(l(context).xMore(room.members.count - shownMembersCount)),
title: Text(
context.intl.chat.details.more(
room.members.count - shownMembersCount,
),
),
subtitle: isLoading ? LinearProgressIndicator() : null,
onTap: onTap,
);
......
......@@ -17,7 +17,7 @@
// along with Pattle. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:pattle/src/resources/localizations.dart';
import 'package:pattle/src/resources/intl/localizations.dart';
import 'package:pattle/src/section/main/models/chat_message.dart';
import '../state.dart';
......@@ -36,12 +36,11 @@ class CreationContent extends StatelessWidget {
return RichText(
text: TextSpan(
style: DefaultTextStyle.of(context).style,
children: l(context).createdThisGroup(
TextSpan(
text: message.sender.name,
style: TextStyle(
fontWeight: FontWeight.bold,
),
children: context.intl.chat.message.creation.toTextSpans(
message.sender.person,
message.sender.name,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
......
......@@ -18,7 +18,7 @@
import 'package:flutter/material.dart';
import 'package:matrix_sdk/matrix_sdk.dart';
import 'package:pattle/src/resources/localizations.dart';
import 'package:pattle/src/resources/intl/localizations.dart';
import 'package:pattle/src/section/main/models/chat_message.dart';
import '../state.dart';
......@@ -34,25 +34,33 @@ class MemberChangeContent extends StatelessWidget {
final event = message.event;
final style = TextStyle(fontWeight: FontWeight.bold);
final sender = TextSpan(
text: message.sender.name,
style: style,
);
final subject = TextSpan(
text: message.subject.name,
style: style,
);
var text;
if (event is JoinEvent) {
text = l(context).joined(subject);
text = context.intl.chat.message.join.toTextSpans(
message.subject.person,
message.subject.name,
style: style,
);
} else if (event is LeaveEvent) {
text = l(context).left(subject);
text = context.intl.chat.message.leave.toTextSpans(
message.subject.person,
message.subject.name,
style: style,
);
} else if (event is InviteEvent) {
text = l(context).wasInvitedBy(subject, sender);
text = context.intl.chat.message.invite.toTextSpans(
message.subject.personTo(message.sender),
message.subject.name,
message.sender.name,
style: style,
);
} else if (event is BanEvent) {
text = l(context).wasBannedBy(subject, sender);
text = context.intl.chat.message.ban.toTextSpans(
message.subject.personTo(message.sender),
message.subject.name,
message.sender.name,
style: style,
);
}
return text;
......
......@@ -17,7 +17,7 @@
// along with Pattle. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:pattle/src/resources/localizations.dart';
import 'package:pattle/src/resources/intl/localizations.dart';
import 'package:pattle/src/section/main/models/chat_message.dart';
import '../state.dart';
......@@ -36,10 +36,9 @@ class TopicChangeContent extends StatelessWidget {
return RichText(
text: TextSpan(
style: DefaultTextStyle.of(context).style,
children: l(context).changedDescriptionTapToView(
TextSpan(
text: message.sender.name,
),
children: context.intl.chat.message.descriptionChange.toTextSpans(
message.sender.person,
message.sender.name,
),
),
);
......
......@@ -17,7 +17,7 @@
// along with Pattle. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:pattle/src/resources/localizations.dart';
import 'package:pattle/src/resources/intl/localizations.dart';
import 'package:pattle/src/section/main/models/chat_message.dart';
import '../state.dart';
......@@ -36,10 +36,9 @@ class UpgradeContent extends StatelessWidget {
return RichText(
text: TextSpan(
style: DefaultTextStyle.of(context).style,
children: l(context).upgradedThisGroup(
TextSpan(
text: message.sender.name,
),
children: context.intl.chat.message.upgrade.toTextSpans(
message.sender.person,
message.sender.name,
),
),
);
......
......@@ -19,7 +19,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:matrix_sdk/matrix_sdk.dart';
import 'package:pattle/src/app.dart';
import 'package:pattle/src/resources/localizations.dart';
import 'package:pattle/src/resources/intl/localizations.dart';
import 'package:pattle/src/section/main/widgets/error.dart';
import 'package:pattle/src/section/main/widgets/chat_member_avatar.dart';
......@@ -73,7 +73,7 @@ class _CreateGroupDetailsPageState extends State<CreateGroupDetailsPage> {
},
child: Scaffold(
appBar: AppBar(
title: Text(l(context).newGroup),
title: Text(context.intl.chats.newGroup.title),
),
body: Column(
children: <Widget>[
......@@ -92,7 +92,7 @@ class _CreateGroupDetailsPageState extends State<CreateGroupDetailsPage> {
},
maxLines: 1,
decoration: InputDecoration(
labelText: l(context).groupName,
labelText: context.intl.chats.newGroup.title,
filled: true,
),
),
......@@ -100,7 +100,7 @@ class _CreateGroupDetailsPageState extends State<CreateGroupDetailsPage> {
)
],
),
Text(l(context).participants),
Text(context.intl.chats.newGroup.participants),
Expanded(child: _buildUserList(context))
],
),
......
......@@ -18,7 +18,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pattle/src/app.dart';
import 'package:pattle/src/resources/localizations.dart';
import 'package:pattle/src/resources/intl/localizations.dart';
import 'package:pattle/src/section/main/widgets/chat_member_tile.dart';
import '../../../../../matrix.dart';
......@@ -57,7 +57,7 @@ class _CreateGroupMembersPageState extends State<CreateGroupMembersPage> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(l(context).newGroup),
title: Text(context.intl.chats.newGroup.title),
),
body: Column(
children: <Widget>[
......
......@@ -19,7 +19,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/material.dart';
import 'package:mdi/mdi.dart';
import 'package:pattle/src/app.dart';
import 'package:pattle/src/resources/localizations.dart';
import 'package:pattle/src/resources/intl/localizations.dart';
import '../../../matrix.dart';
import 'bloc.dart';
......@@ -57,7 +57,7 @@ class _ChatsPageState extends State<ChatsPage> {
length: 2,
child: Scaffold(
appBar: AppBar(
title: Text(l(context).appName),
title: Text(context.intl.appName),
actions: <Widget>[
IconButton(
icon: Icon(Icons.settings),
......@@ -72,7 +72,7 @@ class _ChatsPageState extends State<ChatsPage> {
children: <Widget>[
Icon(Icons.group),
SizedBox(width: 8),
Text(l(context).personal.toUpperCase()),
Text(context.intl.chats.personal.toUpperCase()),
],
),
),
......@@ -83,7 +83,7 @@ class _ChatsPageState extends State<ChatsPage> {
children: <Widget>[
Icon(Mdi.bullhorn),
SizedBox(width: 8),
Text(l(context).public.toUpperCase()),
Text(context.intl.chats.public.toUpperCase()),
],
),
),
......
......@@ -16,7 +16,7 @@
// along with Pattle. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:pattle/src/resources/localizations.dart';
import 'package:pattle/src/resources/intl/localizations.dart';
import 'package:pattle/src/section/main/widgets/message_state.dart';
import '../subtitle.dart';
......@@ -32,7 +32,7 @@ class ImageSubtitleContent extends Subtitle {
if (Sender.necessary(context)) Sender(),
Icon(Icons.photo_camera),
Expanded(
child: Text(' ' + l(context).photo),
child: Text(' ' + context.intl.common.photo),
),
],
);
......
......@@ -17,7 +17,7 @@
import 'package:flutter/material.dart';
import 'package:matrix_sdk/matrix_sdk.dart';
import 'package:pattle/src/resources/localizations.dart';
import 'package:pattle/src/resources/intl/localizations.dart';
import 'package:pattle/src/resources/theme.dart';
import 'package:pattle/src/section/main/chats/models/chat.dart';
......@@ -27,37 +27,22 @@ class TypingContent extends StatelessWidget {
const TypingContent({Key key, @required this.chat}) : super(key: key);
List<TextSpan> _span(BuildContext context, Room room) {
if (room.isDirect) {
return l(context).typing;
if (room.isDirect || room.typingUsers.isEmpty) {
return [TextSpan(text: context.intl.chat.typing)];
}
if (room.typingUsers.length == 1) {
return l(context).isTyping(
TextSpan(
text: room.typingUsers.first.name,
),
);
}
// TODO: Use ChatMember for names
if (room.typingUsers.length == 2) {
return l(context).areTyping(
TextSpan(
text: room.typingUsers.first.name,
),
TextSpan(
text: room.typingUsers[1].name,
),
if (room.typingUsers.length == 1) {
return context.intl.chat.isTyping
.toTextSpans(room.typingUsers.first.name);
} else {
return context.intl.chat.areTyping.toTextSpans(
room.typingUsers.length > 2, // If true, shows 'and more' message
room.typingUsers.first.name,
room.typingUsers[1].name,
);
}
return l(context).andMoreAreTyping(
TextSpan(
text: room.typingUsers.first.name,
),
TextSpan(
text: room.typingUsers[1].name,
),
);
}
@override
......
......@@ -17,7 +17,7 @@
import 'package:dynamic_theme/dynamic_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pattle/src/resources/localizations.dart';
import 'package:pattle/src/resources/intl/localizations.dart';
import 'package:pattle/src/resources/theme.dart';
import 'bloc.dart';
......@@ -46,7 +46,7 @@ class _AppearancePageState extends State<AppearancePage> {
return Scaffold(
appBar: AppBar(
title: Text(l(context).appearance),
title: Text(context.intl.settings.appearanceTileTitle),
),
body: ListView(
children: <Widget>[
......@@ -57,7 +57,7 @@ class _AppearancePageState extends State<AppearancePage> {
: Icons.brightness_3,
color: redOnBackground(context),
),
title: Header(l(context).brightness),
title: Header(context.intl.settings.brightnessTileTitle),
),
RadioListTile(
groupValue: _brightness,
......@@ -65,7 +65,7 @@ class _AppearancePageState extends State<AppearancePage> {
onChanged: (brightness) {
DynamicTheme.of(context).setBrightness(brightness);
},
title: Text(l(context).light),
title: Text(context.intl.settings.brightnessTileOptionLight),
),
RadioListTile(
groupValue: _brightness,
......@@ -73,7 +73,7 @@ class _AppearancePageState extends State<AppearancePage> {
onChanged: (brightness) {
DynamicTheme.of(context).setBrightness(brightness);
},
title: Text(l(context).dark),
title: Text(context.intl.settings.brightnessTileOptionLight),
),
Divider(height: 1)
],
......
......@@ -16,6 +16,7 @@
// along with Pattle. If not, see <https://www.gnu.org/licenses/>.
import 'package:bloc/bloc.dart';
import 'package:pattle/src/section/main/models/chat_member.dart';
import '../../../matrix.dart';
......@@ -31,16 +32,22 @@ class SettingsBloc extends Bloc<SettingsEvent, SettingsState> {
SettingsBloc(this._matrix);
@override
SettingsState get initialState => SettingsInitialized();
SettingsState get initialState => SettingsInitialized(
ChatMember(
_matrix.user,
name: _matrix.user.name,
isYou: true,
),
);
@override
Stream<SettingsState> mapEventToState(SettingsEvent event) async* {
if (event is UpdateDisplayName) {
yield UpdatingDisplayName();
yield UpdatingDisplayName(state.me);
await _matrix.user.setName(event.name);
yield DisplayNameUpdated();
yield DisplayNameUpdated(state.me);
}
}
}
......@@ -18,12 +18,10 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pattle/src/resources/localizations.dart';
import 'package:pattle/src/resources/intl/localizations.dart';
import 'package:pattle/src/resources/theme.dart';
import 'package:pattle/src/section/main/settings/bloc.dart';
import '../../../matrix.dart';
class _NamePageState extends State<NamePage> {
final _textController = TextEditingController();
......@@ -31,11 +29,11 @@ class _NamePageState extends State<NamePage> {
void didChangeDependencies() {
super.didChangeDependencies();
final name = Matrix.of(context).user.name;
final me = BlocProvider.of<SettingsBloc>(context).state.me;
_textController.value = TextEditingValue(
text: name,
selection: TextSelection(baseOffset: 0, extentOffset: name.length),
text: me.name,
selection: TextSelection(baseOffset: 0, extentOffset: me.name.length),
);
}
......@@ -61,7 +59,7 @@ class _NamePageState extends State<NamePage> {
child: Scaffold(
appBar: AppBar(
title: Text(
l(context).name,
context.intl.common.name,
style: TextStyle(
color: redOnBackground(context),
),
......@@ -126,7 +124,7 @@ class _NamePageState extends State<NamePage> {
),
Expanded(
child: Text(
l(context).editNameDescription,
context.intl.settings.editNameDescription,
style: TextStyle(
color: Theme.of(context).textTheme.caption.color,
),
......
......@@ -16,12 +16,11 @@
// along with Pattle. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pattle/src/resources/localizations.dart';
import 'package:pattle/src/resources/intl/localizations.dart';
import 'package:pattle/src/resources/theme.dart';
import 'package:pattle/src/section/main/widgets/chat_member_avatar.dart';
import '../../../matrix.dart';
import '../../../util/local_user.dart';
import '../../../app.dart';
import 'bloc.dart';
......@@ -44,12 +43,9 @@ class _SettingsPageState extends State<SettingsPage> {
@override
Widget build(BuildContext context) {
final bloc = BlocProvider.of<SettingsBloc>(context);
// TODO: Use ChatMember
final me = Matrix.of(context).user;
return Scaffold(
appBar: AppBar(
title: Text(l(context).settings),
title: Text(context.intl.settings.title),
),
body: ListView(
children: <Widget>[
......@@ -64,33 +60,39 @@ class _SettingsPageState extends State<SettingsPage> {
},
child: Padding(
padding: EdgeInsets.all(16),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Hero(
tag: me.id,
child: ChatMemberAvatar(
member: me.toChatMember(),
radius: 36,
),
),
Padding(
padding: EdgeInsets.only(left: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
me.name,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
child: BlocBuilder<SettingsBloc, SettingsState>(
builder: (context, state) {
final me = state.me;
return Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Hero(
tag: me.user.id,
child: ChatMemberAvatar(
member: me,
radius: 36,
),
),
Padding(
padding: EdgeInsets.only(left: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
me.name,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
Text(me.user.id.toString())
],
),
Text(me.id.toString())
],
),
)
],
)
],
);
},
),
),
),
......@@ -98,13 +100,13 @@ class _SettingsPageState extends State<SettingsPage> {
Divider(height: 1),
ListTile(
leading: Icon(Icons.vpn_key, color: LightColors.red),
title: Text(l(context).account),
subtitle: Text(l(context).accountDescription),
title: Text(context.intl.settings.accountTileTitle),
subtitle: Text(context.intl.settings.accountTileSubtitle),
),
ListTile(
leading: Icon(Icons.landscape, color: LightColors.red),
title: Text(l(context).appearance),
subtitle: Text(l(context).appearanceDescription),
title: Text(context.intl.settings.appearanceTileTitle),
subtitle: Text(context.intl.settings.appearanceTileSubtitle),
onTap: () => Navigator.of(context).pushNamed(
Routes.settingsAppearance,
arguments: bloc,
......
......@@ -17,12 +17,9 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pattle/src/resources/localizations.dart';
import 'package:pattle/src/resources/intl/localizations.dart';
import 'package:pattle/src/resources/theme.dart';
import 'package:pattle/src/section/main/widgets/chat_member_avatar.dart';
import '../../../matrix.dart';
import '../../../util/local_user.dart';
import '../../../app.dart';
import 'bloc.dart';
......@@ -44,69 +41,72 @@ class ProfilePage extends StatefulWidget {
class _ProfilePageState extends State<ProfilePage> {
@override
Widget build(BuildContext context) {
// TODO: Use ChatMember
final me = Matrix.of(context).user;
return Scaffold(
appBar: AppBar(
title: Text(l(context).profile),
title: Text(context.intl.settings.profileTitle),
),
body: Center(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(16),
child: Stack(
overflow: Overflow.visible,
children: <Widget>[
Hero(
tag: me.id,
child: ChatMemberAvatar(
member: me.toChatMember(),
radius: 96,
),
body: BlocBuilder<SettingsBloc, SettingsState>(
builder: (context, state) {
final me = state.me;
return Center(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(16),
child: Stack(
overflow: Overflow.visible,
children: <Widget>[
Hero(
tag: me.user.id,
child: ChatMemberAvatar(
member: me,
radius: 96,
),
),
Positioned(
right: -1,
bottom: -1,
child: FloatingActionButton(
child: Icon(Icons.photo_camera),
onPressed: () {},
),
)
],
),
Positioned(
right: -1,
bottom: -1,
child: FloatingActionButton(
child: Icon(Icons.photo_camera),
onPressed: () {},
),
)
],
),
),
Expanded(
child: ListView(
children: <Widget>[
ListTile(
leading: Icon(
Icons.person,
color: redOnBackground(context),
),
title: Text(l(context).name),
subtitle: Text(me.name),
trailing: Icon(Icons.edit),
onTap: () => Navigator.pushNamed(
context,
Routes.settingsProfileName,
arguments: BlocProvider.of<SettingsBloc>(context),
),
),
Expanded(
child: ListView(
children: <Widget>[
ListTile(
leading: Icon(
Icons.person,
color: redOnBackground(context),
),
title: Text(context.intl.common.name),
subtitle: Text(me.name),
trailing: Icon(Icons.edit),
onTap: () => Navigator.pushNamed(
context,
Routes.settingsProfileName,
arguments: BlocProvider.of<SettingsBloc>(context),
),
),
ListTile(
leading: Icon(
Icons.alternate_email,
color: redOnBackground(context),
),
title: Text(context.intl.common.username),
subtitle: Text(me.user.id.toString()),
)
],
),
ListTile(
leading: Icon(
Icons.alternate_email,
color: redOnBackground(context),
),
title: Text(l(context).username),
subtitle: Text(me.id.toString()),
)
],
),
)
],
),
)
],
),
);
},
),
);
}
......