Skip to content

P3. Convergent Design

Functional Design

User

Purpose: authenticate users

OP: After a user registers with a username and password, they can authenticate as that user by providing a matching username and password

State:

registered: set User
username, password: registered → one String
registered: set User
username, password: registered → one String

Actions:

register (n, p: String, out u: User)
authenticate (n, p: String, out u: User)
register (n, p: String, out u: User)
authenticate (n, p: String, out u: User)

Section

Purpose: Represents a short but meaningful (3-4 sentences) section of content that can be translated independently

OP: Uploaded untranslated content is grouped into sections. Then, users can provide translations to each section separately, which allows for easy collaboration.

States:

sections: set Section
sectionText: one Section → one string
sections: set Section
sectionText: one Section → one string

Actions:

createSingleSection(text: string) →
  creates a single section from the given text and returns it
splitIntoMultipleSections(text: string) →
  automatically splits a large text into multiple different
  sections (each 3-4 sentences long) and returns the sections as a list
createSingleSection(text: string) →
  creates a single section from the given text and returns it
splitIntoMultipleSections(text: string) →
  automatically splits a large text into multiple different
  sections (each 3-4 sentences long) and returns the sections as a list

SectionTranslation[User, Section]

Purpose: Represents a possible translation of a section in a text

OP: Each section in the app can be translated in different ways by different users. Each of these possible translations are then displayed as alternatives.

States:

sectionTranslations: set SectionTranslation
translator: one SectionTranslation → one User
translation: one SectionTranslation → one String
translationOf: sectionTranslations → one Section
sectionTranslations: set SectionTranslation
translator: one SectionTranslation → one User
translation: one SectionTranslation → one String
translationOf: sectionTranslations → one Section

Actions:

createSectionTranslation(section: Section, translator: User, translation: string) →
     creates a sectionTranslation for a given section
createSectionTranslation(section: Section, translator: User, translation: string) →
     creates a sectionTranslation for a given section

Name: Document[Tag, User]

Purpose: Represent an article or a similar document uploaded onto the app

OP: A user uploads any online document that they need translated. Then, they can make requests to translate it into a different language.

States:

documents: set Document
title: one Document → one string
author: one Document → one string
content: one Document → one string
originalLanguage: one Document → one Tag
uploader: one Document → one User
documents: set Document
title: one Document → one string
author: one Document → one string
content: one Document → one string
originalLanguage: one Document → one Tag
uploader: one Document → one User

Actions:

create(title: string, author: string, content: string, originalLanguage: Tag, uploader: User) →
    creates a new document, and sets its fields to the appropriate values
delete(document: Document) → deletes the given document
create(title: string, author: string, content: string, originalLanguage: Tag, uploader: User) →
    creates a new document, and sets its fields to the appropriate values
delete(document: Document) → deletes the given document

Tag [TaggedObject]

Purpose: Represent any relevant information about the context of a translation request (language, subject, content source, etc…)

OP: Works similarly to how tags work in other apps: People post translation requests and can associate them with tags. People can then search by tag. The unique use of our app is that each request will have two mandatory** **tags: language translated from and language translated to. These will work similarly to other tags but might have their own interface because of how crucial they are.

States:

tags: set Tag
tagName: one Tag → one string
attachments: one Tag → set TaggedConcept
languageTags: set Tag
tags: set Tag
tagName: one Tag → one string
attachments: one Tag → set TaggedConcept
languageTags: set Tag

Actions:

createTag(tagName: string, isLanguage: boolean) →
  creates a new tag with the given name, if it is a language Tag,
  adds it to the languageTags set
tagItem(item: TaggedConcept, tag: Tag) → tags the given item with the given tag
createTag(tagName: string, isLanguage: boolean) →
  creates a new tag with the given name, if it is a language Tag,
  adds it to the languageTags set
tagItem(item: TaggedConcept, tag: Tag) → tags the given item with the given tag

Translation Request [Document, Section, Tag, User]

Purpose: Allows users to take documents published and have them translated.

