9

I have a Jetpack Compose app that uses stringResource everywhere and it works great for localization.

But, I have a few functions that are no Composable Functions and I would like to retrieve the string from the resources. When I try to use stringResource in those functions it tells me it can only be used in a composable.

So, how do I get a string from a resource if I am not a composable function?

z.g.y
  • 5,512
  • 4
  • 10
  • 36
LilMoke
  • 3,176
  • 7
  • 48
  • 88
  • Something like `context.resources.getString(R.string.myString)` – Gabriele Mariotti Oct 12 '22 at 15:17
  • Yes, but how do I get context in a non-composable – LilMoke Oct 12 '22 at 15:19
  • Just passing it as a parameter for example. – Gabriele Mariotti Oct 12 '22 at 15:21
  • Yes, but the calling function is not a composable either so I cannot get the context. Actually I have a class and I am calling a utility function to get me the string, but the utility function is a composable so I cannot call it from the class. I guess I could pass the context to the class, but it all seems messy. – LilMoke Oct 12 '22 at 15:23

1 Answers1

6

Not sure if I understand it correctly, but is it like this?

@Composable
fun Composable() {

    val context = LocalContext.current
    val someString = NonComposable(context)
}

fun NonComposable(context: Context): String =
    context.resources.getString(R.string.app_name)

Recommendation: You can also define a sealed class that has 2 types where you can supply your intended string parameter, an actual String value and a String resource where you can specify how they're going to be resolved.

UiText

sealed class UiText {

data class StringValue(val str: String): UiText()

class StringResource(
    @StringRes val resourceId: Int,
    vararg val args: Any
): UiText()

@Composable
fun asString(): String {
    return when (this) {
        is StringValue -> {
            str
        }
        is StringResource -> {
            stringResource(id = resourceId, formatArgs = args)
        }
    }
}

Sample usage scope:

Inside your ViewModel where you can simply supply the id of the string resource

var stringResourceVariable = UiText.StringResource(R.string.some_string_resource)

Then in your Composable

viewModel.stringResourceVariable.asString()

you can simply invoke asString and it will be resolved depending on what type of UiText string you supplied.

The benefit of having this approach, is you won't have any problems supplying string resources in your ViewModel.

z.g.y
  • 5,512
  • 4
  • 10
  • 36
  • Yes, and that is what I am doing now. I just did not have the context in the non-composable becuase it was called from another non-composable. SO, I added the var and pass it all the way through. I guess I was looking for a way to not have to pas the context everywhere. Thanks for the reply in any case. – LilMoke Oct 12 '22 at 16:44