• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

icerockdev/moko-resources: Resources access for mobile (android & ios) Kotli ...

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称(OpenSource Name):

icerockdev/moko-resources

开源软件地址(OpenSource Url):

https://github.com/icerockdev/moko-resources

开源编程语言(OpenSource Language):

Kotlin 100.0%

开源软件介绍(OpenSource Introduction):

moko-resources
GitHub license Download kotlin-version badge badge badge badge badge badge badge badge

Mobile Kotlin resources

This is a Kotlin MultiPlatform library that provides access to the resources on macOs, iOS, Android the JVM and JS/Browser with the support of the default system localization.

Table of Contents

Features

  • Strings, Plurals, Images, Fonts, Files to access the corresponding resources from common code;
  • Colors with light/dark mode support;
  • StringDesc for lifecycle-aware access to resources and unified localization on both platforms;
  • Static iOS frameworks support;
  • Fat and XC frameworks support.

Requirements

  • Gradle version 6.8.3+
  • Android API 16+
  • iOS version 11.0+

Installation

root build.gradle

buildscript {
    repositories {
        gradlePluginPortal()
    }

    dependencies {
        classpath "dev.icerock.moko:resources-generator:0.20.1"
    }
}


allprojects {
    repositories {
        mavenCentral()
    }
}

project build.gradle

apply plugin: "dev.icerock.mobile.multiplatform-resources"

dependencies {
    commonMainApi("dev.icerock.moko:resources:0.20.1")
    androidMainApi("dev.icerock.moko:resources-compose:0.20.1")
    jvmMainApi("dev.icerock.moko:resources-compose:0.20.1")
    commonTestImplementation("dev.icerock.moko:resources-test:0.20.1")
}

multiplatformResources {
    multiplatformResourcesPackage = "org.example.library" // required
    multiplatformResourcesClassName = "SharedRes" // optional, default MR
    multiplatformResourcesVisibility = MRVisibility.Internal // optional, default Public
    iosBaseLocalizationRegion = "en" // optional, default "en"
    multiplatformResourcesSourceSet = "commonClientMain"  // optional, default "commonMain"
}

To use toUIColor(), toUIImage(), desc() and other iOS extensions from Swift - you should add export declarations:

framework {
    export("dev.icerock.moko:resources:0.20.1")
    export("dev.icerock.moko:graphics:0.9.0") // toUIColor here
}

If your project includes a build type, for example staging which isn't in moko-resources. That isn't an issue. Use matchingFallbacks to specify alternative matches for a given build type, as shown below

buildTypes {
    staging {
        initWith debug
        matchingFallbacks = ['debug']
    }
}

ios-app Info.plist:

<key>CFBundleLocalizations</key>
<array>
<string>en</string>
<string>ru</string>
</array>

in array should be added all used languages.

JS/Browser generates json files which is included in webpack by default. For more details about JS see this example

Static kotlin frameworks support

If project configured with static framework output (for example by org.jetbrains.kotlin.native.cocoapods plugin) in Xcode project should be added Build Phase (at end of list) with script:

"$SRCROOT/../gradlew" -p "$SRCROOT/../" :yourframeworkproject:copyFrameworkResourcesToApp \
    -Pmoko.resources.PLATFORM_NAME=$PLATFORM_NAME \
    -Pmoko.resources.CONFIGURATION=$CONFIGURATION \
    -Pmoko.resources.BUILT_PRODUCTS_DIR=$BUILT_PRODUCTS_DIR \
    -Pmoko.resources.CONTENTS_FOLDER_PATH=$CONTENTS_FOLDER_PATH

Please replace :yourframeworkproject to kotlin project gradle path, and set correct relative path ($SRCROOT/../ in example).
This phase will copy resources into application, because static frameworks can't have resources.

To disable warnings about static framework in gradle set flag:

multiplatformResources {
    disableStaticFrameworkWarning = true
}

With Pods dependencies in Kotlin

When you use org.jetbrains.kotlin.native.cocoapods plugin and also kotlin module depends to Pods - you also need to pass extra properties:

"$SRCROOT/../gradlew" -p "$SRCROOT/../" :shared:copyFrameworkResourcesToApp \
    -Pmoko.resources.PLATFORM_NAME=$PLATFORM_NAME \
    -Pmoko.resources.CONFIGURATION=$CONFIGURATION \
    -Pmoko.resources.BUILT_PRODUCTS_DIR=$BUILT_PRODUCTS_DIR \
    -Pmoko.resources.CONTENTS_FOLDER_PATH=$CONTENTS_FOLDER_PATH\
    -Pkotlin.native.cocoapods.platform=$PLATFORM_NAME \
    -Pkotlin.native.cocoapods.archs="$ARCHS" \
    -Pkotlin.native.cocoapods.configuration=$CONFIGURATION 

