Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Fix #3753: Fix some translatable/untranslatable strings #3754

Merged
merged 3 commits into from
Sep 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ gradlew.bat @BenHenning

# App UI strings.
/app/src/main/res/values*/strings.xml @BenHenning
/app/src/main/res/values*/untranslated_strings.xml @BenHenning

# Proguard configuration.
*.pro @BenHenning
Expand Down
7 changes: 5 additions & 2 deletions app/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ exports_files(["src/main/AndroidManifest.xml"])
# NOTE: if the file is added here make sure to remove this from the other sub lists
# of EXCLUDED_APP_LIB_FILES.
# keep sorted
MIGRATED_SOURCE_FILES = [
MIGRATED_SOURCE_FILES = glob([
"src/main/java/org/oppia/android/app/utility/datetime/*.kt",
]) + [
"src/main/java/org/oppia/android/app/viewmodel/ObservableArrayList.kt",
"src/main/java/org/oppia/android/app/viewmodel/ObservableViewModel.kt",
]
Expand Down Expand Up @@ -502,7 +504,7 @@ android_library(
["src/main/res/**"],
exclude = DATABINDING_LAYOUTS,
),
visibility = ["//visibility:private"],
visibility = ["//app:__subpackages__"],
deps = ["//third_party:com_google_android_material_material"],
)