OP: Users can take documents published and make requests to have them translated. The document then gets divided into sections and each section gets translated separately. After the translation is complete, you can download the finished translation.

States:

document: one TranslationRequest → one Document
sections: one TranslationRequest → list Section
languageTo: one TranslationRequest → Tag
requester: one TranslationRequest → one User
document: one TranslationRequest → one Document
sections: one TranslationRequest → list Section
languageTo: one TranslationRequest → Tag
requester: one TranslationRequest → one User

Actions:

create(document: document, languageTo: Tag, sections: list Section curUser: User) →
  creates a new request for the given document, language, and sections.
  Must be logged in, and sets the requester to be the currently logged-in user.
create(document: document, languageTo: Tag, sections: list Section curUser: User) →
  creates a new request for the given document, language, and sections.
  Must be logged in, and sets the requester to be the currently logged-in user.

Access Control [ControlledObject, User]

Purpose: Allows users to control which users can access a ControlledObject

OP: Users can choose which other users can access a ControlledObject. All users can access the ControlledObject if usersThatCanAccess is an empty set, otherwise, only the specified users can. Note: Allowing a User access to a ControlledObject allows them to perform various actions depending on the type of the ControlledObject. For example, an Access Control on a TranslationRequest specifies what users have permission to add translations while an Access Control on a Document specifies what users have permission to view it.

States:

accessController: one Access Control → one User
accessControlled: one Access Control → one ControlledObj
usersThatCanAccess: one Access Control → set User

Note: An empty usersThatCanACcess means access is open to everyone.
accessController: one Access Control → one User
accessControlled: one Access Control → one ControlledObj
usersThatCanAccess: one Access Control → set User

Note: An empty usersThatCanACcess means access is open to everyone.

Actions:

createAccessControl(curUser: User, obj: ControlledObj) →
  sets up AccessControl for the given obj, with the curUser as the controller
addAccess(curUser: User, obj: ControlledObj, addedUser: User) →
  Checks that curUser is the controller of the given obj, and adds access for addedUser.
removeAccess(curUser: User, obj: ControlledObj, deletedUser: User) →
  Checks that curUser is the controller of the given obj, and removes access for addedUser.
checkAccess(user: User, obj: ControlledObj) → Checks whether user has access to obj.
createAccessControl(curUser: User, obj: ControlledObj) →
  sets up AccessControl for the given obj, with the curUser as the controller
addAccess(curUser: User, obj: ControlledObj, addedUser: User) →
  Checks that curUser is the controller of the given obj, and adds access for addedUser.
removeAccess(curUser: User, obj: ControlledObj, deletedUser: User) →
  Checks that curUser is the controller of the given obj, and removes access for addedUser.
checkAccess(user: User, obj: ControlledObj) → Checks whether user has access to obj.

Upvote[Content, User]

Purpose: Allow users to rank content

OP: Signed-in users can upvote content to show they think it is of high quality

State:

upvotes: set Upvote
upvotedContent: one Upvote → one Content
upvotingUser: one Upvote → one User
upvotes: set Upvote
upvotedContent: one Upvote → one Content
upvotingUser: one Upvote → one User

Actions:

upvote (c: Content, u: User)
removeUpvote (c: Content, u: User)
countUpvotes (c: Content)
upvote (c: Content, u: User)
removeUpvote (c: Content, u: User)
countUpvotes (c: Content)

Instantiations

User = User

Section = Section[Document]

SectionTranslation = SectionTranslation[User, Section]

DocumentTag = Tag[Document]

Document = Document[DocumentTag, User]

DocumentAccessControl = AccessControl[Document, User]

TranslationTag = Tag[TranslationRequest]

TranslationRequest = TranslationRequest[Document, Section, TranslationTag, User]

TranslationRequestAccessControl = AccessControl[TranslationRequest, User]

SectionTranslationUpvotes = Upvotes[SectionTranslation, User]

TranslationRequestUpvotes = Upvotes[TranslationRequest, User]
User = User

Section = Section[Document]

SectionTranslation = SectionTranslation[User, Section]