iOS executable

When you use executable kotlin target you should add custom build phase to xcode, after kotlin compilation:

"$SRCROOT/../gradlew" -p "$SRCROOT/../" :shared:copyResourcesDebugExecutableIosSimulatorArm64 \
    -Pmoko.resources.BUILT_PRODUCTS_DIR=$BUILT_PRODUCTS_DIR \
    -Pmoko.resources.CONTENTS_FOLDER_PATH=$CONTENTS_FOLDER_PATH

copyResourcesDebugExecutableIosSimulatorArm64 should be configured depends on target.

Configured sample you can see in sample/ios-app - TestKotlinApp target

Usage

Example 1 - simple localization string

The first step is a create a file strings.xml in commonMain/resources/MR/base with the following content:

<?xml version="1.0" encoding="UTF-8" ?>
<resources>
    <string name="my_string">My default localization string</string>
</resources>

Next - create a file strings.xml with localized strings in commonMain/resource/MR/<languageCode>. Here's an example of creating commonMain/resource/MR/ru for a Russian localization:

<?xml version="1.0" encoding="UTF-8" ?>
<resources>
    <string name="my_string">Моя строка локализации по умолчанию</string>
</resources>

After adding the resources we can call a gradle sync or execute a gradle task generateMRcommonMain. This will generate a MR class containing MR.strings.my_string, which we can use in commonMain:

fun getMyString(): StringDesc {
    return StringDesc.Resource(MR.strings.my_string)
}

After this we can use our functions on the platform side:
Android:

val string = getMyString().toString(context = this)

iOS:

let string = getMyString().localized()

JS:

val strings = MR.stringsLoader.getOrLoad() // loading localization from a remote file
val string = getMyString().localized(strings)

Note: StringDesc is a multiple-source container for Strings: in StringDesc we can use a resource, plurals, formatted variants, or raw string. To convert StringDesc to String on Android call toString(context) (a context is required for the resources usage), on iOS - call localized().

MR directly from native side

Android:

val string = MR.strings.my_string.desc().toString(context = this)

iOS:

let string = MR.strings().my_string.desc().localized()

Get resourceId for Jetpack Compose / SwiftUI

Android:

val resId = MR.strings.my_string.resourceId

for example in Compose:

text = stringResource(id = MR.strings.email.resourceId)

iOS:

LocalizedStringKey(MR.strings().email.resourceId)

Note: more info in issue #126.

Example 2 - formatted localization string

In commonMain/resources/MR/base/strings.xml add:

<?xml version="1.0" encoding="UTF-8" ?>
<resources>
    <string name="my_string_formatted">My format '%s'</string>
</resources>

Then add the localized values for other languages like in example #1. Now create the following function in commonMain:

fun getMyFormatDesc(input: String): StringDesc {
    return StringDesc.ResourceFormatted(MR.strings.my_string_formatted, input)
}

To create formatted strings from resources you can also use extension format:

fun getMyFormatDesc(input: String): StringDesc {
    return MR.strings.my_string_formatted.format(input)
}

Now add support on the platform side like in example #1:
Android:

val string = getMyFormatDesc("hello").toString(context = this)

iOS:

let string = getMyFormatDesc(input: "hello").localized()

Warning: Do no mix positioned placeholders with unpositioned ones within a string, as this may lead to different behaviour on different platforms. Stick to one style for each string.

Example 3 - plural string

The first step is to create a file plurals.xml in commonMain/resources/MR/base with the following content:

<?xml version="1.0" encoding="UTF-8" ?>
<resources>
    <plural name="my_plural">
        <item quantity="zero">zero</item>
        <item quantity="one">one</item>
        <item quantity="two">two</item>
        <item quantity="few">few</item>
        <item quantity="many">many</item>
        <item quantity="other">other</item>
    </plural>
</resources>

Then add the localized values for other languages like in example #1.
Next, create a function in commonMain:

fun getMyPluralDesc(quantity: Int): StringDesc {
    return StringDesc.Plural(MR.plurals.my_plural, quantity)
}

Now add support on the platform side like in example #1:
Android:

val string = getMyPluralDesc(10).toString(context = this)

iOS:

let string = getMyPluralDesc(quantity: 10).localized()

Example 4 - plural formatted string

The first step is to create file plurals.xml in commonMain/resources/MR/base with the following content:

