While completing the Turkish translation (#1451) I ran the app with a non-English locale and found a set of small gaps where text bypasses the localisation and accessibility conventions this project already applies consistently elsewhere. Grouping them in one issue since each is a few lines; happy to split or send PRs for any subset.
1. Two enums render their name directly, so they stay English in every locale
The established pattern in core/data/Enums.kt is a @param:StringRes displayNameResId — used by GenderType:160, Limb:221, AmputationPart:228, TimeRangeFilter:450, AggregationLevel:462, SmoothingAlgorithm:551, PolynomialDegree:561 — or a getDisplayName(context) method (BackupInterval:582, BodyFatFormulaOption:655, …).
Two enums don't follow it and are printed raw:
ActivityLevel (Enums.kt:172-173), rendered at ui/screen/settings/UserDetailScreen.kt:417 and again at :435:
value = activityLevel.name.lowercase().replaceFirstChar { it.uppercaseChar().toString() }
InputFieldType (Enums.kt:437-444), rendered at ui/screen/settings/MeasurementTypeDetailScreen.kt:509 and :518
So the user profile shows "Sedentary"/"Mild"/… and the measurement-type editor shows "Float"/"Int"/"Text" regardless of language. The surrounding labels are localised (user_detail_label_activity_level, measurement_type_label_input_type) — only the values are stuck.
Fix would mirror GenderType exactly: 5 + 6 string resources and a constructor parameter.
(I asked about ActivityLevel in a comment on #1451; folding it in here so it's all in one place.)
2. contentDescription set to an identifier — screen readers announce internals
ui/screen/components/MeasurementIcon.kt:43 — contentDescription = icon.id.toString() → TalkBack reads a raw resource number, e.g. "2131165312"
ui/screen/components/MeasurementIcon.kt:51 — contentDescription = icon.imageVector.name → reads the Material vector name, e.g. "Filled.MonitorWeight"
ui/screen/overview/OverviewScreen.kt:1045 — contentDescription = trend.name → reads "UP"/"DOWN", untranslated
The correct pattern already exists in-repo for the same concept: ui/screen/statistics/StatisticsScreen.kt:318-322 maps up/down/no-change to statistics_content_desc_increase / _decrease / _no_change, and MeasurementDetailScreen.kt:699,702 uses stringResource(R.string.content_desc_increase_value, …).
3. Interactive controls with no accessible label
ui/navigation/AppNavigation.kt:441 and :447 — the user-switcher IconButton in the top bar. It has no text child, and both branches pass contentDescription = null, so it is announced as an unlabelled button. This one appears on every screen.
ui/screen/overview/OverviewScreen.kt:826 — IconButton(onClick = onEdit) with contentDescription = null. This looks like an oversight rather than a choice: the three sibling IconButtons in the same if/else (:836, :843, :853) all use action_delete_measurement_desc / action_edit_measurement_desc / action_show_less_desc. Only the aggregated branch was missed, and the string it needs already exists and already takes the headerLabel argument.
ui/screen/insights/InsightsScreen.kt:1056 — a full-width TextButton whose only child is an Icon with contentDescription = null. OverviewScreen.kt:853-857 does the identical show-more/show-less toggle correctly with action_show_less_desc / action_show_more_desc.
ui/screen/settings/MeasurementTypeDetailScreen.kt:694 — an Icon that is itself the tap target via .clickable { onInfo(opt) }, with no description.
For the avoidance of doubt: I checked the other ~38 contentDescription = null sites and they look correct — decorative dialog icons, leading icons on rows whose title is already a stringResource, empty-state illustrations paired with visible text, and the chart drag handle at MeasurementChart.kt:727-758 which sets the description on the container and nulls the child deliberately. Those shouldn't be touched.
Everything above is verified against the current master checkout. None of it needs any scale hardware, so I can send PRs for whichever of the three groups you'd want — separately or together.
While completing the Turkish translation (#1451) I ran the app with a non-English locale and found a set of small gaps where text bypasses the localisation and accessibility conventions this project already applies consistently elsewhere. Grouping them in one issue since each is a few lines; happy to split or send PRs for any subset.
1. Two enums render their
namedirectly, so they stay English in every localeThe established pattern in
core/data/Enums.ktis a@param:StringRes displayNameResId— used byGenderType:160,Limb:221,AmputationPart:228,TimeRangeFilter:450,AggregationLevel:462,SmoothingAlgorithm:551,PolynomialDegree:561— or agetDisplayName(context)method (BackupInterval:582,BodyFatFormulaOption:655, …).Two enums don't follow it and are printed raw:
ActivityLevel(Enums.kt:172-173), rendered atui/screen/settings/UserDetailScreen.kt:417and again at:435:value = activityLevel.name.lowercase().replaceFirstChar { it.uppercaseChar().toString() }InputFieldType(Enums.kt:437-444), rendered atui/screen/settings/MeasurementTypeDetailScreen.kt:509and:518So the user profile shows "Sedentary"/"Mild"/… and the measurement-type editor shows "Float"/"Int"/"Text" regardless of language. The surrounding labels are localised (
user_detail_label_activity_level,measurement_type_label_input_type) — only the values are stuck.Fix would mirror
GenderTypeexactly: 5 + 6 string resources and a constructor parameter.(I asked about
ActivityLevelin a comment on #1451; folding it in here so it's all in one place.)2.
contentDescriptionset to an identifier — screen readers announce internalsui/screen/components/MeasurementIcon.kt:43—contentDescription = icon.id.toString()→ TalkBack reads a raw resource number, e.g. "2131165312"ui/screen/components/MeasurementIcon.kt:51—contentDescription = icon.imageVector.name→ reads the Material vector name, e.g. "Filled.MonitorWeight"ui/screen/overview/OverviewScreen.kt:1045—contentDescription = trend.name→ reads "UP"/"DOWN", untranslatedThe correct pattern already exists in-repo for the same concept:
ui/screen/statistics/StatisticsScreen.kt:318-322maps up/down/no-change tostatistics_content_desc_increase/_decrease/_no_change, andMeasurementDetailScreen.kt:699,702usesstringResource(R.string.content_desc_increase_value, …).3. Interactive controls with no accessible label
ui/navigation/AppNavigation.kt:441and:447— the user-switcherIconButtonin the top bar. It has no text child, and both branches passcontentDescription = null, so it is announced as an unlabelled button. This one appears on every screen.ui/screen/overview/OverviewScreen.kt:826—IconButton(onClick = onEdit)withcontentDescription = null. This looks like an oversight rather than a choice: the three siblingIconButtons in the same if/else (:836,:843,:853) all useaction_delete_measurement_desc/action_edit_measurement_desc/action_show_less_desc. Only the aggregated branch was missed, and the string it needs already exists and already takes theheaderLabelargument.ui/screen/insights/InsightsScreen.kt:1056— a full-widthTextButtonwhose only child is anIconwithcontentDescription = null.OverviewScreen.kt:853-857does the identical show-more/show-less toggle correctly withaction_show_less_desc/action_show_more_desc.ui/screen/settings/MeasurementTypeDetailScreen.kt:694— anIconthat is itself the tap target via.clickable { onInfo(opt) }, with no description.For the avoidance of doubt: I checked the other ~38
contentDescription = nullsites and they look correct — decorative dialog icons, leading icons on rows whose title is already astringResource, empty-state illustrations paired with visible text, and the chart drag handle atMeasurementChart.kt:727-758which sets the description on the container and nulls the child deliberately. Those shouldn't be touched.Everything above is verified against the current
mastercheckout. None of it needs any scale hardware, so I can send PRs for whichever of the three groups you'd want — separately or together.