Je souhaite utiliser des pluriels pour mon projet Android. Cependant, les valeurs que je fournis peuvent être des valeurs flottantes.
Par exemple, lorsque vous définissez 1,5 étoiles, je veux que cela comprenne, ce n'est pas 1 étoile mais 1,5 étoile s .
String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs)
Cependant , le système Android semble n'utiliser que des valeurs entières (% d).
La méthode ressemble à ceci:
<plurals name="stars"> <item quantity="one">%d star</item> <item quantity="other">%d stars</item> </plurals>
où quantité strong> est défini comme Int
Y a-t-il une solution à cela?
3 Réponses :
Je dois d'abord dire: question très intéressante.
Deuxièmement, voici la solution: utilisez% s au lieu de% d pour votre espace réservé.
import android.content.res.Resources; import android.support.annotation.PluralsRes; public class PluralResource { public static String get(Resources resources, @PluralsRes int pluralResId, float pluralValue) { return resources.getQuantityString(pluralResId, (int) Math.ceil(pluralValue), pluralValue); } }
Ensuite, vous devez utiliser Math.ceil () code> sur votre quantité. Ainsi,
1.1f
par exemple deviendrait 2
et donc votre texte passerait d'étoile en étoile s .
J'ai écrit cette solution en Kotlin et Java.
Pour Kotlin, j'ai écrit une fonction d'extension qui ressemble à ceci:
fun Resources.getQuantityString(@PluralsRes pluralResId: Int, pluralValue: Float) = this.getQuantityString(R.plurals.stars, Math.ceil(pluralValue.toDouble()).toInt(), pluralValue)
Mais cela ne résout toujours pas tout le problème, à savoir que la quantité est une valeur flottante. Cela aide à imprimer une valeur flottante, mais la décision de savoir si 1.5 est "un" ou "autre" n'est pas résolue. Vous avez simplement ajouté 2 - donc "autre" sera utilisé. Mais qu'en est-il de 1,5? Si j'en fais un Int, cela prendra la quantité "une".
Dans mon édition, j'ai écrit que vous devriez arrondir votre nombre au prochain int. Vous pouvez le faire en utilisant la fonction ceil. Comme ceci: getResources (). GetQuantityString (R.plurals.stars, Math.ceil (1.2f), format.format (1.2f))
Je viens de retravailler ma réponse. J'espère que cela fonctionne maintenant comme vous vous attendez :)
Mais ceil (1.2f) n'indiquerait-il pas 1.1 à la place? Donc j'aurais "1,1 étoile". Je suppose qu'il faudrait une valeur == 1.0 vérifier avant. Mais là encore, cela rend les pluriels complètement inutiles, si je dois quand même obtenir la chaîne manuellement.
Non, vous n'avez pas besoin de vérifier spécifiquement 1.1f. Je viens de l'essayer et cela a bien fonctionné! J'ai de nouveau mis à jour ma réponse. J'ai amélioré ma solution Kotlin et Java. Essayez-le, il vous suffit de le copier et de le coller :) Si cela ne fonctionne pas comme prévu, faites-le moi savoir.
Vous pouvez remplacer tout le contenu de ceil par pluralValue> 1f? 2: 1
.
Vrai :) Tellement triste que l'opérateur ?
n'existe pas dans Kotlin
Pas sûr que nous puissions envisager de plafonner ou de remplacer quoi que ce soit> 1 par 2 comme une mise en œuvre fonctionnelle du pluriel pour toutes les langues. Certains sont très complexes, mais je n'ai absolument aucune idée d'une règle correcte pour les quantités flottantes unicode.org/cldr/charts/34/supplemental/…
Remplacer tout signe supérieur à 1 par 2 comme vous l'avez dit ressemble vraiment à la mauvaise approche lorsque vous regardez le lien que vous avez fourni. Mais est-ce la même chose pour le plafond? Prenons cet exemple: à partir de 5, un certain pluriel est utilisé. La valeur est de 4,2. Donc, le pluriel pour 5 et plus est utilisé. Je sais que vous avez dit que vous ne savez pas comment gérer les valeurs flottantes, mais pouvez-vous me dire si toutes les langues ont en commun qu'une valeur flottante utilisera la valeur entière la plus proche pour décider du pluriel à utiliser?
Faites simplement ceci:
getQuantityString(R.plurals.stars, quantity > 1f ? 2 : 1, quantity):
Et remplacez le% d dans vos chaînes par% f.
Cependant, je ne suis pas sûr que ce soit simplement cela. Il peut y avoir des langues qui ont des problèmes avec 2 ou 0. Par exemple, 0,5 étoile s est également différent de "pas d'étoile" d'avoir une quantité de 0.
C'est vrai. Cependant, je pense que le point est que le paramètre quantité
de getQuantityString () est mappé aux valeurs de l'attribut quantité
des éléments pluriels ("zéro", "un "," other "), les plus formatArgs
sont utilisés pour le ou les espaces réservés dans les chaînes elles-mêmes. Au lieu de mon exemple simple, vous pouvez également créer une méthode distincte qui mappe le flottant donné à un int représentant "zéro", "un", "autre" ... mais vous pouvez toujours utiliser la valeur flottante d'origine comme dans formatArgs.
Eh bien, l'idée était d'éviter la séparation manuelle. Si je dois les traiter "manuellement" de toute façon, je peux simplement créer des ressources String et faire la logique moi-même. Il n'y a donc aucune utilité réelle à utiliser des pluriels en premier lieu. Mais merci pour la suggestion.
Après des recherches plus poussées, il semble qu'il n'y a pas de bonne solution pour cela .
Comme on le voit également dans les autres réponses, elles nécessitent toujours beaucoup de "traitement manuel" ne nécessitant pas flux de travail différent de celui de créer des ressources de chaîne séparées.
La suggestion générale semble être d'arrondir / traiter les valeurs flottantes manuellement (par exemple vérifier si la valeur flottante correspond à 1.0) et ensuite d'utiliser des valeurs Int appropriées pour l'appel pluriel.
Mais à part le fait de ne pas vraiment utiliser de pluriel, cela vient avec le problème d'autres langues (par exemple, je n'ai aucune idée si 1,5 étoiles serait également pluriel dans une autre langue comme en anglais) et donc ces options d'arrondi peut ne pas s'appliquer universellement.
La réponse est donc: il ne semble pas y avoir de solution parfaite (c'est-à-dire résolue "automatiquement" par le système Android).
Ce que je fais en fait, c'est donc de choisissez simplement des exceptions et utilisez-y différentes chaînes. Donc, la façon de faire (pseudo-code) ressemble actuellement à
// optionally wrap different languages around // if language == English when (amountStars) { is 1.0 -> getString(R.string.stars_singular, 1) ... -> else -> getString(R.string.stars_plural, amountStars) } // if language == Chinese ...
où des cas supplémentaires doivent être "codés en dur". Par exemple, vous devez décider si 0 signifie
" 0 étoile s " (chaîne plurielle) ou
" no star "(chaîne au singulier)
Mais il ne semble pas vraiment avantageux d'utiliser des pluriels sur des ressources de chaîne séparées avec des espaces réservés communs. D'un autre côté, cela ( enfin pour moi) donne plus de flexibilité pour les options de formatage. Par exemple, on peut créer un texte comme "1 étoile et demie" où il redevient singulier (même si numériquement on écrirait 1,5 étoile).
Je pense qu'en fin de compte, vous devez passer un
int
pour ne pouvoir passer que la partieint
de la note et cela sera couvert dansother
. Ou peut-être que je n'ai pas compris la question.