Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ tasks.withType<Detekt> {
exclude("**/*gradle.kts")
exclude("**/build/**")
exclude("**/buildSrc/**")
// exclude("**/examples/**")
}

// endregion
Expand Down
19 changes: 19 additions & 0 deletions sample/single-module-multiplatform-app/.fleet/receipt.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Project generated by Kotlin Multiplatform Wizard
{
"spec": {
"template_id": "kmt",
"targets": {
"android": {
"ui": [
"compose"
]
},
"ios": {
"ui": [
"swiftui"
]
}
}
},
"timestamp": "2024-11-29T09:06:39.079604318Z"
}
18 changes: 18 additions & 0 deletions sample/single-module-multiplatform-app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
*.iml
.kotlin
.gradle
**/build/
xcuserdata
!src/**/build/
local.properties
.idea
.DS_Store
captures
.externalNativeBuild
.cxx
*.xcodeproj/*
!*.xcodeproj/project.pbxproj
!*.xcodeproj/xcshareddata/
!*.xcodeproj/project.xcworkspace/
!*.xcworkspace/contents.xcworkspacedata
**/xcshareddata/WorkspaceSettings.xcsettings
42 changes: 42 additions & 0 deletions sample/single-module-multiplatform-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# KMP Localization Example with Linguine Plugin

This is an example of a simple Kotlin Multiplatform (KMP) project demonstrating the integration and usage of the Linguine localization strings plugin. This project targets two platforms: Android and iOS.

## Project Structure

- **Android Localization**:
JSON localization files for the Android app are located in:
`/composeApp/src/androidMain/assets`

- **iOS Localization**:
JSON localization files for the iOS app are located in:
`/iosApp/iosApp`
These files are also linked in the Xcode project.

## Linguine Plugin Configuration

The Linguine plugin is configured in `shared/build.gradle.kts`. In this example, the Android English localization file is used as the input for the Linguine generator. Here's the configuration:

```kotlin
linguineConfig {
inputFilePath = "../composeApp/src/androidMain/assets/strings-en.json"
outputFilePath = "src/commonMain/kotlin/com/qinshift/project"
majorDelimiter = "__"
minorDelimiter = "_"
}
```

## Key Details
- **`inputFilePath`**: Specifies the path to the input localization file (Android English JSON in this case).
- **`outputFilePath`**: Defines the output directory for the generated code.
- **Delimiters**: `majorDelimiter` and `minorDelimiter` control how keys in the localization file are split and organized.

## Plugin Installation

The Linguine plugin is added to the project in `shared/build.gradle.kts`. The plugin version is managed in the `gradle/libs.versions.toml` file. Here's an example of how the plugin is configured:

```kotlin
plugins {
...
alias(libs.plugins.linguine)
}
9 changes: 9 additions & 0 deletions sample/single-module-multiplatform-app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
plugins {
// this is necessary to avoid the plugins to be loaded multiple times
// in each subproject's classloader
alias(libs.plugins.androidApplication) apply false
alias(libs.plugins.androidLibrary) apply false
alias(libs.plugins.composeMultiplatform) apply false
alias(libs.plugins.composeCompiler) apply false
alias(libs.plugins.kotlinMultiplatform) apply false
}
65 changes: 65 additions & 0 deletions sample/single-module-multiplatform-app/composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.androidApplication)
alias(libs.plugins.composeMultiplatform)
alias(libs.plugins.composeCompiler)
}

kotlin {
androidTarget()

sourceSets {

androidMain.dependencies {
implementation(compose.preview)
implementation(libs.androidx.activity.compose)
}
commonMain.dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
implementation(compose.ui)
implementation(compose.components.resources)
implementation(compose.components.uiToolingPreview)
implementation(libs.androidx.lifecycle.viewmodel)
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(projects.shared)
}
}
}

android {
namespace = "com.qinshift.project"
compileSdk = libs.versions.android.compileSdk.get().toInt()

defaultConfig {
applicationId = "com.qinshift.project"
minSdk = libs.versions.android.minSdk.get().toInt()
targetSdk = libs.versions.android.targetSdk.get().toInt()
versionCode = 1
versionName = "1.0"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
}

dependencies {
debugImplementation(compose.uiTooling)
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@android:style/Theme.Material.Light.NoActionBar">
<activity
android:exported="true"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|mnc|colorMode|density|fontScale|fontWeightAdjustment|keyboard|layoutDirection|locale|mcc|navigation|smallestScreenSize|touchscreen|uiMode"
android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"demo__button_label": "Klikni zde!",
"demo__hello": "%1$s - Ahoj, %2$s!",
"credits__info": "Vytvořeno v Qinshift"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"demo__button_label": "Click me!",
"demo__hello": "%1$s - Hello, %2$s!",
"credits__info": "Made in Qinshift"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
@file:Suppress("WildcardImport", "NoWildcardImports", "ImportOrdering")
package com.qinshift.project

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.ui.tooling.preview.Preview
import presentation.Credits
import presentation.Demo

import single_module_multiplatform_app.composeapp.generated.resources.Res
import single_module_multiplatform_app.composeapp.generated.resources.compose_multiplatform

@Composable
@Preview
fun App() {
MaterialTheme {
var showContent by remember { mutableStateOf(false) }
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
Button(onClick = { showContent = !showContent }) {
Text(Demo.buttonLabel)
}
AnimatedVisibility(showContent) {
val firstGreeting = remember { Greeting().greet(1) }
val secondGreeting = remember { Greeting().greet(2) }
val thirdGreeting = remember { Greeting().alternativeGreet(3) }
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
Image(painterResource(Res.drawable.compose_multiplatform), null)
Text("Compose: $firstGreeting")
Text("Compose: $secondGreeting")
Text("Compose: $thirdGreeting")
}
}
Spacer(Modifier.weight(1f))
Text(
Credits.info,
modifier = Modifier.padding(16.dp)
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.qinshift.project

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

setContent {
App()
}
}
}

@Preview
@Composable
fun AppAndroidPreview() {
App()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
Loading