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

String resources for internationalization (i18n) #425

Closed
keturn opened this issue Feb 25, 2021 · 15 comments · Fixed by #4519
Closed

String resources for internationalization (i18n) #425

keturn opened this issue Feb 25, 2021 · 15 comments · Fixed by #4519

Comments

@keturn
Copy link

keturn commented Feb 25, 2021

I'd like to see an example of how to do internationalization for Compose Desktop.

I looked at the Code Viewer example, as it's written to run under both Android and desktop. It doesn't yet address that feature; its Text widgets and contentDescription values are hard-coded, e.g. https://github.com/JetBrains/compose-jb/blob/4de10a649910053ed634429b88c82541989bf332/examples/codeviewer/common/src/commonMain/kotlin/org/jetbrains/codeviewer/ui/editor/EditorEmptyView.kt#L28-L29

Can we use stringResource (from androidx.compose.ui.res) on desktop? How do we get the resource ID if we're developing for desktop and not using Android Studio?

@olonho
Copy link
Contributor

olonho commented Feb 26, 2021

Image viewer example has some code for localization.

@keturn
Copy link
Author

keturn commented Feb 27, 2021

Where does R.kt come from?

How does it handle plurals?

Image viewer has a common subproject but then it splits much of its code out in to separate implementations for Android https://github.com/JetBrains/compose-jb/blob/da611b319dfa9cb0141d60ad5687b1771854ec72/examples/imageviewer/common/src/androidMain/kotlin/example/imageviewer/view/MainScreen.kt#L202-L210

and desktop https://github.com/JetBrains/compose-jb/blob/da611b319dfa9cb0141d60ad5687b1771854ec72/examples/imageviewer/common/src/desktopMain/kotlin/example/imageviewer/view/MainScreen.kt#L244-L251

Those look like they're supposed to be doing the same job, but the way they use string resources is entirely different. Can we write a view that will work in either environment?

@olonho olonho added the discussion Need further discussion to understand if it actually needed label Mar 5, 2021
@olonho
Copy link
Contributor

olonho commented Mar 5, 2021

Generally, while meaningful, not sure if it fully belongs to the UI framework scope.

@olonho
Copy link
Contributor

olonho commented Mar 5, 2021

@igordmn do you have an idea how we could support in MPP manner?

@igordmn
Copy link
Collaborator

igordmn commented Mar 5, 2021

One of the complex things is pluraziation support.

Java only provides ChoiceFormat, which properly works only with some languages.

Proper pluraziation support implemented in ICU.

We can provide a function for pluralization in skiko (because skia already uses icu library).

Or write a pluralization function in pure Kotlin/Java using patterns (example)

Another thing we need to think about - how string resources should be defined:

  1. We can write strings in pure Kotlin:
val strings = when(Locale.getDefault().language) {
    "en" -> EnStrings
    "ru" -> RuStrings
    else -> EnStrings
}

interface Strings {
    val appName: String get() = "Image viewer"
    val open: String
    fun folderFileCount(count: Int): String
}

object EnStrings : Strings {
    override val open = "Open"
    override fun folderFileCount(count: Int) = "Folder file count: ${fileCount(count)}"

    private fun fileCount(count: Int) = plural(
        count,
        zero = "$count files",
        one = "$count file",
        many = "$count files"
    )
}

object RuStrings : Strings {
    override val open = "Открыть"
    override fun folderFileCount(count: Int) = "Количество файлов в папке: ${fileCount(count)}"

    private fun fileCount(count: Int) = plural(
        count,
        zero = "$count файлов",
        one = "$count файл",
        many = "$count файлов"
    )
}

Don't know if it is a good idea. It maybe convinient for string formatting, but not convinient for translators.

  1. Provide android-like strings.xml. There is MPP implementation Moko resources. But support for JVM target isn't implemented yet. There is PR, but for plurals it uses ChoiceFormat.

@keturn
Copy link
Author

keturn commented Mar 5, 2021

It maybe convinient for string formatting, but not convinient for translators.

Yeah. Assume translators and their tools don't know Kotlin at all. Best to have a format that makes it super clear which things are strings to be translated and which aren't.

