Externalize strings

Also some cleanup. Work on issue #41.
This commit is contained in:
N-Pex 2021-05-20 12:33:59 +02:00
parent 3c60ad4f14
commit a78659b206
43 changed files with 402 additions and 288 deletions

11
package-lock.json generated
View file

@ -32,6 +32,7 @@
"v-emoji-picker": "^2.3.1", "v-emoji-picker": "^2.3.1",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-clipboard2": "^0.3.1", "vue-clipboard2": "^0.3.1",
"vue-i18n": "^8.24.4",
"vue-resize": "^0.5.0", "vue-resize": "^0.5.0",
"vue-router": "^3.2.0", "vue-router": "^3.2.0",
"vue-sanitize": "^0.2.1", "vue-sanitize": "^0.2.1",
@ -13997,6 +13998,11 @@
"integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==",
"dev": true "dev": true
}, },
"node_modules/vue-i18n": {
"version": "8.24.4",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.24.4.tgz",
"integrity": "sha512-RZE94WUAGxEiBAANxQ0pptbRwDkNKNSXl3fnJslpFOxVMF6UkUtMDSuYGuW2blDrVgweIXVpethOVkYoNNT9xw=="
},
"node_modules/vue-loader": { "node_modules/vue-loader": {
"version": "15.9.6", "version": "15.9.6",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.9.6.tgz", "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.9.6.tgz",
@ -26866,6 +26872,11 @@
"integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==",
"dev": true "dev": true
}, },
"vue-i18n": {
"version": "8.24.4",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.24.4.tgz",
"integrity": "sha512-RZE94WUAGxEiBAANxQ0pptbRwDkNKNSXl3fnJslpFOxVMF6UkUtMDSuYGuW2blDrVgweIXVpethOVkYoNNT9xw=="
},
"vue-loader": { "vue-loader": {
"version": "15.9.6", "version": "15.9.6",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.9.6.tgz", "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.9.6.tgz",

View file

@ -33,6 +33,7 @@
"v-emoji-picker": "^2.3.1", "v-emoji-picker": "^2.3.1",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-clipboard2": "^0.3.1", "vue-clipboard2": "^0.3.1",
"vue-i18n": "^8.24.4",
"vue-resize": "^0.5.0", "vue-resize": "^0.5.0",
"vue-router": "^3.2.0", "vue-router": "^3.2.0",
"vue-sanitize": "^0.2.1", "vue-sanitize": "^0.2.1",

View file

@ -33,7 +33,7 @@ export default {
return this.$store.state.auth.user; return this.$store.state.auth.user;
}, },
title() { title() {
var title = config.appName; var title = this.$t(config.appName);
if (this.$matrix.notificationCount > 0) { if (this.$matrix.notificationCount > 0) {
title += " [" + this.$matrix.notificationCount + "]"; title += " [" + this.$matrix.notificationCount + "]";
} }

View file

@ -0,0 +1,173 @@
export default {
"Keanu Weblite": "Keanu Weblite",
menu: {
start_private_chat: "Private chat with this user",
reply: "Reply",
edit: "Edit",
delete: "Delete",
download: "Download",
ok: "Ok",
cancel: "Cancel",
send: "Send",
back: "BACK",
login: "Login",
logout: "Logout",
},
message: {
you: "You",
user_changed_display_name: "{user} changed display name to {displayName}",
user_changed_avatar: "{user} changed the avatar",
user_changed_room_avatar: "{user} changed the room avatar",
user_was_invited: "{user} was invited to the chat...",
user_joined: "{user} joined the chat",
user_left: "{user} left the chat",
user_said: "{user} said:",
file_prefix: "File: ",
edited: "(edited)",
download_progress: "{percentage}% downloaded",
upload_progress: "Uploaded {count}",
upload_progress_with_total: "Uploaded {count} of {total}",
user_changed_room_history: "{user} made room history {type}",
room_history_world_readable: "readable by anyone",
room_history_shared: "readable to all members in the room",
room_history_invited: "readable to members from when they were invited",
room_history_joined: "readable to members from when they joined",
user_changed_join_rules: "{user} made the room {type}",
room_joinrule_invite: "invite only",
room_joinrule_public: "public",
user_changed_room_name: "{user} changed room name to {name}",
user_changed_room_topic: "{user} changed room topic to {topic}",
unread_messages: "Unread messages",
replying_to_event: "REPLYING TO EVENT: {message}",
your_message: "Your message...",
scale_image: "Scale image",
user_is_typing: "{user} is typing",
users_are_typing: "{count} members are typing",
},
room: {
members: "no members | 1 member | {count} members",
leave: "Leave"
},
room_welcome: {
welcome: "Welcome!",
info: "Here are a few things to know about your group:",
join_public: "Anyone can join by opening this link: {link}",
join_invite: "Only people you invite can join.",
info_permissions: "You can change 'join permissions' and 'message history' at any time in the group settings.",
got_it: "Got it",
},
new_room: {
new_room: "New Group",
done: "Done",
next: "Next",
name_room: "Name group",
join_permissions: "Join permissions",
set_join_permissions: "Set Join Permissions",
join_permissions_info: "These permissions determine how people can join the group and how easily others can be invited. They can be changed anytime.",
get_link: "Get link",
add_people: "Add people",
link_copied: "Link copied!",
public_info: "Anyone with a link",
public_description: "Get a link to share",
invite_info: "Only people added",
invite_description: "Choose from a list or search by account ID",
status_creating: "Creating room",
status_avatar_total: "Uploading avatar: {count} of {total}",
status_avatar: "Uploading avatar: {count}",
},
device_list: {
title: "DEVICES",
blocked: "Blocked",
verified: "Verified",
not_verified: "Not verified",
},
login: {
title: "Login",
username: "Username",
password: "Password",
username_required: "Username is required",
password_required: "Password is required",
login: "Login"
},
profile: {
title: "My Profile",
temporary_identity: "This identity is temporary. Set a password to use it again",
set_password: "Set password",
change_name: "Change name",
change_password: "Change password",
password_old: "Old password",
password_new: "New password",
password_repeat: "Repeat new password",
display_name: "Display name",
},
join: {
title: "Welcome to {roomName}",
user_name_label: "User name",
shared_computer: "Using a shared computer",
joining_as: "You are joining as:",
join: "Join room",
join_guest: "Join as guest",
status_logging_in: "Logging in...",
status_joining: "Joining room...",
},
invite: {
title: "Add Friends",
done: "Done",
send_invites_to: "Send invites to",
status_inviting: "Inviting friend {index} of {count}",
status_error: "Failed to invite one or or more friends!",
},
leave: {
title_public: "Goodbye, {user}",
text_public: "You can always join this room again if you know the link.",
text_public_lastroom: "If you want to join this group again, you can join under a new identity. To keep {user}, {action}.",
title_invite: "Are you sure you want to leave?",
text_invite: "This group is locked. You cannot rejoin without a special permission.",
create_account: "create an account",
go_back: "Go back",
leave: "Leave"
},
purge_room: {
title: "Purge room?",
info: "This operation will close the room for all members. It cannot be undone.",
button: "Purge room"
},
room_info: {
title: "Info",
created_by: "Created by {user}",
permissions: "Permissions",
join_invite: "Room can be joined by invitation only",
join_public: "Anyone with the link can join",
link_copied: "Link copied!",
purge: "Purge room",
members: "Members",
user: "{user}",
user_you: "{user} (you)",
hide_all: "Hide",
show_all: "Show all",
my_profile: "My Profile",
identity: "You are logged in as {displayName}.",
identity_temporary: "Your identity {displayName} is temporary. You can change your name or set a password to keep it.",
view_profile: "View",
leave_room: "Leave group",
leave_room_info: "Note: This step cannot be undone. Make sure you want to logout and delete the chat forever.",
version_info: "Powered by Guardian Project. Version: {version}",
},
room_info_sheet: {
this_room: "This group",
view_details: "View details",
create_room: "Create group"
},
voice_recorder: {
swipe_to_cancel: "Swipe to cancel",
release_to_cancel: "Release to cancel",
failed_to_record: "Failed to record audio"
},
fallbacks: {
audio_file: "Audio file",
video_file: "Video file",
original_text: "<original text>",
download_name: "Download",
}
}

View file

@ -111,7 +111,7 @@
<div <div
v-if="event.getId() == readMarker && index < events.length - 1" v-if="event.getId() == readMarker && index < events.length - 1"
class="read-marker" class="read-marker"
title="Unread messages" :title="$t('message.unread_messages')"
/> />
</div> </div>
</div> </div>
@ -135,7 +135,7 @@
<v-row class="ma-0 pa-0"> <v-row class="ma-0 pa-0">
<div v-if="replyToEvent"> <div v-if="replyToEvent">
REPLYING TO EVENT: {{ replyToEvent.getContent().body }} {{$t('message.replying_to_event',{message: replyToEvent.getContent().body}) }}
</div> </div>
<!-- CONTACT IS TYPING --> <!-- CONTACT IS TYPING -->
@ -154,7 +154,7 @@
v-model="currentInput" v-model="currentInput"
no-resize no-resize
class="input-area-text" class="input-area-text"
placeholder="Your message..." :placeholder="$t('message.your_message')"
hide-details hide-details
background-color="white" background-color="white"
v-on:keydown.enter.prevent=" v-on:keydown.enter.prevent="
@ -308,7 +308,7 @@
> >
<v-switch <v-switch
v-if="currentImageInput && currentImageInput.scaled" v-if="currentImageInput && currentImageInput.scaled"
label="Scale image" :label="$('message.scale_image')"
v-model="currentImageInput.useScaled" v-model="currentImageInput.useScaled"
/> />
</div> </div>
@ -319,7 +319,7 @@
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn color="primary" text @click="cancelSendAttachment" <v-btn color="primary" text @click="cancelSendAttachment"
>Cancel</v-btn >{{$t('menu.cancel')}}</v-btn
> >
<v-btn <v-btn
color="primary" color="primary"
@ -327,7 +327,7 @@
@click="sendAttachment" @click="sendAttachment"
v-if="currentSendShowSendButton" v-if="currentSendShowSendButton"
:disabled="currentSendOperation != null" :disabled="currentSendOperation != null"
>Send</v-btn >{{$t('menu.send')}}</v-btn
> >
</v-card-actions> </v-card-actions>
</v-card> </v-card>
@ -336,7 +336,6 @@
<MessageOperationsBottomSheet <MessageOperationsBottomSheet
ref="messageOperationsSheet" ref="messageOperationsSheet"
xv-show="showEmojiPicker"
> >
<MessageOperationsPicker <MessageOperationsPicker
v-on:close="showEmojiPicker = false" v-on:close="showEmojiPicker = false"
@ -362,23 +361,6 @@
v-on:selectSticker="sendSticker" v-on:selectSticker="sendSticker"
/> />
<!-- "NOT ALLOWED FOR GUEST ACCOUNTS" dialog -->
<v-dialog v-model="showNotAllowedForGuests" class="ma-0 pa-0" width="50%">
<v-card>
<v-card-title>You are logged in as a guest</v-card-title>
<v-card-text>
<div>Unfortunately guests are not allowed to upload files.</div>
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="primary" text @click="showNotAllowedForGuests = false"
>Ok</v-btn
>
</v-card-actions>
</v-card>
</v-dialog>
<!-- Loading indicator --> <!-- Loading indicator -->
<v-container <v-container
fluid fluid
@ -555,9 +537,6 @@ export default {
*/ */
showScrollToEnd: false, showScrollToEnd: false,
/** Shows a dialog with info about an operation being disallowed for guests */
showNotAllowedForGuests: false,
/** A timer for read receipts. */ /** A timer for read receipts. */
rrTimer: null, rrTimer: null,
@ -641,9 +620,9 @@ export default {
typingMembersString() { typingMembersString() {
const count = this.typingMembers.length; const count = this.typingMembers.length;
if (count > 1) { if (count > 1) {
return "" + count + " members are typing"; return this.$t('message.users_are_typing',{count: count});
} else if (count > 0) { } else if (count > 0) {
return this.typingMembers[0].name + " is typing"; return this.$t('message.user_is_typing',{user: this.typingMembers[0].name});
} else { } else {
return ""; return "";
} }
@ -776,7 +755,6 @@ export default {
this.timelineWindow this.timelineWindow
.load(initialEventId, 20) .load(initialEventId, 20)
.then(() => { .then(() => {
console.log("This is", self);
self.events = self.timelineWindow.getEvents(); self.events = self.timelineWindow.getEvents();
const getMoreIfNeeded = function _getMoreIfNeeded() { const getMoreIfNeeded = function _getMoreIfNeeded() {
@ -1046,7 +1024,7 @@ export default {
this.restartRRTimer(); this.restartRRTimer();
}, },
onEvent(event) { onEvent(event) {
console.log("OnEvent", JSON.stringify(event)); //console.log("OnEvent", JSON.stringify(event));
if (event.getRoomId() !== this.roomId) { if (event.getRoomId() !== this.roomId) {
return; // Not for this room return; // Not for this room
} }
@ -1083,7 +1061,7 @@ export default {
this.typingMembers.splice(index, 1); this.typingMembers.splice(index, 1);
} }
} }
console.log("Typing: ", this.typingMembers); //console.log("Typing: ", this.typingMembers);
}, },
sendCurrentTextMessage() { sendCurrentTextMessage() {
@ -1119,12 +1097,6 @@ export default {
* Show attachment picker to select file * Show attachment picker to select file
*/ */
showAttachmentPicker() { showAttachmentPicker() {
// Guests not currently allowed to send attachments (=actually upload them)
// See https://matrix.org/docs/spec/client_server/r0.2.0#guest-access
// if (this.$matrix.currentUser && this.$matrix.currentUser.is_guest) {
// this.showNotAllowedForGuests = true;
// return;
// }
this.$refs.attachment.click(); this.$refs.attachment.click();
}, },
@ -1202,9 +1174,9 @@ export default {
onUploadProgress(p) { onUploadProgress(p) {
if (p.total) { if (p.total) {
this.currentSendProgress = this.currentSendProgress =
"Uploaded " + (p.loaded || 0) + " of " + p.total; this.$t('message.upload_progress_with_total',{count: (p.loaded || 0), total: p.total});
} else { } else {
this.currentSendProgress = "Uploaded " + (p.loaded || 0); this.currentSendProgress = this.$t('message.upload_progress',{count: (p.loaded || 0)});
} }
}, },
@ -1390,7 +1362,7 @@ export default {
const link = document.createElement("a"); const link = document.createElement("a");
link.href = url; link.href = url;
link.target = "_blank"; link.target = "_blank";
link.download = event.getContent().body || "Download"; link.download = event.getContent().body || this.$t('fallbacks.download_name');
link.click(); link.click();
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
}) })
@ -1436,10 +1408,6 @@ export default {
showContextMenuForEvent(e) { showContextMenuForEvent(e) {
const event = e.event; const event = e.event;
const ref = this.$refs[event.getId()];
if (ref) {
console.log("Got the ref", ref);
}
this.selectedEvent = event; this.selectedEvent = event;
this.updateRecentEmojis(); this.updateRecentEmojis();
this.showContextMenu = true; this.showContextMenu = true;

View file

@ -13,10 +13,10 @@
<v-col class="ma-0 pa-0 flex-shrink-1 flex-nowrap" style="overflow:hidden;cursor:pointer" @click.stop="onHeaderClicked"> <v-col class="ma-0 pa-0 flex-shrink-1 flex-nowrap" style="overflow:hidden;cursor:pointer" @click.stop="onHeaderClicked">
<div class="d-flex flex-nowrap room-name-inline">{{ room.summary.info.title }} <!--<v-icon>expand_more</v-icon>--></div> <div class="d-flex flex-nowrap room-name-inline">{{ room.summary.info.title }} <!--<v-icon>expand_more</v-icon>--></div>
<div class="num-members">{{ memberCount }}{{ memberCount > 1 ? " members" : " member" }}</div> <div class="num-members">{{ $tc('room.members', memberCount) }}</div>
</v-col> </v-col>
<v-col cols="auto" class="text-end ma-0 pa-0"> <v-col cols="auto" class="text-end ma-0 pa-0">
<v-btn text class="leave-button" @click.stop="leaveRoom">Leave</v-btn> <v-btn text class="leave-button" @click.stop="leaveRoom">{{$t('room.leave')}}</v-btn>
</v-col> </v-col>
</v-row> </v-row>

View file

@ -2,7 +2,7 @@
<div class="create-room"> <div class="create-room">
<div> <div>
<v-container fluid> <v-container fluid>
<div class="room-name">New Group</div> <div class="room-name">{{$t('new_room.new_room')}}</div>
<v-btn <v-btn
text text
class="header-button-left" class="header-button-left"
@ -11,7 +11,7 @@
:disabled="step > steps.NAME_SET" :disabled="step > steps.NAME_SET"
> >
<v-icon>arrow_back</v-icon> <v-icon>arrow_back</v-icon>
<span>BACK</span> <span>{{$t('menu.back')}}</span>
</v-btn> </v-btn>
<v-btn <v-btn
text text
@ -21,7 +21,7 @@
class="header-button-right" class="header-button-right"
@click.stop="next" @click.stop="next"
> >
<span>{{ step == steps.CREATED ? "Done" : "Next" }}</span> <span>{{ step == steps.CREATED ? $t('new_room.done') : $t('new_room.next') }}</span>
</v-btn> </v-btn>
</v-container> </v-container>
</div> </div>
@ -37,7 +37,7 @@
<v-col> <v-col>
<v-text-field <v-text-field
v-model="roomName" v-model="roomName"
label="Name group" :label="$t('new_room.name_room')"
color="black" color="black"
background-color="white" background-color="white"
v-on:keyup.enter="$refs.topic.focus()" v-on:keyup.enter="$refs.topic.focus()"
@ -49,12 +49,9 @@
<v-fade-transition> <v-fade-transition>
<div class="section ma-3" flat v-if="step > steps.INITIAL"> <div class="section ma-3" flat v-if="step > steps.INITIAL">
<div class="h4 text-left">Join permissions</div> <div class="h4 text-left">{{$t('new_room.join_permissions')}}</div>
<div class="h2 text-left">Set Join Permissions</div> <div class="h2 text-left">{{$t('new_room.set_join_permissions')}}</div>
<div> <div>{{$t('new_room.join_permissions_info')}}</div>
These permissions determine how people can join the group and how
easily others can be invited. They can be changed anytime.
</div>
<v-select <v-select
:disabled="step >= steps.CREATING" :disabled="step >= steps.CREATING"
:items="joinRules" :items="joinRules"
@ -65,7 +62,7 @@
<template v-slot:selection="{ item }"> <template v-slot:selection="{ item }">
{{ item.text }} {{ item.text }}
</template> </template>
<template v-slot:item="{ active, item, attrs, on }"> <template v-slot:item="{ item, attrs, on }">
<v-list-item v-on="on" v-bind="attrs" #default="{ active }"> <v-list-item v-on="on" v-bind="attrs" #default="{ active }">
<v-list-item-avatar> <v-list-item-avatar>
<v-icon class="grey lighten-1" dark>{{ item.icon }}</v-icon> <v-icon class="grey lighten-1" dark>{{ item.icon }}</v-icon>
@ -105,7 +102,7 @@
depressed depressed
class="outlined-button" class="outlined-button"
@click.stop="getPublicLink" @click.stop="getPublicLink"
><v-icon class="mr-2">link</v-icon>Get link</v-btn ><v-icon class="mr-2">link</v-icon>{{$t('new_room.get_link')}}</v-btn
> >
<v-btn <v-btn
v-else-if="joinRule == 'invite'" v-else-if="joinRule == 'invite'"
@ -113,10 +110,10 @@
depressed depressed
class="outlined-button" class="outlined-button"
@click.stop="addPeople" @click.stop="addPeople"
><v-icon class="mr-2">person_add</v-icon>Add people</v-btn ><v-icon class="mr-2">person_add</v-icon>{{$t('new_room.add_people')}}</v-btn
> >
<div v-if="publicRoomLinkCopied" class="link-copied">Link copied!</div> <div v-if="publicRoomLinkCopied" class="link-copied">{{$t('new_room.link_copied')}}</div>
<div v-if="status">{{ status }}</div> <div v-if="status">{{ status }}</div>
</div> </div>
@ -158,15 +155,15 @@ export default {
joinRules: [ joinRules: [
{ {
id: "public", id: "public",
text: "Anyone with a link", text: this.$t('new_room.public_info'),
icon: "link", icon: "link",
descr: "Get a link to share", descr: this.$t('new_room.public_description'),
}, },
{ {
id: "invite", id: "invite",
text: "Only people added", text: this.$t('new_room.invite_info'),
icon: "person_add", icon: "person_add",
descr: "Choose from a list or search by account ID", descr: this.$t('new_room.invite_description'),
}, },
], ],
publicRoomLink: null, publicRoomLink: null,
@ -265,7 +262,7 @@ export default {
createRoom() { createRoom() {
this.step = steps.CREATING; this.step = steps.CREATING;
var roomId; var roomId;
this.status = "Creating room"; this.status = this.$t('new_room.status_creating');
var createRoomOptions = {}; var createRoomOptions = {};
if (this.joinRule == "public") { if (this.joinRule == "public") {
createRoomOptions = { createRoomOptions = {
@ -325,10 +322,9 @@ export default {
this.roomAvatarFile, this.roomAvatarFile,
function (p) { function (p) {
if (p.total) { if (p.total) {
self.status = self.status = this.$t('new_room.status_avatar_total', {count: (p.loaded || 0), total: p.total});
"Uploading avatar: " + (p.loaded || 0) + " of " + p.total;
} else { } else {
self.status = "Uploading avatar: " + (p.loaded || 0); self.status = this.$t('new_room.status_avatar', {count: (p.loaded || 0)});
} }
} }
); );

View file

@ -1,12 +1,12 @@
<template> <template>
<div class="created-room-welcome-header"> <div class="created-room-welcome-header">
<div class="h4">Welcome!</div> <div class="h4">{{$t('room_welcome.welcome')}}</div>
<div class="mt-2">Here are a few things to know about your group:</div> <div class="mt-2">{{$t('room_welcome.info')}}</div>
<div class="mt-2" v-if="roomJoinRule == 'public'">Anyone can join by opening this link: {{ publicRoomLink }}</div> <div class="mt-2" v-if="roomJoinRule == 'public'">{{$t('room_welcome.join_public', {link: publicRoomLink}) }}</div>
<div class="mt-2" v-else-if="roomJoinRule == 'invite'">Only people you invite can join.</div> <div class="mt-2" v-else-if="roomJoinRule == 'invite'">{{$t('room_welcome.join_invite')}}</div>
<div class="mt-2">You can change 'join permissions' and 'message history' at any time in the group settings.</div> <div class="mt-2">{{$t('room_welcome.info_permissions')}}</div>
<div class="text-right"> <div class="text-right">
<v-btn text @click.stop="$emit('close')">Got it</v-btn> <v-btn text @click.stop="$emit('close')">{{$t('room_welcome.got_it')}}</v-btn>
</div> </div>
</div> </div>
</template> </template>

View file

@ -1,6 +1,6 @@
<template> <template>
<v-list dense @click.native.stop="nullEvent"> <v-list dense @click.native.stop="nullEvent">
<v-subheader>DEVICES</v-subheader> <v-subheader>{{$t('device_list.title')}}</v-subheader>
<v-list-item-group color="primary"> <v-list-item-group color="primary">
<v-list-item <v-list-item
v-for="device in devices" v-for="device in devices"
@ -84,11 +84,11 @@ export default {
verificationStatus(device) { verificationStatus(device) {
if (device.isBlocked()) { if (device.isBlocked()) {
return "Blocked"; return this.$t('device_list.blocked');
} else if (device.isVerified()) { } else if (device.isVerified()) {
return "Verified"; return this.$t('device_list.verified');
} else { } else {
return "Not verified"; return this.$t('device_list.not_verified');
} }
}, },

View file

@ -1,7 +1,7 @@
<template> <template>
<div class="pa-4"> <div class="pa-4">
<RoomList showInvites /> <RoomList showInvites />
<v-btn block depressed class="outlined-button" @click.stop="logout">Logout</v-btn> <v-btn block depressed class="outlined-button" @click.stop="logout">{{$t('menu.logout')}}</v-btn>
<!-- Loading indicator --> <!-- Loading indicator -->
<v-container <v-container

View file

@ -1,14 +1,14 @@
<template> <template>
<div class="d-flex flex-column pa-4" style="overflow: hidden"> <div class="d-flex flex-column pa-4" style="overflow: hidden">
<div class="flex-grow-0 flex-shrink-0"> <div class="flex-grow-0 flex-shrink-0">
<div class="room-name">Add Friends</div> <div class="room-name">{{$t('invite.title')}}</div>
<v-btn <v-btn
:loading="loading" :loading="loading"
text text
class="header-button-right" class="header-button-right"
@click.stop="done" @click.stop="done"
> >
<span>Done</span> <span>{{$t('invite.done')}}</span>
</v-btn> </v-btn>
</div> </div>
@ -16,7 +16,7 @@
class="flex-grow-0 flex-shrink-0" class="flex-grow-0 flex-shrink-0"
style="min-height: 100px; max-height: 30vh" style="min-height: 100px; max-height: 30vh"
> >
<div class="h4">Send invites to</div> <div class="h4">{{$t('invite.send_invites_to')}}</div>
<div>{{ status }}</div> <div>{{ status }}</div>
<v-chip-group active-class="primary--text" column> <v-chip-group active-class="primary--text" column>
<v-chip <v-chip
@ -102,14 +102,14 @@ export default {
this.loading = false; this.loading = false;
if (this.selectedMembers.length > 0) { if (this.selectedMembers.length > 0) {
// Error. // Error.
this.status = "Failed to invite one or or more friends!"; this.status = this.$t('invite.status_error');
} else { } else {
this.status = ""; this.status = "";
this.close(); this.close();
} }
return; return;
} }
this.status = `Inviting friend ${index + 1} of ${memberArray.length}`; this.status = this.$t('invite.status_error', {index: index + 1, count: memberArray.length});
const member = memberArray[index]; const member = memberArray[index];
// Is this userId already a member of this room? In that case don't send an invite. // Is this userId already a member of this room? In that case don't send an invite.

View file

@ -8,7 +8,7 @@
@click.stop="handleLogin" @click.stop="handleLogin"
:loading="loading" :loading="loading"
v-if="!currentUser" v-if="!currentUser"
>Login</v-btn >{{$t('menu.login')}}</v-btn
> >
<v-avatar class="join-avatar"> <v-avatar class="join-avatar">
@ -17,7 +17,7 @@
roomName.substring(0, 1).toUpperCase() roomName.substring(0, 1).toUpperCase()
}}</span> }}</span>
</v-avatar> </v-avatar>
<div class="join-title">Welcome to {{ roomName }}</div> <div class="join-title">{{$t('join.title', {roomName: roomName})}}</div>
<div class="join-message"> <div class="join-message">
<!-- Join the group chat in a web browser or with the Keanu app. --> <!-- Join the group chat in a web browser or with the Keanu app. -->
</div> </div>
@ -33,7 +33,7 @@
ref="avatar" ref="avatar"
:items="availableAvatars" :items="availableAvatars"
cache-items cache-items
label="User name" :label="$t('join.user_name_label')"
outlined outlined
dense dense
@change="selectAvatar" @change="selectAvatar"
@ -60,12 +60,12 @@
<div class="ml-2">{{ data.item.name }}</div> <div class="ml-2">{{ data.item.name }}</div>
</template> </template>
</v-select> </v-select>
<v-switch v-model="sharedComputer" label="Using a shared computer" /> <v-switch v-model="sharedComputer" :label="$t('join.shared_computer')" />
</v-col> </v-col>
</v-row> </v-row>
<v-row v-else> <v-row v-else>
<v-col> <v-col>
You are joining as: {{$t('join.joining_as')}}
<div style="display: inline-block"> <div style="display: inline-block">
<v-avatar color="#e0e0e0" style=""> <v-avatar color="#e0e0e0" style="">
<v-img v-if="userAvatar" :src="userAvatar" /> <v-img v-if="userAvatar" :src="userAvatar" />
@ -97,7 +97,7 @@
@click.stop="handleJoin" @click.stop="handleJoin"
:loading="loading" :loading="loading"
v-if="!currentUser" v-if="!currentUser"
>Join as guest</v-btn >{{$t('join.join_guest')}}</v-btn
> >
<v-btn <v-btn
class="btn-dark" class="btn-dark"
@ -106,7 +106,7 @@
@click.stop="handleJoin" @click.stop="handleJoin"
:loading="loading" :loading="loading"
v-else v-else
>Join room</v-btn >{{$t('join.join')}}</v-btn
> >
<!-- <div class="join-privacy"> <!-- <div class="join-privacy">
@ -325,7 +325,7 @@ export default {
handleJoin() { handleJoin() {
this.loading = true; this.loading = true;
this.loadingMessage = "Logging in..."; this.loadingMessage = this.$t('join.status_logging_in');
const hasUser = this.currentUser ? true : false; const hasUser = this.currentUser ? true : false;
var setProfileData = false; var setProfileData = false;
return this.getLoginPromise() return this.getLoginPromise()
@ -374,7 +374,7 @@ export default {
.then( .then(
function (ignoreduser) { function (ignoreduser) {
console.log("Join: joining room"); console.log("Join: joining room");
this.loadingMessage = "Joining room..."; this.loadingMessage = this.$t('join.status_joining');
return this.$matrix.matrixClient.joinRoom(this.roomId); return this.$matrix.matrixClient.joinRoom(this.roomId);
}.bind(this) }.bind(this)
) )

View file

@ -4,26 +4,27 @@
<template v-if="roomJoinRule == 'public'"> <template v-if="roomJoinRule == 'public'">
<h1>👋</h1> <h1>👋</h1>
<h2 class="dialog-title"> <h2 class="dialog-title">
Goodbye, {{ $matrix.currentUserDisplayName }}. {{$t('leave.title_public',{user: $matrix.currentUserDisplayName})}}
</h2> </h2>
<div <div
v-if="$matrix.currentUser.is_guest && lastRoom" v-if="$matrix.currentUser.is_guest && lastRoom"
class="dialog-text" class="dialog-text"
> >
If you want to join this group again, you can join under a new <i18n path="leave.text_public_lastroom" tag="p">
identity. To keep {{ $matrix.currentUserDisplayName }}, <template v-slot:user>
<a @click.prevent="viewProfile">create an account</a>. <span>{{ $matrix.currentUserDisplayName }}</span>
</div> </template>
<div v-else class="dialog-text"> <template v-slot:action>
You can always join this room again if you know the link. <a @click.prevent="viewProfile">{{ $t('leave.create_account') }}</a>
</template>
</i18n>
</div> </div>
<div v-else class="dialog-text">{{$t('leave.text_public')}}</div>
</template> </template>
<template v-else> <template v-else>
<v-icon color="black" size="30">lock</v-icon> <v-icon color="black" size="30">lock</v-icon>
<h2 class="dialog-title">Are you sure you want to leave?</h2> <h2 class="dialog-title">{{$t('leave.title_invite',{user: $matrix.currentUserDisplayName})}}</h2>
<div class="dialog-text"> <div class="dialog-text">{{$t('leave.text_invite')}}</div>
This group is locked. You cannot rejoin without a special permission.
</div>
</template> </template>
<v-container fluid> <v-container fluid>
<v-row cols="12"> <v-row cols="12">
@ -34,7 +35,7 @@
block block
class="text-button" class="text-button"
@click="showDialog = false" @click="showDialog = false"
>Go back</v-btn >{{$t('leave.go_back')}}</v-btn
> >
</v-col> </v-col>
<v-col cols="6" align="center"> <v-col cols="6" align="center">
@ -44,7 +45,7 @@
block block
class="filled-button" class="filled-button"
@click.stop="onLeaveRoom()" @click.stop="onLeaveRoom()"
>Leave</v-btn >{{$t('leave.leave')}}</v-btn
> >
</v-col> </v-col>
</v-row> </v-row>

View file

@ -5,15 +5,15 @@
</v-btn> </v-btn>
<div color="rgba(255,255,255,0.1)" class="text-center"> <div color="rgba(255,255,255,0.1)" class="text-center">
<div class="h2">Login</div> <div class="h2">{{$t('login.title')}}</div>
<v-form v-model="isValid"> <v-form v-model="isValid">
<v-text-field <v-text-field
v-model="user.user_id" v-model="user.user_id"
label="Username" :label="$t('login.username')"
color="black" color="black"
background-color="white" background-color="white"
outlined outlined
:rules="[(v) => !!v || 'Username is required']" :rules="[(v) => !!v || $t('login.username_required')]"
:error="userErrorMessage != null" :error="userErrorMessage != null"
:error-messages="userErrorMessage" :error-messages="userErrorMessage"
required required
@ -22,12 +22,12 @@
<v-text-field <v-text-field
ref="password" ref="password"
v-model="user.password" v-model="user.password"
label="Password" :label="$t('login.password')"
color="black" color="black"
background-color="white" background-color="white"
outlined outlined
type="password" type="password"
:rules="[(v) => !!v || 'Password is required']" :rules="[(v) => !!v || $t('login.password_required')]"
:error="passErrorMessage != null" :error="passErrorMessage != null"
:error-messages="passErrorMessage" :error-messages="passErrorMessage"
required required
@ -40,7 +40,7 @@
block block
@click.stop="handleLogin" @click.stop="handleLogin"
:loading="loading" :loading="loading"
>Login</v-btn >{{$t('login.login')}}</v-btn
> >
</v-form> </v-form>
</div> </div>

View file

@ -2,7 +2,7 @@
<div v-if="user" class="profile"> <div v-if="user" class="profile">
<div class="chat-header"> <div class="chat-header">
<v-container fluid> <v-container fluid>
<div class="room-name">My Profile</div> <div class="room-name">{{$t('profile.title')}}</div>
<v-btn <v-btn
text text
class="header-button-right" class="header-button-right"
@ -29,31 +29,29 @@
<v-col class="flex-shrink-1 flex-grow-1"> <v-col class="flex-shrink-1 flex-grow-1">
<div class="h1">{{ displayName }}</div> <div class="h1">{{ displayName }}</div>
<div class="text-center">{{ $matrix.currentUser.user_id }}</div> <div class="text-center">{{ $matrix.currentUser.user_id }}</div>
<div v-if="$matrix.currentUser.is_guest"> <div v-if="$matrix.currentUser.is_guest">{{$t('profile.temporary_identity')}}</div>
This identity is temporary. Set a password to use it again. <v-btn depressed block class="outlined-button" @click.stop="logout">{{$t('menu.logout')}}</v-btn>
</div>
<v-btn depressed block class="outlined-button" @click.stop="logout">Logout</v-btn>
</v-col> </v-col>
</v-row> </v-row>
</v-container> </v-container>
<div class="action" @click="showEditPasswordDialog = true"><v-icon>lock</v-icon><span>Set password</span></div> <div class="action" @click="showEditPasswordDialog = true"><v-icon>lock</v-icon><span>{{$t('profile.set_password')}}</span></div>
<div class="action" @click="editValue = displayName;showEditDisplaynameDialog = true"><v-icon>edit</v-icon><span>Change name</span></div> <div class="action" @click="editValue = displayName;showEditDisplaynameDialog = true"><v-icon>edit</v-icon><span>{{$t('profile.change_name')}}</span></div>
<!-- edit password dialog --> <!-- edit password dialog -->
<v-dialog v-model="showEditPasswordDialog" class="ma-0 pa-0" width="50%"> <v-dialog v-model="showEditPasswordDialog" class="ma-0 pa-0" width="50%">
<v-card :disabled="settingPassword"> <v-card :disabled="settingPassword">
<v-card-title>Change password</v-card-title> <v-card-title>{{$t('profile.change_password')}}</v-card-title>
<v-card-text> <v-card-text>
<v-text-field v-if="!$matrix.currentUser.is_guest" v-model="password" label="Old password" type="password" /> <v-text-field v-if="!$matrix.currentUser.is_guest" v-model="password" :label="$t('profile.password_old')" type="password" />
<v-text-field v-model="newPassword1" label="New password" type="password" /> <v-text-field v-model="newPassword1" :label="$t('profile.password_new')" type="password" />
<v-text-field v-model="newPassword2" label="Repeat new password" type="password" /> <v-text-field v-model="newPassword2" :label="$t('profile.password_repeat')" type="password" />
<div class="red--text" v-if="passwordErrorMessage">{{ passwordErrorMessage }}</div> <div class="red--text" v-if="passwordErrorMessage">{{ passwordErrorMessage }}</div>
</v-card-text> </v-card-text>
<v-divider></v-divider> <v-divider></v-divider>
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn text @click="closeEditPasswordDialog">Cancel</v-btn> <v-btn text @click="closeEditPasswordDialog">{{$t('menu.cancel')}}</v-btn>
<v-btn <v-btn
:disabled="!passwordsMatch" :disabled="!passwordsMatch"
color="primary" color="primary"
@ -61,7 +59,7 @@
@click=" @click="
setPassword($matrix.currentUser.is_guest ? $matrix.currentUser.password : password, newPassword1); setPassword($matrix.currentUser.is_guest ? $matrix.currentUser.password : password, newPassword1);
" "
>Ok</v-btn >{{$t('menu.ok')}}</v-btn
> >
</v-card-actions> </v-card-actions>
</v-card> </v-card>
@ -70,14 +68,14 @@
<!-- edit display name dialog --> <!-- edit display name dialog -->
<v-dialog v-model="showEditDisplaynameDialog" class="ma-0 pa-0" width="50%"> <v-dialog v-model="showEditDisplaynameDialog" class="ma-0 pa-0" width="50%">
<v-card> <v-card>
<v-card-title>Display name</v-card-title> <v-card-title>{{$t('profile.display_name')}}</v-card-title>
<v-card-text> <v-card-text>
<v-text-field v-model="editValue" /> <v-text-field v-model="editValue" />
</v-card-text> </v-card-text>
<v-divider></v-divider> <v-divider></v-divider>
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn text @click="showEditDisplaynameDialog = false">Cancel</v-btn> <v-btn text @click="showEditDisplaynameDialog = false">{{$t('menu.cancel')}}</v-btn>
<v-btn <v-btn
color="primary" color="primary"
text text
@ -85,7 +83,7 @@
setDisplayName(editValue); setDisplayName(editValue);
showEditDisplaynameDialog = false; showEditDisplaynameDialog = false;
" "
>Ok</v-btn >{{$t('menu.ok')}}</v-btn
> >
</v-card-actions> </v-card-actions>
</v-card> </v-card>

View file

@ -3,10 +3,9 @@
<div class="dialog-content text-center"> <div class="dialog-content text-center">
<template> <template>
<v-icon color="black" size="30">lock</v-icon> <v-icon color="black" size="30">lock</v-icon>
<h2 class="dialog-title">Purge room?</h2> <h2 class="dialog-title">{{$t('purge_room.title')}}</h2>
<div class="dialog-text"> <div class="dialog-text">
This operation will close the room for all members. It cannot be {{$t('purge_room.info')}}
undone.
</div> </div>
</template> </template>
<v-container fluid> <v-container fluid>
@ -18,7 +17,7 @@
block block
class="text-button" class="text-button"
@click="showDialog = false" @click="showDialog = false"
>Cancel</v-btn >{{$t('menu.cancel')}}</v-btn
> >
</v-col> </v-col>
<v-col cols="6" align="center"> <v-col cols="6" align="center">
@ -28,7 +27,7 @@
block block
class="filled-button" class="filled-button"
@click.stop="onPurgeRoom()" @click.stop="onPurgeRoom()"
>Purge room</v-btn >{{$t('purge_room.button')}}</v-btn
> >
</v-col> </v-col>
</v-row> </v-row>

View file

@ -2,7 +2,7 @@
<div v-if="room" class="room-info"> <div v-if="room" class="room-info">
<div class="chat-header"> <div class="chat-header">
<v-container fluid> <v-container fluid>
<div class="room-name">Info</div> <div class="room-name">{{ $t("room_info.title") }}</div>
<v-btn <v-btn
text text
class="header-button-left" class="header-button-left"
@ -10,7 +10,7 @@
@click.stop="$navigation.pop" @click.stop="$navigation.pop"
> >
<v-icon>arrow_back</v-icon> <v-icon>arrow_back</v-icon>
<span>BACK</span> <span>{{ $t("menu.back") }}</span>
</v-btn> </v-btn>
</v-container> </v-container>
</div> </div>
@ -25,7 +25,9 @@
</v-avatar> </v-avatar>
<div class="h1">{{ roomName }}</div> <div class="h1">{{ roomName }}</div>
<div class="h3">{{ roomTopic }}</div> <div class="h3">{{ roomTopic }}</div>
<div class="small">Created by {{ creator }}</div> <div class="small">
{{ $t("room_info.created_by", { user: creator }) }}
</div>
<v-expand-transition> <v-expand-transition>
<canvas <canvas
v-show="publicRoomLink" v-show="publicRoomLink"
@ -38,18 +40,15 @@
</v-card> </v-card>
<v-card class="account ma-3" flat> <v-card class="account ma-3" flat>
<v-card-title class="h2">Permissions</v-card-title> <v-card-title class="h2">{{ $t("room_info.permissions") }})</v-card-title>
<v-card-text> <v-card-text>
<v-radio-group <v-radio-group
v-model="roomJoinRule" v-model="roomJoinRule"
v-if="roomJoinRule" v-if="roomJoinRule"
:disabled="!userCanChangeJoinRule || updatingJoinRule" :disabled="!userCanChangeJoinRule || updatingJoinRule"
> >
<v-radio <v-radio :label="$t('room_info.join_invite')" :value="'invite'" />
label="Room can be joined by invitation only" <v-radio :label="$t('room_info.join_public')" :value="'public'">
:value="'invite'"
/>
<v-radio label="Anyone with the link can join" :value="'public'">
</v-radio> </v-radio>
<v-text-field <v-text-field
v-if="publicRoomLink" v-if="publicRoomLink"
@ -60,7 +59,9 @@
type="text" type="text"
@click:append="copyRoomLink" @click:append="copyRoomLink"
></v-text-field> ></v-text-field>
<div v-if="publicRoomLinkCopied" class="link-copied">Link copied!</div> <div v-if="publicRoomLinkCopied" class="link-copied">
{{ $t("room_info.link_copied") }}
</div>
</v-radio-group> </v-radio-group>
<v-btn <v-btn
@ -70,7 +71,7 @@
block block
class="filled-button" class="filled-button"
@click.stop="showPurgeConfirmation = true" @click.stop="showPurgeConfirmation = true"
>Purge room</v-btn >{{ $("room_info.purge") }}</v-btn
> >
<!-- <div v-if="anyoneCanJoin"> <!-- <div v-if="anyoneCanJoin">
<div>Anyone with a link can join.</div> <div>Anyone with a link can join.</div>
@ -88,7 +89,7 @@
<v-card class="members ma-3" flat> <v-card class="members ma-3" flat>
<v-card-title class="h2" <v-card-title class="h2"
>Members<v-spacer></v-spacer> >{{ $t("room_info.members") }}<v-spacer></v-spacer>
<div>{{ memberCount }}</div></v-card-title <div>{{ memberCount }}</div></v-card-title
> >
<v-card-text> <v-card-text>
@ -105,37 +106,52 @@
member.name.substring(0, 1).toUpperCase() member.name.substring(0, 1).toUpperCase()
}}</span> }}</span>
</v-avatar> </v-avatar>
{{ member.user ? member.user.displayName : member.name {{
}}{{ member.userId == $matrix.currentUserId ? " (you)" : "" }} member.userId == $matrix.currentUserId
? $t("room_info.user_you", {
user: member.user ? member.user.displayName : member.name,
})
: $t("room_info.user", {
user: member.user ? member.user.displayName : member.name,
})
}}
<DeviceList <DeviceList
v-if="expandedMembers.includes(member)" v-if="expandedMembers.includes(member)"
:member="member" :member="member"
/> />
</div> </div>
<div class="show-all" @click="showAllMembers = !showAllMembers"> <div class="show-all" @click="showAllMembers = !showAllMembers">
{{ showAllMembers ? "Hide" : "Show all" }} {{
showAllMembers ? $t("room_info.hide_all") : $t("room_info.show_all")
}}
</div> </div>
</v-card-text> </v-card-text>
</v-card> </v-card>
<v-card class="account ma-3" flat> <v-card class="account ma-3" flat>
<v-card-title class="h2">My Profile</v-card-title> <v-card-title class="h2">{{ $t("room_info.my_profile") }}</v-card-title>
<v-card-text> <v-card-text>
<div> <div>
<div v-if="$matrix.currentUser.is_guest"> <div v-if="$matrix.currentUser.is_guest">
Your identity <b>{{ displayName }}</b> is temporary. You can change <i18n path="room_info.identity_temporary" tag="span">
your name or set a password to keep it. <template v-slot:displayName>
<b>{{ displayName }}</b>
</template>
</i18n>
</div> </div>
<div v-else> <div v-else>
Your are logged in as <b>{{ displayName }}</b <i18n path="room_info.identity" tag="span">
>. <template v-slot:displayName>
<b>{{ displayName }}</b>
</template>
</i18n>
</div> </div>
<v-btn <v-btn
depressed depressed
block block
class="outlined-button" class="outlined-button"
@click.stop="viewProfile" @click.stop="viewProfile"
>View</v-btn >{{$t('room_info.view_profile')}}</v-btn
> >
</div> </div>
</v-card-text> </v-card-text>
@ -149,18 +165,13 @@
block block
class="filled-button" class="filled-button"
@click.stop="showLeaveConfirmation = true" @click.stop="showLeaveConfirmation = true"
>Leave group</v-btn >{{$t('room_info.leave_room')}}</v-btn
> >
<div> <div>{{$t('room_info.leave_room_info')}}</div>
Note: This step cannot be undone. Make sure you want to logout and
delete the chat forever.
</div>
</v-card-text> </v-card-text>
</v-card> </v-card>
<div class="build-version"> <div class="build-version">{{$t('room_info.version_info',{version: buildVersion})}}</div>
Powered by Guardian Project. Version: {{ buildVersion }}
</div>
<LeaveRoomDialog <LeaveRoomDialog
:show="showLeaveConfirmation" :show="showLeaveConfirmation"
@ -173,7 +184,6 @@
:room="room" :room="room"
@close="showPurgeConfirmation = false" @close="showPurgeConfirmation = false"
/> />
</div> </div>
</template> </template>
@ -340,7 +350,8 @@ export default {
setInterval(() => { setInterval(() => {
// Hide again // Hide again
self.publicRoomLinkCopied = false; self.publicRoomLinkCopied = false;
}, 3000); }, }, 3000);
},
function (e) { function (e) {
console.log(e); console.log(e);
} }

View file

@ -11,14 +11,14 @@
roomName.substring(0, 1).toUpperCase() roomName.substring(0, 1).toUpperCase()
}}</span> }}</span>
</v-avatar> </v-avatar>
<div class="h4">This group</div> <div class="h4">{{$t('room_info_sheet.this_room')}}</div>
<div class="h2">{{ roomName }}</div> <div class="h2">{{ roomName }}</div>
<v-btn <v-btn
height="20px" height="20px"
color="black" color="black"
class="filled-button" class="filled-button"
@click.stop="showDetails" @click.stop="showDetails"
>View details</v-btn >{{$t('room_info_sheet.view_details')}}</v-btn
> >
</div> </div>
<room-list :title="'Other groups'" v-on:close="close" /> <room-list :title="'Other groups'" v-on:close="close" />
@ -27,7 +27,7 @@
color="black" color="black"
class="outlined-button" class="outlined-button"
@click.stop="createRoom" @click.stop="createRoom"
>Create group</v-btn >{{$t('room_info_sheet.create_room')}}</v-btn
> >
</div> </div>
</BottomSheet> </BottomSheet>

View file

@ -56,7 +56,7 @@
</div> </div>
</v-col> </v-col>
<v-col cols="6" v-if="ptt"> <v-col cols="6" v-if="ptt">
<div class="swipe-info">&lt;&lt; Swipe to cancel</div> <div class="swipe-info">&lt;&lt; {{$t('voice_recorder.swipe_to_cancel')}}</div>
</v-col> </v-col>
</v-row> </v-row>
</v-container> </v-container>
@ -72,7 +72,7 @@
<v-icon color="white">delete_outline</v-icon> <v-icon color="white">delete_outline</v-icon>
</v-col> </v-col>
<v-col cols="6"> <v-col cols="6">
<div class="swipe-info">Release to cancel</div> <div class="swipe-info">{{$t('voice_recorder.release_to_cancel')}}</div>
</v-col> </v-col>
</v-row> </v-row>
</v-container> </v-container>
@ -94,7 +94,7 @@
</v-col> </v-col>
<v-col cols="3"> <v-col cols="3">
<v-btn @click.stop="cancelRecording" text class="swipe-info" <v-btn @click.stop="cancelRecording" text class="swipe-info"
>Cancel</v-btn >{{$t('menu.cancel')}}</v-btn
> >
</v-col> </v-col>
<v-col cols="3"> <v-col cols="3">
@ -116,7 +116,7 @@
<v-row align="center"> <v-row align="center">
<v-col> <v-col>
<div class="swipe-info"> <div class="swipe-info">
{{ errorMessage || "Failed to record audio" }} {{ errorMessage || $t('voice_recorder.failed_to_record') }}
</div> </div>
</v-col> </v-col>
<v-col align="right"> <v-col align="right">

View file

@ -115,71 +115,3 @@ export default {
<style lang="scss"> <style lang="scss">
@import "@/assets/css/chat.scss"; @import "@/assets/css/chat.scss";
</style> </style>
function playPauseAudio() {
if (player.src) {
if (player.paused || player.ended) {
// Change the button to a pause button
changeButtonType(btnPlayPause, 'pause');
player.play();
}
else {
// Change the button to a play button
changeButtonType(btnPlayPause, 'play');
player.pause();
}
}
}
// Stop the current media from playing, and return it to the start position
function stopAudio() {
if (player.src) {
player.pause();
if (player.currentTime) player.currentTime = 0;
}
}
// Toggles the media player's mute and unmute status
function muteVolume() {
if (player.src) {
if (player.muted) {
// Change the button to a mute button
changeButtonType(btnMute, 'mute');
player.muted = false;
}
else {
// Change the button to an unmute button
changeButtonType(btnMute, 'unmute');
player.muted = true;
}
}
}
// Replays the media currently loaded in the player
function replayAudio() {
if (player.src) {
resetPlayer();
player.play();
}
}
// Updates a button's title, innerHTML and CSS class
function changeButtonType(btn, value) {
btn.title = value;
btn.innerHTML = value;
btn.className = value;
}
function resetPlayer() {
progressBar.value = 0;
//clear the current song
player.src = '';
// Move the media back to the start
player.currentTime = 0;
// Set the play/pause button to 'play'
changeButtonType(btnPlayPause, 'play');
}

View file

@ -7,7 +7,7 @@
}" }"
> >
<v-btn v-if="incoming" text @click.stop="startPrivateChat" class="ma-0 pa-0" <v-btn v-if="incoming" text @click.stop="startPrivateChat" class="ma-0 pa-0"
>Private chat with this user</v-btn >{{ $t("menu.start_private_chat") }}</v-btn
> >
</div> </div>
</template> </template>

View file

@ -2,10 +2,10 @@
<!-- Contact joined the chat --> <!-- Contact joined the chat -->
<div class="messageJoin"> <div class="messageJoin">
<div v-if="displayNameChange"> <div v-if="displayNameChange">
{{ changer }} changed display name to {{ event.getContent().displayname }} {{ $t('message.user_changed_display_name', { user: changer, displayName: event.getContent().displayname})}}
</div> </div>
<div v-if="avatarChange"> <div v-if="avatarChange">
{{ changer }} changed the avatar {{ $t('message.user_changed_avatar', { user: changer})}}
</div> </div>
</div> </div>
</template> </template>
@ -28,7 +28,7 @@ export default {
}, },
changer() { changer() {
if (this.event.getSender() == this.$matrix.currentUserId) { if (this.event.getSender() == this.$matrix.currentUserId) {
return "You"; return this.$t("message.you");
} }
if (this.displayNameChange) { if (this.displayNameChange) {
return this.event.getPrevContent().displayname; return this.event.getPrevContent().displayname;

View file

@ -1,7 +1,7 @@
<template> <template>
<!-- Contact invited to the chat --> <!-- Contact invited to the chat -->
<div class="messageJoin"> <div class="messageJoin">
{{ event.getContent().displayname || stateEventDisplayName(event) }} was invited to the chat... {{ $t('message.user_was_invited', {user: event.getContent().displayname || stateEventDisplayName(event)}) }}
</div> </div>
</template> </template>

View file

@ -1,7 +1,7 @@
<template> <template>
<!-- Contact joined the chat --> <!-- Contact joined the chat -->
<div class="messageJoin"> <div class="messageJoin">
{{ stateEventDisplayName(event) }} joined the chat {{ $t('message.user_joined',{user: stateEventDisplayName(event)}) }}
</div> </div>
</template> </template>

View file

@ -1,7 +1,7 @@
<template> <template>
<!-- Contact left the chat --> <!-- Contact left the chat -->
<div class="messageJoin"> <div class="messageJoin">
{{ stateEventDisplayName(event) }} left the chat {{ $t('message.user_left',{user: stateEventDisplayName(event)}) }}
</div> </div>
</template> </template>

View file

@ -1,7 +1,7 @@
<template> <template>
<message-incoming v-bind="{...$props, ...$attrs}" v-on="$listeners"> <message-incoming v-bind="{...$props, ...$attrs}" v-on="$listeners">
<div class="bubble audio-bubble"> <div class="bubble audio-bubble">
<audio-player :src="src">Audio file</audio-player> <audio-player :src="src">{{ $t('fallbacks.audio_file')}}</audio-player>
</div> </div>
</message-incoming> </message-incoming>
</template> </template>

View file

@ -3,7 +3,7 @@
<div class="bubble"> <div class="bubble">
<div class="original-message" v-if="inReplyToText"> <div class="original-message" v-if="inReplyToText">
<div class="original-message-sender"> <div class="original-message-sender">
{{ inReplyToSender || "Someone" }} said: {{ $t('message.user_said', {user: inReplyToSender || "Someone"}) }}
</div> </div>
<div <div
class="original-message-text" class="original-message-text"
@ -11,14 +11,14 @@
/> />
</div> </div>
<div class="message"> <div class="message">
<span>File: </span> <span>{{ $t('file_prefix') }}</span>
<span <span
style="cursor: pointer" style="cursor: pointer"
@click.stop="$emit('download')" @click.stop="$emit('download')"
v-html="linkify($sanitize(messageText))" v-html="linkify($sanitize(messageText))"
/> />
<span class="edit-marker" v-if="event.replacingEventId()" <span class="edit-marker" v-if="event.replacingEventId()"
>(edited)</span >{{ $t('edited') }}</span
> >
</div> </div>
</div> </div>

View file

@ -3,7 +3,7 @@
<div class="bubble"> <div class="bubble">
<div class="original-message" v-if="inReplyToText"> <div class="original-message" v-if="inReplyToText">
<div class="original-message-sender"> <div class="original-message-sender">
{{ inReplyToSender || "Someone" }} said: {{ $t('message.user_said', {user: inReplyToSender || "Someone"}) }}
</div> </div>
<div <div
class="original-message-text" class="original-message-text"
@ -13,7 +13,7 @@
<div class="message"> <div class="message">
<span v-html="linkify($sanitize(messageText))" /> <span v-html="linkify($sanitize(messageText))" />
<span class="edit-marker" v-if="event.replacingEventId()" <span class="edit-marker" v-if="event.replacingEventId()"
>(edited)</span >{{ $t('edited') }}</span
> >
</div> </div>
<!-- <div>{{ JSON.stringify(event) }}</div> --> <!-- <div>{{ JSON.stringify(event) }}</div> -->

View file

@ -3,11 +3,11 @@
<div class="bubble image-bubble"> <div class="bubble image-bubble">
<v-responsive :aspect-ratio="16 / 9" :src="src"> <v-responsive :aspect-ratio="16 / 9" :src="src">
<video :src="src" controls style="width: 100%; height: 100%"> <video :src="src" controls style="width: 100%; height: 100%">
Video file {{$t('fallbacks.video_file')}}
</video> </video>
<div v-if="downloadProgress" class="download-overlay"> <div v-if="downloadProgress" class="download-overlay">
<div class="text-center download-text"> <div class="text-center download-text">
{{ downloadProgress }}% downloaded {{ $t('message.download_progress',{percentage: downloadProgress}) }}
</div> </div>
</div> </div>
</v-responsive> </v-responsive>

View file

@ -12,25 +12,25 @@
<v-btn icon @click.stop="addReply" class="ma-0 pa-0"> <v-btn icon @click.stop="addReply" class="ma-0 pa-0">
<v-icon>reply</v-icon> <v-icon>reply</v-icon>
</v-btn> </v-btn>
<div>Reply</div> <div>{{$t('menu.reply')}}</div>
</v-col> </v-col>
<v-col v-if="isEditable"> <v-col v-if="isEditable">
<v-btn icon @click.stop="edit" class="ma-0 pa-0"> <v-btn icon @click.stop="edit" class="ma-0 pa-0">
<v-icon>edit</v-icon> <v-icon>edit</v-icon>
</v-btn> </v-btn>
<div>Edit</div> <div>{{$t('menu.edit')}}</div>
</v-col> </v-col>
<v-col v-if="isRedactable"> <v-col v-if="isRedactable">
<v-btn icon @click.stop="redact" class="ma-0 pa-0"> <v-btn icon @click.stop="redact" class="ma-0 pa-0">
<v-icon>delete</v-icon> <v-icon>delete</v-icon>
</v-btn> </v-btn>
<div>Delete</div> <div>{{$t('menu.delete')}}</div>
</v-col> </v-col>
<v-col v-if="isDownloadable"> <v-col v-if="isDownloadable">
<v-btn icon @click.stop="download" class="ma-0 pa-0"> <v-btn icon @click.stop="download" class="ma-0 pa-0">
<v-icon>get_app</v-icon> <v-icon>get_app</v-icon>
</v-btn> </v-btn>
<div>Download</div> <div>{{$t('menu.download')}}</div>
</v-col> </v-col>
</v-row> </v-row>
</v-container> </v-container>

View file

@ -18,7 +18,7 @@
<img v-if="userAvatar" :src="userAvatar" /> <img v-if="userAvatar" :src="userAvatar" />
<span v-else class="white--text headline">{{ userAvatarLetter }}</span> <span v-else class="white--text headline">{{ userAvatarLetter }}</span>
</v-avatar> </v-avatar>
<!-- <div class="sender">{{ "You" }}</div> --> <!-- <div class="sender">{{ $t('message.you') }}</div> -->
<div class="senderAndTime"> <div class="senderAndTime">
<div class="time"> <div class="time">
{{ formatTime(event.event.origin_server_ts) }} {{ formatTime(event.event.origin_server_ts) }}

View file

@ -1,7 +1,7 @@
<template> <template>
<message-outgoing v-bind="{ ...$props, ...$attrs }" v-on="$listeners"> <message-outgoing v-bind="{ ...$props, ...$attrs }" v-on="$listeners">
<div class="audio-bubble"> <div class="audio-bubble">
<audio-player :src="src">Audio file</audio-player> <audio-player :src="src">{{ $t('fallbacks.audio_file')}}</audio-player>
</div> </div>
</message-outgoing> </message-outgoing>
</template> </template>

View file

@ -3,7 +3,7 @@
<div class="bubble"> <div class="bubble">
<div class="original-message" v-if="inReplyToText"> <div class="original-message" v-if="inReplyToText">
<div class="original-message-sender"> <div class="original-message-sender">
{{ inReplyToSender || "Someone" }} said: {{ $t('message.user_said', {user: inReplyToSender || "Someone"}) }}
</div> </div>
<div <div
class="original-message-text" class="original-message-text"
@ -19,7 +19,7 @@
v-html="linkify($sanitize(messageText))" v-html="linkify($sanitize(messageText))"
/> />
<span class="edit-marker" v-if="event.replacingEventId()" <span class="edit-marker" v-if="event.replacingEventId()"
>(edited)</span >{{ $t('edited') }}</span
> >
</div> </div>
</div> </div>

View file

@ -3,7 +3,7 @@
<div class="bubble"> <div class="bubble">
<div class="original-message" v-if="inReplyToText"> <div class="original-message" v-if="inReplyToText">
<div class="original-message-sender"> <div class="original-message-sender">
{{ inReplyToSender || "Someone" }} said: {{ $t('message.user_said', {user: inReplyToSender || "Someone"}) }}
</div> </div>
<div <div
class="original-message-text" class="original-message-text"
@ -14,7 +14,7 @@
<div class="message"> <div class="message">
<span v-html="linkify($sanitize(messageText))" /> <span v-html="linkify($sanitize(messageText))" />
<span class="edit-marker" v-if="event.replacingEventId()" <span class="edit-marker" v-if="event.replacingEventId()"
>(edited)</span >{{ $t('edited') }}</span
> >
</div> </div>
</div> </div>

View file

@ -3,7 +3,7 @@
<div class="bubble image-bubble"> <div class="bubble image-bubble">
<v-responsive :aspect-ratio="16 / 9" class="ma-0 pa-0"> <v-responsive :aspect-ratio="16 / 9" class="ma-0 pa-0">
<video :src="src" controls style="width: 100%; height: 100%"> <video :src="src" controls style="width: 100%; height: 100%">
Video file {{$t('fallbacks.video_file')}}
</video> </video>
</v-responsive> </v-responsive>
</div> </div>

View file

@ -1,7 +1,7 @@
<template> <template>
<!-- ROOM AVATAR CHANGED --> <!-- ROOM AVATAR CHANGED -->
<div class="statusEvent"> <div class="statusEvent">
{{ stateEventDisplayName(event) }} changed the room avatar {{ $t('message.user_changed_room_avatar',{user: stateEventDisplayName(event)}) }}
</div> </div>
</template> </template>

View file

@ -1,7 +1,7 @@
<template> <template>
<!-- ROOM AVATAR CHANGED --> <!-- ROOM AVATAR CHANGED -->
<div class="statusEvent"> <div class="statusEvent">
{{ stateEventDisplayName(event) }} made room history {{ history(event) }} {{ $t('message.user_changed_room_history',{user: stateEventDisplayName(event), type: history(event)}) }}
</div> </div>
</template> </template>
@ -15,13 +15,13 @@ export default {
const visibility = event.getContent().history_visibility; const visibility = event.getContent().history_visibility;
switch (visibility) { switch (visibility) {
case "world_readable": case "world_readable":
return "readable by anyone"; return this.$t('message.room_history_world_readable');
case "shared": case "shared":
return "readable to all members in the room"; return this.$t('message.room_history_shared');
case "invited": case "invited":
return "readable to members from when they were invited"; return this.$t('message.room_history_invited');
case "joined": case "joined":
return "readable to members from when they joined"; return this.$t('message.room_history_joined');
} }
return visibility; return visibility;
} }

View file

@ -1,7 +1,7 @@
<template> <template>
<!-- ROOM JOIN RULES CHANGED --> <!-- ROOM JOIN RULES CHANGED -->
<div class="statusEvent"> <div class="statusEvent">
{{ stateEventDisplayName(event) }} made the room {{ joinRule(event) }} {{ $t('message.user_changed_join_rules', { user: stateEventDisplayName(event), type: joinRule(event)}) }}
</div> </div>
</template> </template>
@ -15,9 +15,9 @@ export default {
const joinRule = event.getContent().join_rule; const joinRule = event.getContent().join_rule;
switch (joinRule) { switch (joinRule) {
case "invite": case "invite":
return "invite only"; return this.$t('message.room_joinrule_invite');
case "public": case "public":
return "public"; return this.$t('message.room_joinrule_public');
} }
return joinRule; return joinRule;
} }

View file

@ -1,8 +1,7 @@
<template> <template>
<!-- ROOM NAME CHANGED --> <!-- ROOM NAME CHANGED -->
<div class="statusEvent"> <div class="statusEvent">
{{ stateEventDisplayName(event) }} changed room name to {{ $t('message.user_changed_room_name', {user: stateEventDisplayName(event), name: event.getContent().name}) }}
{{ event.getContent().name }}
</div> </div>
</template> </template>

View file

@ -1,8 +1,7 @@
<template> <template>
<!-- ROOM TOPIC CHANGED --> <!-- ROOM TOPIC CHANGED -->
<div class="statusEvent"> <div class="statusEvent">
{{ stateEventDisplayName(event) }} changed topic to {{ $t('message.user_changed_room_topic', {user: stateEventDisplayName(event), topic: event.getContent().topic}) }}
{{ event.getContent().topic }}
</div> </div>
</template> </template>

View file

@ -102,7 +102,7 @@ export default {
} }
// We don't have the original text (at the moment at least) // We don't have the original text (at the moment at least)
return "<original text>"; return this.$t('fallbacks.original_text');
} }
return null; return null;
}, },
@ -169,7 +169,7 @@ export default {
*/ */
stateEventDisplayName(event) { stateEventDisplayName(event) {
if (event.getSender() == this.$matrix.currentUserId) { if (event.getSender() == this.$matrix.currentUserId) {
return "You"; return this.$t('message.you');
} }
if (this.room) { if (this.room) {
const member = this.room.getMember(event.getSender()); const member = this.room.getMember(event.getSender());

View file

@ -13,6 +13,7 @@ import VueResize from 'vue-resize';
import 'vue-resize/dist/vue-resize.css'; import 'vue-resize/dist/vue-resize.css';
import VueClipboard from 'vue-clipboard2' import VueClipboard from 'vue-clipboard2'
import VueSanitize from "vue-sanitize"; import VueSanitize from "vue-sanitize";
import i18n from './plugins/lang';
var defaultOptions = VueSanitize.defaults; var defaultOptions = VueSanitize.defaults;
defaultOptions.disallowedTagsMode = "recursiveEscape"; defaultOptions.disallowedTagsMode = "recursiveEscape";
@ -153,6 +154,7 @@ new Vue({
vuetify, vuetify,
store, store,
router, router,
i18n,
matrix, matrix,
cleaninsights, cleaninsights,
render: h => h(App) render: h => h(App)

24
src/plugins/lang.js Normal file
View file

@ -0,0 +1,24 @@
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
var messages = {}
function importAll(r) {
return r.keys().map(res => {
// Remove"./"
const parts = res.split("/");
const locale = parts[1].split(".")[0];
messages[locale] = r(res).default;
});
}
importAll(require.context('@/assets/translations/', true, /\.js$/));
export default new VueI18n({
locale: 'en',
fallbackLocale: 'en',
silentFallbackWarn: true,
messages: messages
})