DocumentTag = Tag[Document]

Document = Document[DocumentTag, User]

DocumentAccessControl = AccessControl[Document, User]

TranslationTag = Tag[TranslationRequest]

TranslationRequest = TranslationRequest[Document, Section, TranslationTag, User]

TranslationRequestAccessControl = AccessControl[TranslationRequest, User]

SectionTranslationUpvotes = Upvotes[SectionTranslation, User]

TranslationRequestUpvotes = Upvotes[TranslationRequest, User]

Synchronizations

AccessControl:

Creating a new document creates a new access control for that document. Then, whenever someone tries to view that document, it is first checked that they have access to that document.

Creating a new translation request requires that the user has access to the document that will be translated. This also sets up access control for that translation request.

Viewing and upvoting a translation request (or a section translation for a section of that request) requires that the user has access to the document for that translation request.

Adding a section translation for a section requires the user to have access to that translation request.

Being added for access control of a translation request requires that the user first has access to the document for that translation request.

Export a Document:

When a user exports a translated document, they compile translated sections into a single file, which is an action that encompasses multiple concepts.

Language Tags:

When a user creates a new document or translation request, they also define the tag that corresponds to the language from/ language to. This tag must be in the languageTags concept in the corresponding Tag concept. This action also triggers a tagItem action in the corresponding Tag concept, so that coherency inside the app is created.

Cascading Deletes:

When a user is deleted, so do all the upvotes made by that user; when a translation request is deleted, so do its sections; when a section is deleted, so do its section translations; etc…

Sync Code:

The code below shows how a new translation request would get initialized with all of the concept syncs:

createTranslationRequest(Document document, User uploader, Tag languageTo, List[User] canAccess)
    sections = Section.splitIntoMultipleSections(document.text)
    tr = TranslationRequest.create(document, languageTo, sections, uploader)
    ac = TranslationRequestAccessControl.createAccessControl(uploader, tr)
    for user in canAccess:
        TranslationRequestAccessControl.addAccess(uploader, ac, user)
createTranslationRequest(Document document, User uploader, Tag languageTo, List[User] canAccess)
    sections = Section.splitIntoMultipleSections(document.text)
    tr = TranslationRequest.create(document, languageTo, sections, uploader)
    ac = TranslationRequestAccessControl.createAccessControl(uploader, tr)
    for user in canAccess:
        TranslationRequestAccessControl.addAccess(uploader, ac, user)

Dependency diagram

Wireframes

https://www.figma.com/file/DHxuB4UCGhtJojR7LO0x6F/P3?type=design&node-id=0%3A1&mode=design&t=Scylkrl9Syjgzb6J-1

Heuristic Evaluation

Usability Criteria

Efficiency: once you know how to use an interface, can you use it to quickly and efficiently accomplish your goals?

Our interface weakly supports the efficiency heuristic in one regard: the user may become familiar with the interface to the point where they understand the process of submitting translation requests, contributing section translations, and exporting document translations but the interface is inefficient for helping users discover translators. For example, the only way to find a translator’s profile is if they’ve made a translation request or have contributed a section translation (information scent provided with a link to their profile). However, there is no other way for a user to search for translators by ratings, their language, or by expertise which could get in the way of them quickly and efficiently getting their document translated. One solution would be to create a view where a user can look up translators by ratings, language, and expertise – a contact book of some sort. See below:

Pleasantness: how aesthetically pleasing or calming is the interface?

The interface is aesthetically pleasing and calming. The layout is simple so as to not overwhelm the user but remains intuitive. The color scheme remains professional, yet inviting as well as cohesive by following a more neutral, cool-toned palette. We chose these colors and designed the components to fit the theme and purpose of the app. While a more colorful and bold color scheme might be suitable for a more casual app focused on fun and entertainment, we recognize that our users are approaching our app from a professional and educational context.

Physical heuristics

Mapping: does the layout of the interface elements match their function?