<?xml version="1.0" encoding="UTF-8" ?>
<resources>
    <plural name="my_plural">
        <item quantity="zero">no items</item>
        <item quantity="one">%d item</item>
        <item quantity="two">%d items</item>
        <item quantity="few">%d items</item>
        <item quantity="many">%d items</item>
        <item quantity="other">%d items</item>
    </plural>
</resources>

Then add the localized values for other languages like in example #1.
Next, create a function in commonMain:

fun getMyPluralFormattedDesc(quantity: Int): StringDesc {
    // we pass quantity as selector for correct plural string and for pass quantity as argument for formatting
    return StringDesc.PluralFormatted(MR.plurals.my_plural, quantity, quantity)
}

To create formatted plural strings from resources you can also use extension format:

fun getMyPluralFormattedDesc(quantity: Int): StringDesc {
    // we pass quantity as selector for correct plural string and for pass quantity as argument for formatting
    return MR.plurals.my_plural.format(quantity, quantity)
}

And like in example #1, add the platform-side support:
Android:

val string = getMyPluralFormattedDesc(10).toString(context = this)

iOS:

let string = getMyPluralFormattedDesc(quantity: 10).localized()

Example 5 - pass raw string or resource

If we already use some resources as a placeholder value, we can use StringDesc to change the string source:

fun getUserName(user: User?): StringDesc {
    if(user != null) {
        return StringDesc.Raw(user.name)
    } else {
        return StringDesc.Resource(MR.strings.name_placeholder)
    }
}

And just like in example 1 usage on platform side:
Android:

val string1 = getUserName(user).toString(context = this) // we got name from User model
val string2 = getUserName(null).toString(context = this) // we got name_placeholder from resources

iOS:

let string1 = getUserName(user: user).localized() // we got name from User model
let string2 = getUserName(user: null).localized() // we got name_placeholder from resources

Example 6 - Select localization in runtime

You can force StringDesc to use preferred localization in common code:

StringDesc.localeType = StringDesc.LocaleType.Custom("es")

and return to system behaviour (when localization depends on device settings):

StringDesc.localeType = StringDesc.LocaleType.System()

Example 7 - pass image

Image resources directory is commonMain/resources/MR/images with support of nested directories.
Image name should be end with one of:

  • @0.75x - android ldpi;
  • @1x - android mdpi, ios 1x;
  • @1.5x - android hdpi;
  • @2x - android xhdpi, ios 2x;
  • @3x - android xxhdpi, ios 3x;
  • @4x - android xxxhdpi. Supported png and jpg resources for now.

If we add to commonMain/resources/MR/images files:

We got autogenerated MR.images.home_black_18 ImageResource in code, that we can use:

  • Android: imageView.setImageResource(image.drawableResId)
  • iOS: imageView.image = image.toUIImage()

You can get images by their name too

in commonMain create a Resources.kt file with the content below

fun getImageByFileName(name: String): ImageResource {
    val fallbackImage = MR.images.transparent
    return MR.images.getImageByFileName(name) ?: fallbackImage
}
  • Android: imageView.setImageResource(getDrawableByFileName("image_name"))
  • iOS: imageView.image = ResourcesKt.getDrawableByFileName(name: "image_name").toUIImage()!

Example 8 - pass font

Fonts resources directory is commonMain/resources/MR/fonts.
Font name should be this pattern: <fontFamily>-<fontStyle> like:

  • Raleway-Bold.ttf
  • Raleway-Regular.ttf
  • Raleway-Italic.ttf Supports ttf and otf resources.

If we add to commonMain/resources/MR/fonts files:

  • Raleway-Bold.ttf
  • Raleway-Regular.ttf
  • Raleway-Italic.ttf

We got autogenerated MR.fonts.Raleway.italic, MR.fonts.Raleway.regular, MR.fonts.Raleway.bold FontResource in code, that we can use:

  • Android: textView.typeface = font.getTypeface(context = this)
  • iOS: textView.font = font.uiFont(withSize: 14.0)

Example 9 - pass colors

Colors resources directory is commonMain/resources/MR/colors.
Colors files is xml with format:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- format: #RRGGBB[AA] or 0xRRGGBB[AA] or RRGGBB[AA] where [AA] - optional -->
    <color name="valueColor">#B02743FF</color>
    <color name="referenceColor">@color/valueColor</color>
    <color name="themedColor">
        <light>0xB92743FF</light>
        <dark>7CCFEEFF</dark>
    </color>
    <color name="themedReferenceColor">
        <light>@color/valueColor</light>
        <dark>@color/referenceColor</dark>
    </color>
</resources>

If you want use one color without light/dark theme selection:

<color name
                      

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap