Skip to content

Commit d918d2f

Browse files
authored
Merge pull request #14 from icerockdev/develop
release 0.5.0
2 parents 327eef8 + bffb474 commit d918d2f

16 files changed

Lines changed: 141 additions & 141 deletions

File tree

README.md

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
![moko-resources](img/logo.png)
2-
[![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0) [![Download](https://api.bintray.com/packages/icerockdev/moko/moko-resources/images/download.svg) ](https://bintray.com/icerockdev/moko/moko-resources/_latestVersion) ![kotlin-version](https://img.shields.io/badge/kotlin-1.3.50-orange)
2+
[![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0) [![Download](https://api.bintray.com/packages/icerockdev/moko/moko-resources/images/download.svg) ](https://bintray.com/icerockdev/moko/moko-resources/_latestVersion) ![kotlin-version](https://img.shields.io/badge/kotlin-1.3.60-orange)
33

44
# Mobile Kotlin resources
55
This is a Kotlin MultiPlatform library that provides access to the resources on iOS & Android with the support of the default system localization.
@@ -21,7 +21,7 @@ This is a Kotlin MultiPlatform library that provides access to the resources on
2121

2222
## Requirements
2323
- Gradle version 5.4.1+
24-
- Android API 21+
24+
- Android API 16+
2525
- iOS version 9.0+
2626

2727
## Versions
@@ -30,6 +30,8 @@ This is a Kotlin MultiPlatform library that provides access to the resources on
3030
- 0.2.0
3131
- 0.3.0
3232
- 0.4.0
33+
- kotlin 1.3.60
34+
- 0.5.0
3335

3436
## Installation
3537
root build.gradle
@@ -40,7 +42,7 @@ buildscript {
4042
}
4143
4244
dependencies {
43-
classpath "dev.icerock.moko:resources-generator:0.4.0"
45+
classpath "dev.icerock.moko:resources-generator:0.5.0"
4446
}
4547
}
4648
@@ -57,7 +59,7 @@ project build.gradle
5759
apply plugin: "dev.icerock.mobile.multiplatform-resources"
5860
5961
dependencies {
60-
commonMainApi("dev.icerock.moko:resources:0.4.0")
62+
commonMainApi("dev.icerock.moko:resources:0.5.0")
6163
}
6264
6365
multiplatformResources {
@@ -70,16 +72,6 @@ settings.gradle
7072
enableFeaturePreview("GRADLE_METADATA")
7173
```
7274

73-
On iOS, in addition to the Kotlin library add Pod in the Podfile.
74-
```ruby
75-
pod 'MultiPlatformLibraryResources', :git => 'https://github.com/icerockdev/moko-resources.git', :tag => 'release/0.4.0'
76-
```
77-
**`MultiPlatformLibraryResources` CocoaPod requires that the framework compiled from Kotlin be named
78-
`MultiPlatformLibrary` and be connected as a CocoaPod `MultiPlatformLibrary`.
79-
[Here](sample/ios-app/Podfile)'s an example.
80-
To simplify integration with MultiPlatformFramework you can use [mobile-multiplatform-plugin](https://github.com/icerockdev/mobile-multiplatform-gradle-plugin)**.
81-
`MultiPlatformLibraryResources` CocoaPod contains an extension `localized` for `StringDesc`.
82-
8375
## Usage
8476
### Example 1 - simple localization string
8577
The first step is a create a file `strings.xml` in `commonMain/resources/MR/base` with the following content:

buildSrc/build.gradle.kts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ repositories {
1212
}
1313

1414
dependencies {
15-
implementation("dev.icerock:mobile-multiplatform:0.3.0")
16-
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.50")
17-
implementation("com.android.tools.build:gradle:3.5.0")
15+
implementation("dev.icerock:mobile-multiplatform:0.4.0")
16+
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.60")
17+
implementation("com.android.tools.build:gradle:3.5.2")
1818
}
1919

2020
kotlinDslPluginOptions {

buildSrc/src/main/kotlin/Deps.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ object Deps {
88
"com.android.tools.build:gradle:${Versions.Plugins.android}"
99
const val kotlin =
1010
"org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.Plugins.kotlin}"
11-
const val androidExtensions =
12-
"org.jetbrains.kotlin:kotlin-android-extensions:${Versions.Plugins.androidExtensions}"
1311
const val mokoResources =
1412
"dev.icerock.moko:resources-generator:${Versions.Plugins.mokoResources}"
1513
}
@@ -47,7 +45,6 @@ object Deps {
4745
"org.jetbrains.kotlin.multiplatform" to Plugins.kotlin,
4846
"kotlin-kapt" to Plugins.kotlin,
4947
"kotlin-android" to Plugins.kotlin,
50-
"kotlin-android-extensions" to Plugins.androidExtensions,
5148
"dev.icerock.mobile.multiplatform-resources" to Plugins.mokoResources
5249
)
5350
}

buildSrc/src/main/kotlin/Versions.kt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,23 @@ object Versions {
66
object Android {
77
const val compileSdk = 28
88
const val targetSdk = 28
9-
const val minSdk = 21
9+
const val minSdk = 16
1010
}
1111

12-
const val kotlin = "1.3.50"
12+
const val kotlin = "1.3.60"
1313

14-
private const val mokoResources = "0.4.0"
14+
private const val mokoResources = "0.5.0"
1515

1616
object Plugins {
17-
const val android = "3.4.1"
17+
const val android = "3.5.2"
1818

1919
const val kotlin = Versions.kotlin
20-
const val androidExtensions = Versions.kotlin
2120
const val mokoResources = Versions.mokoResources
2221
}
2322

2423
object Libs {
2524
object Android {
26-
const val appCompat = "1.0.2"
25+
const val appCompat = "1.1.0"
2726
}
2827

2928
object MultiPlatform {

gradle-plugin/src/main/kotlin/dev/icerock/gradle/generator/CommonMRGenerator.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@ class CommonMRGenerator(
2929

3030
project.tasks
3131
.mapNotNull { it as? KotlinNativeLink }
32-
.forEach { it.dependsOn(generationTask) }
32+
.forEach { it.compilation.compileKotlinTask.dependsOn(generationTask) }
3333
}
3434
}

gradle-plugin/src/main/kotlin/dev/icerock/gradle/generator/IosMRGenerator.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class IosMRGenerator(
6060
.filter { it.compilation.kotlinSourceSets.contains(sourceSet) }
6161

6262
linkTasks.forEach { linkTask ->
63-
linkTask.dependsOn(generationTask)
63+
linkTask.compilation.compileKotlinTask.dependsOn(generationTask)
6464

6565
val framework = linkTask.binary as? Framework ?: return@forEach
6666

gradle.properties

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,4 @@ org.gradle.parallel=true
55
kotlin.code.style=official
66

77
android.useAndroidX=true
8-
android.enableJetifier=true
9-
android.databinding.enableV2=true
8+
android.enableJetifier=true

resources/build.gradle.kts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
plugins {
66
id("com.android.library")
77
id("org.jetbrains.kotlin.multiplatform")
8-
id("kotlin-android-extensions")
98
id("dev.icerock.mobile.multiplatform")
109
id("maven-publish")
1110
}
@@ -22,10 +21,6 @@ android {
2221
}
2322
}
2423

25-
androidExtensions {
26-
isExperimental = true
27-
}
28-
2924
dependencies {
3025
mppLibrary(Deps.Libs.MultiPlatform.kotlinStdLib)
3126

@@ -42,3 +37,13 @@ publishing {
4237
}
4338
}
4439
}
40+
41+
kotlin {
42+
targets.filterIsInstance<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget>().forEach { target ->
43+
target.compilations.getByName("main") {
44+
val pluralizedString by cinterops.creating {
45+
defFile(project.file("src/iosMain/def/pluralizedString.def"))
46+
}
47+
}
48+
}
49+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
language = Objective-C
2+
package = dev.icerock.moko.resources.objc
3+
---
4+
#import <Foundation/NSString.h>
5+
#import <Foundation/NSBundle.h>
6+
7+
NSString* pluralizedString(NSBundle* bundle, NSString* resourceId, int number) {
8+
NSString* localized = [bundle localizedStringForKey: resourceId value: nil table: nil];
9+
return [NSString localizedStringWithFormat:localized, number];
10+
}

resources/src/iosMain/kotlin/dev/icerock/moko/resources/desc/StringDesc.kt

Lines changed: 90 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ package dev.icerock.moko.resources.desc
66

77
import dev.icerock.moko.resources.PluralsResource
88
import dev.icerock.moko.resources.StringResource
9+
import dev.icerock.moko.resources.objc.pluralizedString
10+
import platform.Foundation.NSString
11+
import platform.Foundation.stringWithFormat
912

1013
actual sealed class StringDesc {
1114
actual data class Resource actual constructor(val stringRes: StringResource) : StringDesc() {
12-
override fun toLocalizedString(formatter: Formatter): String {
15+
override fun localized(): String {
1316
return stringRes.bundle.localizedStringForKey(stringRes.resourceId, null, null)
1417
}
1518
}
@@ -18,21 +21,26 @@ actual sealed class StringDesc {
1821
val stringRes: StringResource,
1922
val args: List<Any>
2023
) : StringDesc() {
21-
override fun toLocalizedString(formatter: Formatter): String {
22-
val string = stringRes.bundle.localizedStringForKey(stringRes.resourceId, null, null)
23-
return formatter.formatString(string, args.toTypedArray())
24-
}
25-
2624
actual constructor(stringRes: StringResource, vararg args: Any) : this(
2725
stringRes,
2826
args.toList()
2927
)
28+
29+
override fun localized(): String {
30+
val string = stringRes.bundle.localizedStringForKey(stringRes.resourceId, null, null)
31+
return stringWithFormat(string, args.toTypedArray())
32+
}
3033
}
3134

3235
actual data class Plural actual constructor(val pluralsRes: PluralsResource, val number: Int) :
3336
StringDesc() {
34-
override fun toLocalizedString(formatter: Formatter): String {
35-
return formatter.plural(pluralsRes, number)
37+
38+
override fun localized(): String {
39+
return pluralizedString(
40+
bundle = pluralsRes.bundle,
41+
resourceId = pluralsRes.resourceId,
42+
number = number
43+
)!!
3644
}
3745
}
3846

@@ -41,41 +49,96 @@ actual sealed class StringDesc {
4149
val number: Int,
4250
val args: List<Any>
4351
) : StringDesc() {
44-
override fun toLocalizedString(formatter: Formatter): String {
45-
return formatter.formatPlural(pluralsRes, number, args.toTypedArray())
46-
}
4752

4853
actual constructor(pluralsRes: PluralsResource, number: Int, vararg args: Any) : this(
4954
pluralsRes,
5055
number,
5156
args.toList()
5257
)
58+
59+
override fun localized(): String {
60+
val pluralized = pluralizedString(
61+
bundle = pluralsRes.bundle,
62+
resourceId = pluralsRes.resourceId,
63+
number = number
64+
)!!
65+
return stringWithFormat(pluralized, args.toTypedArray())
66+
}
5367
}
5468

5569
actual data class Raw actual constructor(val string: String) : StringDesc() {
56-
override fun toLocalizedString(formatter: Formatter): String {
70+
71+
override fun localized(): String {
5772
return string
5873
}
5974
}
6075

61-
actual data class Composition actual constructor(val args: List<StringDesc>, val separator: String?) : StringDesc() {
62-
override fun toLocalizedString(formatter: Formatter): String {
63-
return StringBuilder().apply {
64-
args.forEachIndexed { index, stringDesc ->
65-
if(index != 0 && separator != null) {
66-
append(separator)
67-
}
68-
append(stringDesc.toLocalizedString(formatter))
69-
}
70-
}.toString()
76+
actual data class Composition actual constructor(
77+
val args: List<StringDesc>,
78+
val separator: String?
79+
) : StringDesc() {
80+
override fun localized(): String {
81+
return args.joinToString(separator = separator ?: "") { it.localized() }
7182
}
7283
}
7384

74-
abstract fun toLocalizedString(formatter: Formatter): String
85+
abstract fun localized(): String
7586

76-
interface Formatter {
77-
fun formatString(string: String, args: Array<out Any>): String
78-
fun plural(resource: PluralsResource, number: Int): String
79-
fun formatPlural(resource: PluralsResource, number: Int, args: Array<out Any>): String
87+
protected fun stringWithFormat(format: String, args: Array<out Any>): String {
88+
// NSString format works with NSObjects via %@, we should change standard format to %@
89+
val objcFormat = format.replace(Regex("%[\\.|\\d]*[a|b|c|d|e|f|s]"), "%@")
90+
// bad but objc interop limited :(
91+
// When calling variadic C functions spread operator is supported only for *arrayOf(...)
92+
return when (args.size) {
93+
0 -> NSString.stringWithFormat(objcFormat)
94+
1 -> NSString.stringWithFormat(objcFormat, args[0])
95+
2 -> NSString.stringWithFormat(objcFormat, args[0], args[1])
96+
3 -> NSString.stringWithFormat(objcFormat, args[0], args[1], args[2])
97+
4 -> NSString.stringWithFormat(objcFormat, args[0], args[1], args[2], args[3])
98+
5 -> NSString.stringWithFormat(objcFormat, args[0], args[1], args[2], args[3], args[4])
99+
6 -> NSString.stringWithFormat(
100+
objcFormat,
101+
args[0],
102+
args[1],
103+
args[2],
104+
args[3],
105+
args[4],
106+
args[5]
107+
)
108+
7 -> NSString.stringWithFormat(
109+
objcFormat,
110+
args[0],
111+
args[1],
112+
args[2],
113+
args[3],
114+
args[4],
115+
args[5],
116+
args[6]
117+
)
118+
8 -> NSString.stringWithFormat(
119+
objcFormat,
120+
args[0],
121+
args[1],
122+
args[2],
123+
args[3],
124+
args[4],
125+
args[5],
126+
args[6],
127+
args[7]
128+
)
129+
9 -> NSString.stringWithFormat(
130+
objcFormat,
131+
args[0],
132+
args[1],
133+
args[2],
134+
args[3],
135+
args[4],
136+
args[5],
137+
args[6],
138+
args[7],
139+
args[8]
140+
)
141+
else -> throw IllegalArgumentException("can't handle more then 9 arguments now")
142+
}
80143
}
81144
}

0 commit comments

Comments
 (0)