Using one of the web translation portals or other Computer Assisted Translation tools is going to want to parse it in to something like

  • string in the source language
  • a comment from the author about the string (if they need to provide extra context or explanation)
  • a previous translation of the string (when updating a previously-translated application)
  • the new translation of the string, i.e. the translator's input

A good translation house is used to taking all sorts of inputs and munging them in to something that will work but you'll have more options (and cheaper ones) if you can use an existing format. Especially when you take escaping rules in to account: java .properties and Android's strings.xml have their own peculiar rules about which characters need to be escaped and how, how replacement strings like ${count} are marked, etc.

Generally, while meaningful, not sure if it fully belongs to the UI framework scope.

One question that might help clarify this: Is it a goal to be able to share views like that MainScreen.kt between android and Compose for Desktop?

Or are Compose for Desktop apps really their own thing? Sometimes you might get lucky and be able to use some android-compatible component (because that's one of the benefits of composability), but you expect a desktop app to be written as a desktop app.

I've been more of a desktop dev than a mobile one, but my hunch is that if you want to pitch this as a way to take a design you've written for an Android tablet and use it on a Windows or Wayland touchscreen (or vice-versa), then views will need to be compatible with android's string resources.

(As a desktop dev, android support is of secondary importance to me. But android's i18n tools look far more capable than what we've seen from the JDK, as igordmn pointed out with ChoiceFormat. So when I saw this project talking about bringing androidx.compose APIs to the desktop, I was very keen to know if that included things like androidx.compose.ui.res too.)

@nrobi144
Copy link

@igordmn would migrating to PluralRules or PluralFormat from ChoiceFormat on the Moko-Resources side fix your issue?

@igordmn
Copy link
Collaborator

igordmn commented Mar 11, 2021

@igordmn would migrating to PluralRules or PluralFormat from ChoiceFormat on the Moko-Resources side fix your issue?

Yes, I think that will fix the issue. Thanks 👍!

@nrobi144
Copy link

@igordmn, @keturn just migrated Moko-Resources from ChoiceFormat to PluralRules -> icerockdev/moko-resources@97489b6

@kazemcodes
Copy link

moko-resource is good but there is some issue with cache configuration issue , if it was created using ksp then it would be amazing

@MarcusWolschon
Copy link

One question that might help clarify this: Is it a goal to be able to share views like that MainScreen.kt between android and Compose for Desktop?

Most certainly YES.
That's what I already do and without localization it already works well.
So many more possibilities when you get a desktop application nearly for free while developing the Android app.

@igordmn igordmn added commonization multiplatform resources and removed discussion Need further discussion to understand if it actually needed desktop labels Sep 15, 2023
@francismariano
Copy link

This feature is very important for KMP ecosystem. There are others libraries with that goal but they generally have issues with kotlin and/or compose-multiplatform updates.

@tsuyosh
Copy link

tsuyosh commented Feb 14, 2024

Is there any plan to support plural in the new resource library?

terrakok added a commit that referenced this issue Mar 25, 2024
Ports a part of Unicode's ICU in pure Kotlin and implements
Android-style plural string resource support. Fixes
#425.

# Changes

- Added `org.jetbrains.compose.resources.intl.{PluralCategory,
PluralRule, PluralRuleList}`, which parses and evaluates scripts in
Unicode's Locale Data Markup Langauge.
- Copied `plurals.xml` from Unicode's
[CLDR](https://github.com/unicode-org/cldr/blob/release-44-1/common/supplemental/plurals.xml).
- Added `GeneratePluralRuleListsTask`, which parses `plurals.xml` and
generates required Kotlin source codes.
- Added `PluralStringResource`, `pluralStringResource`, or
`getPluralString`, corresponding to `StringResource`, `stringResource`,
or `getString`.
- Modified `ResourcesSpec.kt` so the generated `Res` class exposes
`Res.plurals`.

# Potential Further Improvements

- [ ] Allow configuring the default language in the `compose.resources
{}` block (#4482) to determine the default pluralization rule (or just
presume English as default)
- [ ] Move the parser logic to the Gradle plugin and generate
pluralization rules in `Res` only for languages used in
`composeResources`

---------

Co-authored-by: Konstantin Tskhovrebov <konstantin.tskhovrebov@jetbrains.com>
@okushnikov
Copy link

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.