Repository navigation
Conversation
Every end-user string of the board, the feedback form, My requests and
the conversation screens now resolves from the library's string
resources: values/strings.xml (English, the default) and a complete
values-it/strings.xml. The screens follow the host app's locale,
per-app language included, and fall back to English.
- Every resource name is prefixed feedbackthread_: library resources
merge into the host app, where an unprefixed name would be overridden
by one of the app's own.
- FeedbackThreadText (internal) carries copy produced outside
composition - catch blocks, the status label, enum titles - as a
resource reference or verbatim text, resolved in composition.
- The board's empty filter states are one whole sentence per filter
instead of a lowercased status interpolated into "No ... requests",
and the vote button's description is a proper plural ("Vote, 1 vote").
Deliberately not localized:
- Wire strings. feedbackThreadRequestStage() and its status match
strings, serialized names, URL paths, headers and the persisted voter
key are untouched, byte for byte.
- Public API. FeedbackThreadFeedbackKind.title stays an English String
beside a new internal localizedTitle. Exception messages stay English
for integrators; the end-user copy the SDK writes (unreachable,
unreadable response or settings, the HTTP-status fallback) is tagged
internally and the screens show it localized. The two values
FeedbackThreadConversations writes to FeedbackThreadConversationState
.error become internal constants the host shows localized. A
binary-compatibility-validator dump is identical before and after.
- InvalidConfiguration messages, messages the API writes, and statuses
the SDK doesn't recognize, which stay verbatim.
Tests: a localization suite that discovers every values-*/strings.xml
and checks prefix, completeness, placeholders, plurals and apostrophes;
status labels asserted against the resources (English unchanged, exact
Italian); error tagging and its display mapping; the conversation error
mapping. The wire-mapping and section-bucketing tests are unchanged.
The unit test task declares src/main/res as an input, so a
translation-only edit doesn't leave it up to date.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2.
The Android counterpart of aivars/feedbackthread-swift#5. The SDK's Compose UI — the board, the feedback form, My requests and the 0.5.0 conversation screens — now reads its copy from the library's string resources: English as the default, plus a complete Italian translation. The screens follow the host app's locale, per-app language included, and fall back to English for any other language, so apps that only ship English see no change.
What's in the change
res/values/strings.xml+res/values-it/strings.xml: new; the module had nores/before. They hold 86 strings and 3 plurals, each with a translator comment. Every name is prefixedfeedbackthread_. A library's resources are merged into the host app, and the app's own resource of the same name wins. An unprefixeddonewould quietly pick up whatever the app means bydone. That is the Android version of the bundle-misrouting problem on iOS, and a test enforces the prefix.FeedbackThreadText(new, internal): a small value type that is either a string resource with its arguments or verbatim text. Much of the copy is produced outside composition: catch blocks in launched coroutines, the status label function, enum titles. That code now carries a reference, and composition resolves it. Copy that is always SDK-authored travels as a plain@StringRes Int.feedbackThreadRequestLabel()maps each known stage to its resource. An unrecognised status keeps the existingsensiblyCapitalized()passthrough, verbatim."No … requests", which no other language can inflect. This is the same call the Swift PR made.FeedbackThreadFeedbackKind.titlestill returns its EnglishString. The form uses a new internallocalizedTitlebeside it.## Unreleasedentry in the CHANGELOG, and the README sentence calling conversation localization "a release check" updated.Guarantees
feedbackThreadRequestStage()is byte-identical, and its match strings ("Submitted", "In review", "In progress", "Ready to release", …) were left alone even where a label reads the same. Separating them was done by hand, as CONTRIBUTING asks. The same holds for serialized names, URL paths, headers, and the persisted voter-identity key. The other wire values the screens compare against, the"private"/"public"audience and the"developer"author role, are untouched too.mapsKnownStatusesToTheirPublicBoardStageandbucketsEveryStageIntoExactlyOneMyRequestsSectionare unchanged and green as the regression net.apiDumponmainand on this branch, and the two dumps are identical. (Kotlininternalcompiles to JVM-public, so ajavapdiff would not prove this.)Judgement calls
FeedbackThreadException.messageis public API that integrators read and log. The Swift SDK localized itserrorDescription, but on Android the transport has noContextto resolve resources from. So the throw sites that write end-user copy tag the exception internally: unreachable, unreadable response, unreadable conversation settings, and the HTTP-status fallback with its code. The drop-in screens show the tag's localized text. Themessagestays exactly what it was. No constructor or signature changed: the tag is an internal@Transientproperty on the sealed base class.InvalidConfigurationmessages, which address the integrator wiring the SDK up, as CONTRIBUTING says;FeedbackThreadConversationState.erroris a publicString, so it keeps its English values. The two messagesFeedbackThreadConversationswrites there are now internal constants.FeedbackThreadConversationHostrecognises exactly those two and shows them localized, and shows any other value as written. A typed error field on the state would be cleaner, but it would mean a public API addition, so I left that to you.build.gradle.ktsgets one small change:testOptions.unitTests.all { it.inputs.dir("src/main/res") }. The localization tests readsrc/main/resdirectly. Without declaring it as an input, an edit that only touches a translation leavestestDebugUnitTestUP-TO-DATE locally, a stale green. CI starts clean, so CI isn't affected. Happy to drop it if you'd rather not touch the build file.res/. I left that out of the README so the resource names don't become a de facto public API. Your call whether to promise it.Tests
42 tests on
main→ 66 on this branch, all green.FeedbackThreadLocalizationTestfinds everyvalues-*/strings.xmlon its own, so adding a language needs no test change. For every language it checks:R.string/R.pluralsentry exists in every file.Status label tests, rewritten. They assert the resource each status maps to, and that its English value is exactly the pre-change label, so the English demonstrably did not move. They also assert exact Italian ("In attesa di revisione", "Rifiutata"), and that an unknown status stays a verbatim passthrough.
Client tests, for:
IOExceptioninsubmit,InvalidConfiguration.Each asserts both that the exception message is unchanged English and that the screen's display text is the expected resource or verbatim text.
Display-mapping and conversation-error tests, for
FeedbackThreadTextand the conversation-error mapping.Italian translation notes
Wherever the copy exists in both SDKs, the Italian is the Swift SDK's catalog wording verbatim, so the two platforms read the same. For example: Richieste di funzionalità, In attesa di revisione, Pianificata / Completata / Rifiutata, ✓ Rilasciata nella versione 2.4.0, Le mie richieste, plural section headers Rilasciate / Chiuse.
Status labels stay feminine because they qualify richiesta. Copy that exists only on Android is translated fresh: the conversation screens, the board's empty state, the form's confirmations. The Swift conversation views aren't localized yet, so they had no wording to reuse. Happy to adjust any of it.
Verification
./gradlew :feedbackthread:testDebugUnitTest :feedbackthread:assembleDebug: green.:feedbackthread:lintDebug: no localization findings (MissingTranslation, StringFormat*, plurals).example/builds against the branch, andaapt2 dumpof its APK shows the SDK strings merged with both the default and theitvalues.en-USand thenit-IT, through the board, the filters and their empty states, a request's detail, My requests, the form and its confirmation, and the load-failed state. The Italian screens show no leftover English apart from server content and the example's own tab labels. TalkBack reads the vote button as "Vote, 1 vote" / "Vota, 1 voto". The longest new string, "✓ Rilasciata nella versione 2.4.0", fits at the default font size.Not in this change
requests(),setVote(),myRequests(),myUpdates()andacknowledgeUpdates()don't wrap anIOExceptionthe waysubmit()does. So an offline board shows the platform's own message, e.g. "Unable to resolve host …", which is English and not SDK-authored. Wrapping them inInvalidResponsewould let that case read in the user's language too, but it changes which exception type public functions throw, so it belongs in its own PR. I'm happy to send one.Adding a language from here is one new
values-xx/strings.xml.