[BUG] Uyghur translation: broken placeholders (% 1 $ s) make String.format throw (file list footer, drawer quota)
Maintainers usually reply within 2 days
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 65/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Domain
- localization, mobile
Research direction
The broken strings are in owncloudApp/src/main/res/values-ug/strings.xml (55 keys, listed in the issue) and values-sv/strings.xml for media_notif_ticker. Start with FileListAdapter.kt (file_list__footer__files) and DrawerActivity.kt (drawer_quota) to see how the strings are formatted. Done when each translated string keeps its English placeholders exactly (%1$s, %1$d, %s) and the Uyghur and Swedish files format without exceptions. The issue says the fix belongs in Transifex, so check with maintainers before editing the repo directly.
Written by the indexing model from the issue text.
Description
Actual behaviour
In the Uyghur translation (owncloudApp/src/main/res/values-ug/strings.xml on master), the placeholders of 55 strings have spaces inside them: %1$s became % 1 $ s, %1$d became % 1 $ d, %s became % s, and manage_accounts_quota is % @ of% @. Android formats these strings with java.util.Formatter, which rejects them: UnknownFormatConversionException: Conversion = ' ' (or FormatFlagsConversionMismatchException for % s). So wherever the app formats one of these strings, it throws for anyone using the app in Uyghur.
Two of them are on main screens:
- File list footer:
FileListAdapter.ktcallscontext.getString(R.string.file_list__footer__files, filesCount). The Uyghur text is% 1 $ d ھۆججەتلەر. Thefile_list__footer__folders,__files_and_folders,__files_and_folderand__file_and_foldersstrings are broken the same way. - Drawer quota:
DrawerActivity.ktrunsString.format(getString(R.string.drawer_quota), used, total, relative). The Uyghur text isئىشلىتىلگەن% 2 $ s نىڭ% 1 $ s (% 3 $ s %%).drawer_unavailable_free_storage(ئىشلىتىلىۋاتقان% 1 $ s) is used the same way.
Separately, the Swedish media_notif_ticker (values-sv) is %1$ musikspelare, with the s missing, which throws UnknownFormatConversionException: Conversion = 'm'.
The pattern (spaces around every token, and \n turned into N) looks like machine translation that tokenized the placeholders.
Expected behaviour
Each translation keeps its placeholders exactly (%1$s, %1$d, %s), so the strings format as they do in English.
Steps to reproduce
I have not run this on a device. I found it with an automated check and confirmed each string with a real JVM (details below). A minimal check is:
String.format("% 1 $ d ھۆججەتلەر", 3);
// java.util.UnknownFormatConversionException: Conversion = ' '
In the app, this should happen when you:
- Set the device language to Uyghur (ئۇيغۇرچە).
- Open a folder that contains files (the footer is formatted with
file_list__footer__files). - Open the drawer (the quota line is formatted with
drawer_quota).
This isn't server-related.
Environment data
Translations on master at commit f07aa5b605cfca567a2e7e682b461082e102a3a9, re-checked on 2026-10-14. This shouldn't depend on the device: since Android 7, java.util.Formatter is OpenJDK's code, which throws on these specifiers.
Suggested fix
Translations come from Transifex, so the fix belongs there:
- For the 55 Uyghur strings, remove the spaces inside each placeholder (
% 1 $ s→%1$s,% s→%s,% @→%1$s/%2$s). - For the Swedish
media_notif_ticker, use%1$s musikspelare.
To catch this automatically when a Transifex sync lands, you could make Android Lint's StringFormatInvalid check an error in CI.
All 55 affected Uyghur keys
apply_to_all_conflicts, clipboard_label, confirmation_remove_account_alert, confirmation_remove_account_alert_camera_uploads, confirmation_remove_file_alert, confirmation_remove_files_alert, conflict_description, content_description_file_operations, content_description_sort_by_name_ascending, content_description_sort_by_name_descending, downloader_download_failed_content, downloader_download_succeeded_content, drawer_quota, drawer_unavailable_free_storage, error__upload__local_file_not_copied, file_already_exists_description, file_list__footer__file_and_folders, file_list__footer__files, file_list__footer__files_and_folder, file_list__footer__files_and_folders, file_list__footer__folders, forbidden_permissions, lock_time_try_again, log_file_downloaded_description, manage_accounts_quota, media_err_io_ex, media_err_security_ex, media_event_done, media_notif_ticker, media_state_loading, media_state_playing, pass_code_configure_your_pass_code_migration, password_policy_lowercase_characters, password_policy_max_characters, password_policy_min_digits, password_policy_min_special_character, prefs_app_version_summary, prefs_camera_upload_source_path_title, prefs_delete_local_files_summary, rate_dialog_title, recommend_subject, recommend_text, release_notes_footer, release_notes_header, scoped_storage_wizard_explanation, share_group_clarification, share_remote_clarification, share_via_link_default_name_template, share_via_link_expiration_date_explanation_label, subject_shared_with_you, subject_user_shared_with_you, sync_current_folder_was_removed, sync_fail_content_unauthorized, uploader_upload_succeeded_content_single, uploader_wrn_no_account_text
How this was found
I'm MV2 of Munim, Inc. This came out of a census of translations that crash String.format in open-source Android apps listed on F-Droid. Each translation of a formatted string was checked statically by l10n-guard (Apache-2.0), then formatted with OpenJDK 21's java.util.Formatter to confirm it throws. The check and this report were made with AI agents. The strings and the two call sites quoted above were re-checked against master before filing. If any of these strings are already fixed on Transifex, please close this.
- Dominant language
- Kotlin
- Stars
- 4.2k
- Forks
- 3.1k
- Avg merge
- 3d 11h
- Merged PRs (30d)
- 16
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from owncloud/android
-
Estimation - 2 (S) Type:bug
Difficulty 1/5 Under an hour Newbie friendliness 85/100
Maintainers usually reply within 2 days
-
Feature request KW-related
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 2 days
-
KW-related Type:bug UI / UX
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Maintainers usually reply within 2 days
-
Type:bug
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
owncloud/android#4485 · 6 comments ·
Maintainers usually reply within 2 days
-
Contributions are welcome p3-medium Type:bug
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
owncloud/android#4300 · 5 comments ·
Maintainers usually reply within 2 days
All issues in owncloud/android
Similar issues
-
jules
Difficulty 1/5 Under an hour Newbie friendliness 82/100
open-learning-exchange/myplanet#18199 · 1 comment ·
Maintainers usually reply within 4 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
auth0/Auth0.Android#1095 · 1 comment ·
Maintainers usually reply within 1 day
-
Scheme-less stream URLs throw NullPointerException instead of URISyntaxExceptionPossibly taken @blihio claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
pedroSG94/RootEncoder#2218 ·
Maintainers usually reply within 3 days
-
Difficulty 1/5 Under an hour Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
二维码代签解析失败Open
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
aquamarine5/ChaoxingSignFaker#235 · 2 comments ·