The layout of the interface elements of our wireframe matches their functions. For example, from the layout of interface elements, it is clear that the purpose of the “Home” page is to display a collection of documents and allow the user to efficiently browse through them using different filters. The design pattern, with filtering and sorting interface elements occupying a smaller column space on the left-hand side of the screen and a grid of elements filling up the remaining, majority of space, matches that of many applications serving similar functions including online retail stores and scientific journals.

Similarly, the layout of the translation page helps fulfill its purpose of displaying documents and facilitating annotations. At the bottom half of the page, the 2 columns of equal width suggest some sort of relationship between the content in the “Original Text” column with the content in the “Translated Text” column. Additionally, when a user clicks on a section and the annotations pop up, by aligning the start of the right column with the selected section on the left, the connection between the selected section on the left is made with the list of translations in the column on the right.

Situational context: how does the interface convey to a user their context (where they are, the app’s state, etc.), and how does it adapt to their context?

Our wireframe weakly supports the situational context heuristic. While the user is able to understand where they are in the application in terms of what page they are on based on the nav bar’s reactivity, it is difficult for a user to understand the app’s state upon certain interactions, mainly form submissions. For example:

  1. When the user submits a translation request with a new document upload, the application closes the translation request form and its overlay, returning the user back to the home page
  2. Similarly, when the user submits a request to translate an existing document from a translation page, the application closes the request form and its overlay, returning the user back to the translation page.
  3. When the user submits an “Export Translation to PDF” form, the application closes the form and its overlay, returning the user back to the translation page.

The user may be confused about whether they were able to successfully execute the tasks because the interface does not provide enough “feedback.” This heuristic could be strengthened by adding toasts after every submission to confirm the success of the submission or bring attention to any errors that occur. Additionally, for example, #1 and #2 above, the application could redirect the user to the translation page created based on the request that was just submitted.

Linguistic level

Speak a user’s language: does the interface use simple, helpful informative messages? Are there instances where messages might only be understandable by developers?

While the wireframe employs simple language, the brevity and scarcity of text make it less helpful and informative. For example, the lack of more informative messages in the translation request form may confuse users and leave them unsure of exactly what an input requires or represents. For example, in the translation request form, the field “domain” may not be readily understood by users to mean the field to which the document belongs (“Computer Science, “Chemical Engineering,” etc). More importantly, the access control section lacks any description or instruction. Consequently, the user may not understand the difference between viewer access and translator access. Additionally, the section does not specify that added viewers will be allowed to add more translators to the document if they open another pull request. These are terms and mechanisms that are only understandable by us as the developers. This lack of transparency has significant negative consequences as maintaining the privacy of documents is crucial to our application.

One possible solution would be to add informative tooltips to each input field where upon hovering over an “i” icon, a tooltip will appear to guide the user by explaining what kind of information to put in the field and the purpose/consequences of filling in the field.

Information scent: how does the interface provide hints for navigation to aid a user in “foraging” for information?

The interface currently provides “information scents” to help users discover translator profiles. For example, in the translation sections, clicking on the name of the translator links the user to their profile.

However, the information scent heuristic could be strengthened by providing hints for navigation to aid users in “foraging” for other types of information. For example, it may be beneficial to design for information scents to help users discover other documents under similar domains or languages for a few reasons:

  1. Translators could find other relevant works they can apply their expertise and fluency to
  2. General readers could find other works under the same domain that have been translated into their language.

Possible design solutions include having language badges and tags lead back to the home page with relevant filters already applied.

Visual Design Study

https://docs.google.com/presentation/d/1SI4-VLdhxl9rnk2n1zLnIXcjTwkfaQwZVHGSB7VorlM/edit?usp=sharing

Implementation Plan

The link to the implementation timeline: with assignments, deadlines, and responsibilities. https://anna8murphy.notion.site/f48a848bf86146b39be339d9dda2d969?v=ccadcd04350446bd96e0ed40deeac774

If something goes wrong in the process of implementing the app and we feel that we will not be able to meet the deadlines, we will probably drop the access control concept. We plan to implement this concept last so that we have a buffer before the final deadline. We might also decide to drop the flexible sectioning functionality if we feel like we are falling behind.