Expand Down Expand Up @@ -606,6 +608,7 @@ kt_android_library(
"//app/src/main/java/org/oppia/android/app/viewmodel:observable_array_list",
"//app/src/main/java/org/oppia/android/app/viewmodel:observable_view_model",
"//app/src/main/java/org/oppia/android/app/viewmodel:view_model_provider",
"//app/src/main/java/org/oppia/android/app/utility/datetime:date_time_util",
"//domain",
"//third_party:androidx_core_core",
"//third_party:androidx_databinding_databinding-common",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,41 @@ import org.oppia.android.app.help.faq.faqItemViewModel.FAQContentViewModel
import org.oppia.android.app.help.faq.faqItemViewModel.FAQHeaderViewModel
import org.oppia.android.app.help.faq.faqItemViewModel.FAQItemViewModel
import org.oppia.android.app.viewmodel.ObservableViewModel
import java.util.Locale
import javax.inject.Inject

/** View model in [FAQListFragment]. */
class FAQListViewModel @Inject constructor(
val activity: AppCompatActivity
) : ObservableViewModel() {
private val arrayList = ArrayList<FAQItemViewModel>()

val faqItemList: List<FAQItemViewModel> by lazy {
getRecyclerViewItemList()
computeFaqViewModelList()
}

private fun computeFaqViewModelList(): List<FAQItemViewModel> {
val questions = retrieveQuestions()
val faqs = questions.zip(retrieveAnswers()).mapIndexed { index, (question, answer) ->
FAQContentViewModel(activity, question, answer, showDivider = index != questions.lastIndex)
}
return listOf(FAQHeaderViewModel()) + faqs
}

private fun getRecyclerViewItemList(): ArrayList<FAQItemViewModel> {
val faqHeaderViewModel = FAQHeaderViewModel()
arrayList.add(faqHeaderViewModel)
val questions: Array<String> = activity.resources.getStringArray(R.array.faq_questions)
val answers: Array<String> = activity.resources.getStringArray(R.array.faq_answers)
questions.forEachIndexed { index, question ->
val faqContentViewModel = FAQContentViewModel(activity, question, answers[index])
if (questions[questions.size - 1] == question) {
faqContentViewModel.showDivider.set(false)
} else {
faqContentViewModel.showDivider.set(true)
}
arrayList.add(faqContentViewModel)
private fun retrieveQuestionsOrAnswers(questionsOrAnswers: Array<String>): List<String> {
val appName = activity.resources.getString(R.string.app_name)
return questionsOrAnswers.mapIndexed { index, questionOrAnswer ->
if (index == QUESTION_INDEX_WITH_OPPIA_REFERENCE) {
String.format(Locale.getDefault(), questionOrAnswer, appName)
} else questionOrAnswer
}
return arrayList
}

private fun retrieveQuestions(): List<String> =
retrieveQuestionsOrAnswers(activity.resources.getStringArray(R.array.faq_questions))

private fun retrieveAnswers(): List<String> =
retrieveQuestionsOrAnswers(activity.resources.getStringArray(R.array.faq_answers))

private companion object {
private const val QUESTION_INDEX_WITH_OPPIA_REFERENCE = 3
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
package org.oppia.android.app.help.faq.faqItemViewModel

import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.ObservableField
import org.oppia.android.app.help.faq.RouteToFAQSingleListener

/** Content view model for the recycler view in [FAQFragment]. */
class FAQContentViewModel(
private val activity: AppCompatActivity,
val question: String,
val answer: String
val answer: String,
val showDivider: Boolean
) : FAQItemViewModel() {

/** Used to control visibility of divider. */
val showDivider = ObservableField(true)

fun clickOnFAQQuestion() {
val routeToFAQSingleListener = activity as RouteToFAQSingleListener
routeToFAQSingleListener.onRouteToFAQSingle(question, answer)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package org.oppia.android.app.home

import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel
import org.oppia.android.util.datetime.DateTimeUtil
import org.oppia.android.app.utility.datetime.DateTimeUtil
import org.oppia.android.util.system.OppiaClock
import java.util.Objects

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class OnboardingSlideViewModel(val context: Context, viewPagerSlide: ViewPagerSl
OnboardingViewPagerViewModel() {
val slideImage = ObservableField<Int>(R.drawable.ic_portrait_onboarding_0)
val title =
ObservableField<String>(context.resources.getString(R.string.onboarding_slide_0_title))
ObservableField<String>(getOnboardingSlide0Title())
val description =
ObservableField<String>(context.resources.getString(R.string.onboarding_slide_0_description))
private val orientation = Resources.getSystem().configuration.orientation
Expand All @@ -35,7 +35,7 @@ class OnboardingSlideViewModel(val context: Context, viewPagerSlide: ViewPagerSl
} else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
slideImage.set(R.drawable.ic_portrait_onboarding_0)
}
title.set(context.resources.getString(R.string.onboarding_slide_0_title))
title.set(getOnboardingSlide0Title())
description.set(context.resources.getString(R.string.onboarding_slide_0_description))
}
ViewPagerSlide.SLIDE_1 -> {
Expand Down Expand Up @@ -66,4 +66,9 @@ class OnboardingSlideViewModel(val context: Context, viewPagerSlide: ViewPagerSl
}
}
}

private fun getOnboardingSlide0Title(): String {
val appName = context.resources.getString(R.string.app_name)
return context.resources.getString(R.string.onboarding_slide_0_title, appName)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,11 @@ class PinPasswordActivityPresenter @Inject constructor(
}

private fun showAdminForgotPin() {
val appName = activity.resources.getString(R.string.app_name)
pinViewModel.showAdminPinForgotPasswordPopUp.set(true)
alertDialog = AlertDialog.Builder(activity, R.style.AlertDialogTheme)
.setTitle(R.string.pin_password_forgot_title)
.setMessage(R.string.pin_password_forgot_message)
.setMessage(activity.resources.getString(R.string.pin_password_forgot_message, appName))
.setNegativeButton(R.string.admin_settings_cancel) { dialog, _ ->
pinViewModel.showAdminPinForgotPasswordPopUp.set(false)
dialog.dismiss()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""
General purposes utilities to manage date and time in user-facing strings.
"""

load("@dagger//:workspace_defs.bzl", "dagger_rules")
load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_android_library")

# Resource shim needed so that DateTimeUtil can build in both Gradle & Bazel.
genrule(
name = "update_DateTimeUtil",
srcs = ["DateTimeUtil.kt"],
outs = ["DateTimeUtil_updated.kt"],
cmd = """
cat $(SRCS) |
sed 's/import org.oppia.android.R/import org.oppia.android.app.R/g' > $(OUTS)
""",
)

kt_android_library(
name = "date_time_util",
srcs = [
"DateTimeUtil_updated.kt",
],
visibility = ["//app:__subpackages__"],
deps = [
":dagger",
"//app:resources",
"//third_party:javax_inject_javax_inject",
"//utility/src/main/java/org/oppia/android/util/system:oppia_clock",
],
)

dagger_rules()
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.oppia.android.app.utility.datetime

import android.content.Context
import org.oppia.android.R
import org.oppia.android.util.system.OppiaClock
import java.util.Calendar
import javax.inject.Inject
import javax.inject.Singleton

/** Utility to manage date and time for user-facing strings. */
@Singleton
class DateTimeUtil @Inject constructor(
private val context: Context,
private val oppiaClock: OppiaClock
) {
/**
* Returns a user-readable string based on the time of day (to be concatenated as part of a
* greeting for the user).
*/
fun getGreetingMessage(): String {
val calender = oppiaClock.getCurrentCalendar()
return when (calender.get(Calendar.HOUR_OF_DAY)) {
in 4..11 -> context.getString(R.string.home_screen_good_morning_greeting_fragment)
in 12..16 -> context.getString(R.string.home_screen_good_afternoon_greeting_fragment)
in 17 downTo 3 -> context.getString(R.string.home_screen_good_evening_greeting_fragment)
else -> context.getString(R.string.home_screen_good_evening_greeting_fragment)
}
}
}
27 changes: 0 additions & 27 deletions app/src/main/res/values/array.xml

This file was deleted.

41 changes: 23 additions & 18 deletions app/src/main/res/values/faqs.xml
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="faq_question_1">How can I create a new profile?</string>
<string name="faq_question_2">How can I delete a profile?</string>
<string name="faq_question_3">How can I change my email/phone number?</string>
<string name="faq_question_4">What is Oppia?</string>
<string name="faq_question_5">Who is an Administrator?</string>
<string name="faq_question_6">Why is the Exploration player not loading?</string>
<string name="faq_question_7">Why is my audio not playing?</string>
<string name="faq_question_8">How do I download a Topic?</string>
<string name="faq_question_9">I can\'t find my question here. What now?</string>
<string name="faq_answer_1"><![CDATA[<p>If it is your first time creating a profile and not have a PIN: </p> <p> 1. From the Profile Chooser, tap on <strong>Set up Multiple Profiles</strong>. </p> <p> 2. Create a PIN and <strong>Save</strong>. </p> <p> 3. Fill in all fields for the profile. </p> <ol> <li> (Optional) Upload a photo. </li> <li> Enter a name. </li> <li> (Optional) Assign a 3-digit PIN. </li> </ol> <p> 4. Tap <strong>Create</strong>. This profile is added to your Profile Chooser! <br/> <br/> If you have created a profile before and have a PIN: </p> <p> 1. From the Profile Chooser, tap on <strong>Add Profile</strong>. </p> <p> 2. Enter your PIN and tap <strong>Submit</strong>. </p> <p> 3. Fill in all fields for the profile. </p> <ol> <li> (Optional) Upload a photo. </li> <li> Enter a name. </li> <li> (Optional) Assign a 3-digit PIN. </li> </ol> <p> 4. Tap <strong>Create</strong>. This profile is added to your Profile Chooser! <br/> <br/> Note: Only the <u>Administrator</u> is able to manage profiles.</p>]]></string>
<string name="faq_answer_2"><![CDATA[<p>Once a profile is deleted:</p> <p><br></p> <p> <li> The profile cannot be recovered. </li> </p> <p> <li> Profile information such as name, photos, and progress will be permanently deleted. </li> </p> <p><br></p> <p>To delete a profile (excluding the <u>Administrator\'s</u>):</p> <p>1. From the Administrator\'s Home Page, tap on the menu button on the top left.</p> <p>2. Tap on <strong>Administrator Controls</strong>.</p> <p>3. Tap on <strong>Edit Profiles</strong>.</p> <p>4. Tap on the Profile you would like to delete.</p> <p>5. At the bottom of the screen, tap <strong>Profile Deletion</strong>.</p> <p>6. Tap <strong>Delete</strong> to confirm deletion.</p><p><br></p><p>Note: Only the <u>Administrator</u> is able to manage profiles.</p>]]></string>
<string name="faq_answer_3"><![CDATA[<p>To change your email/phone number:</p> <p>1. From the Administrator\'s Home Page, tap on the menu button on the top left.</p> <p>2. Tap on <strong>Administrator Controls</strong>.</p> <p>3. Tap on <strong>Edit Account</strong>.</p> <p><br></p> <p>If you want to change your email:</p> <p>4. Enter your new email and tap <strong>Save</strong>.</p> <p>5. A confirmation link is sent to confirm your new email. The link will expire after 24 hours and must be clicked on to be associated with your account. </p> <p><br></p> <p>If changing your phone number:</p> <p>4. Enter your new phone number and tap <strong>Verify</strong>.</p> <p>5. A code is sent to confirm your new number. The code will expire after 5 minutes and must be entered in the new screen to be associated with your account.</p>]]></string>
<string name="faq_answer_4"><![CDATA[<p>Oppia <i>\"O-pee-yah\"</i> (Finnish) - \"to learn\"</p><p><br></p><p>Oppia\'s mission is to help anyone learn anything they want in an effective and enjoyable way.</p><p><br></p><p>By creating a set of free, high-quality, demonstrably effective lessons with the help of educators from around the world, Oppia aims to provide students with quality education — regardless of where they are or what traditional resources they have access to.</p><p><br></p><p>As a student, you can begin your learning adventure by browsing the topics listed on the Home Page!</p>]]></string>
<string name="faq_answer_5"><![CDATA[<p>An Administrator is the main user that manages profiles and settings for every profile on their account. They are most likely your parent, teacher, or guardian that created this profile for you. </p><p><br></p><p>Administrators have the ability to manage profiles, assign PINs, and change other settings under their account. Depending on your profile, Administrator permissions may be required for certain features such as downloading Topics, changing your PIN, and more. </p><p><br></p><p>To see who your Administrator is, go to the Profile Chooser. The first profile listed and has \"Administrator\" written under their name is the Administrator. </p>]]></string>
<string name="faq_answer_6"><![CDATA[<p>If the Exploration Player is not loading</p><p><br></p><p>Check to see if the app is up to date:</p><p> <ol> <li> Go to the Play Store and make sure the app is updated to its latest version </li> </ol> </p><p><br></p><p>Check your internet connection:</p><p> <li> If your internet connection is slow, try re-connecting to your Wi-Fi network or connecting to a different network. </li> </p><p><br></p><p>Ask the Administrator to check their device and internet connection:</p><p> <li> Get the Administrator to troubleshoot using the steps above </li> </p><p><br></p><p>Let us know if you still have issues with loading:</p><p> <li> Report a problem by contacting us at [email protected]. </li> </p>]]></string>
<string name="faq_answer_7"><![CDATA[<p>If your audio is not playing</p><p><br></p><p>Check to see if the app is up to date:</p><p> <li> Go to the Play Store and make sure the app is updated to its latest version </li> </p><p><br></p><p>Check your internet connection:</p><p> <li> If your internet connection is slow, try re-connecting to your Wi-Fi network or connecting to a different network. Slow internet may cause the audio to load irregularly, making it difficult to play. </li> </p><p><br></p><p>Ask the Administrator to check their device and internet connection:</p><p> <li> Get the Administrator to troubleshoot using the steps above</li> </p><p><br></p><p>Let us know if you still have issues with loading:</p><p> <li> Report a problem by contacting us at [email protected]. </li></p>]]></string>
<string name="faq_answer_8"><![CDATA[<p>To download an Exploration:</p><p>1. From the Home Page, tap on a Topic or Exploration.</p><p>2. From that Topic Page, tap on the <strong>Info</strong> tab.</p><p>3. Tap on <strong>Download Topic</strong>. </p><p>4. Depending on your app settings, you may need Administrator approval or stable Wifi connection to complete your download. If needed, once these requirements are satisfied, the Topic has been downloaded onto the device and can be used offline by all profiles. <p>]]></string>
<string name="faq_answer_9"><![CDATA[<p>If you cannot find your question or would like to report a bug, contact us at [email protected].</p>]]></string>
<string-array name="faq_questions">
<item>@string/faq_question_1</item>
<item>@string/faq_question_2</item>
<item>@string/faq_question_3</item>
<item>@string/faq_question_4</item>
<item>@string/faq_question_5</item>
<item>@string/faq_question_6</item>
<item>@string/faq_question_7</item>
<item>@string/faq_question_8</item>
<item>@string/faq_question_9</item>
</string-array>

<string-array name="faq_answers">
<item>@string/faq_answer_1</item>
<item>@string/faq_answer_2</item>
<item>@string/faq_answer_3</item>
<item>@string/faq_answer_4</item>
<item>@string/faq_answer_5</item>
<item>@string/faq_answer_6</item>
<item>@string/faq_answer_7</item>
<item>@string/faq_answer_8</item>
<item>@string/faq_answer_9</item>
</string-array>
</resources>
Loading