Skip to content

Commit 6255cd5

Browse files
committed
Add: Firebase Remote Config localization
1 parent 3ccc153 commit 6255cd5

115 files changed

Lines changed: 2184 additions & 603 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
name: Localization Validation
2+
3+
on:
4+
push:
5+
branches:
6+
- feature/firebase-remote-localization
7+
pull_request:
8+
branches:
9+
- develop
10+
workflow_dispatch:
11+
12+
concurrency:
13+
group: localization-validation-${{ github.event_name }}-${{ github.ref }}
14+
cancel-in-progress: true
15+
16+
jobs:
17+
validate:
18+
runs-on: ubuntu-latest
19+
timeout-minutes: 45
20+
21+
steps:
22+
- name: Checkout
23+
uses: actions/checkout@v5
24+
25+
- name: Set up JDK 21
26+
uses: actions/setup-java@v5
27+
with:
28+
distribution: temurin
29+
java-version: '21'
30+
31+
- name: Make Gradle wrapper executable
32+
run: chmod +x gradlew
33+
34+
- name: Verify localization architecture
35+
shell: bash
36+
run: |
37+
if grep -R --line-number --include='*.kt' 'Res\.string' app core data domain infrastructure model ui; then
38+
echo 'Found remaining Compose Res.string usage.'
39+
exit 1
40+
fi
41+
if grep -R --line-number --include='*.kt' 'org\.jetbrains\.compose\.resources\.stringResource' app core data domain infrastructure model ui; then
42+
echo 'Found remaining JetBrains Compose stringResource import.'
43+
exit 1
44+
fi
45+
if grep -R --line-number --include='*.kt' 'com\.google\.firebase' data/localization; then
46+
echo 'Localization data code must use Firebase-KMP-Kit.'
47+
exit 1
48+
fi
49+
if ! grep -R --line-number --include='*.kt' 'com\.firebasekit\.remoteconfig' data/localization/src/commonMain; then
50+
echo 'Firebase-KMP-Kit Remote Config must be used from commonMain.'
51+
exit 1
52+
fi
53+
if grep -R --line-number --include='*.kt' 'dev\.gitlive\.firebase' data/localization; then
54+
echo 'Found obsolete GitLive localization integration.'
55+
exit 1
56+
fi
57+
if [ -d data/firebase ]; then
58+
echo 'Obsolete data/firebase module still exists.'
59+
exit 1
60+
fi
61+
if find data/localization/src -type f -name '*.kt' | grep -v '/com/velord/data/localization/' | grep -q .; then
62+
echo 'Found Kotlin source in data/localization outside com.velord.data.localization.'
63+
find data/localization/src -type f -name '*.kt' | grep -v '/com/velord/data/localization/'
64+
exit 1
65+
fi
66+
if find core/core-resource/src/androidMain/res -path '*/values-*/strings.xml' | grep -q .; then
67+
echo 'Translated Android strings.xml files are forbidden; localization.json is canonical.'
68+
find core/core-resource/src/androidMain/res -path '*/values-*/strings.xml'
69+
exit 1
70+
fi
71+
72+
- name: Validate localization publishing script
73+
shell: pwsh
74+
run: ./scripts/firebase/publish-localization.ps1 -ValidateOnly
75+
76+
- name: Verify QA reuses Develop Firebase client
77+
shell: bash
78+
run: |
79+
trap 'rm -f app/android/google-services.json' EXIT
80+
cat > app/android/google-services.json <<'JSON'
81+
{
82+
"project_info": {
83+
"project_number": "1",
84+
"project_id": "firebase-mapping-test"
85+
},
86+
"client": [
87+
{
88+
"client_info": {
89+
"mobilesdk_app_id": "1:1:android:develop-test",
90+
"android_client_info": {
91+
"package_name": "com.velord.composescreenexample.develop"
92+
}
93+
},
94+
"api_key": [
95+
{
96+
"current_key": "test-api-key"
97+
}
98+
]
99+
}
100+
]
101+
}
102+
JSON
103+
./gradlew :app:android:processQaDebugGoogleServices --stacktrace
104+
if [ -e app/android/src/qa/google-services.json ]; then
105+
echo 'QA must not generate or rewrite a Firebase client configuration.'
106+
exit 1
107+
fi
108+
109+
- name: Compile and test localization
110+
run: >-
111+
./gradlew
112+
:data:localization:desktopTest
113+
:infrastructure:di:desktopTest
114+
:app:desktop:compileKotlinDesktop
115+
:app:android:processDevelopDebugMainManifest
116+
:app:android:compileDevelopDebugKotlin
117+
-x :app:android:processDevelopDebugGoogleServices
118+
--stacktrace
119+
120+
- name: Compile QA
121+
run: >-
122+
./gradlew
123+
:app:android:compileQaDebugKotlin
124+
-x :app:android:processQaDebugGoogleServices
125+
--stacktrace
126+
127+
- name: Compile Stage
128+
run: >-
129+
./gradlew
130+
:app:android:compileStageDebugKotlin
131+
-x :app:android:processStageDebugGoogleServices
132+
--stacktrace
133+
134+
- name: Compile Production
135+
run: >-
136+
./gradlew
137+
:app:android:compileProductionDebugKotlin
138+
-x :app:android:processProductionDebugGoogleServices
139+
--stacktrace
140+
141+
- name: Run project quality checks
142+
run: >-
143+
./gradlew
144+
:infrastructure:konsist:test
145+
detekt
146+
--stacktrace

app/android/build.gradle.kts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ android {
2323

2424
defaultConfig {
2525
applicationId = "com.velord.composescreenexample"
26+
manifestPlaceholders["appName"] = "@string/app_name"
2627

2728
targetSdk = libs.versions.targetApi.get().toInt()
2829

@@ -33,8 +34,6 @@ android {
3334
vectorDrawables {
3435
useSupportLibrary = true
3536
}
36-
37-
androidResources.localeFilters += listOf("en")
3837
}
3938

4039
buildTypes {
@@ -62,8 +61,9 @@ android {
6261
}
6362
create(BuildEnvironment.Qa.value) {
6463
dimension = "environment"
64+
manifestPlaceholders["appName"] = "ComposeScreenExample QA"
6565
manifestPlaceholders["enableCrashReporting"] = true
66-
applicationIdSuffix = ".${BuildEnvironment.Qa.value}"
66+
applicationIdSuffix = ".${BuildEnvironment.Develop.value}"
6767
}
6868

6969
create(BuildEnvironment.Stage.value) {
@@ -84,6 +84,7 @@ android {
8484
}
8585

8686
dependencies {
87+
// Module Model
8788
implementation(projects.model)
8889
// Module Infrastructure
8990
implementation(projects.infrastructure.util)
@@ -97,6 +98,8 @@ dependencies {
9798
// Module Data
9899
implementation(projects.data.os)
99100
implementation(projects.data.appstate)
101+
// Module Domain
102+
implementation(projects.domain.usecaseSetting)
100103
// Module UI
101104
implementation(projects.ui.sharedviewmodel)
102105
// Module UI Feature

app/android/src/main/AndroidManifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
<activity
3030
android:name=".ui.main.MainActivity"
3131
android:exported="true"
32-
android:label="@string/app_name"
32+
android:label="${appName}"
3333
android:windowSoftInputMode="adjustResize">
3434

3535
<intent-filter>

app/android/src/main/kotlin/com/velord/composescreenexample/App.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,20 @@ import android.os.StrictMode
55
import android.os.StrictMode.ThreadPolicy
66
import android.os.StrictMode.VmPolicy
77
import com.velord.data.os.memory.MemoryLeakMonitor
8+
import com.velord.usecase.setting.InitializeLocalizationUC
9+
import kotlinx.coroutines.runBlocking
810
import org.koin.android.ext.android.inject
911

1012
class App : Application() {
1113

1214
private val memoryLeakMonitor: MemoryLeakMonitor by inject()
15+
private val initializeLocalizationUC: InitializeLocalizationUC by inject()
1316

1417
override fun onCreate() {
1518
super.onCreate()
1619

1720
initKoin()
21+
initLocalization()
1822
initStrictMode()
1923
initMemoryLeakMonitor()
2024
}
@@ -23,6 +27,12 @@ class App : Application() {
2327
startKoin()
2428
}
2529

30+
private fun initLocalization() {
31+
runBlocking {
32+
initializeLocalizationUC()
33+
}
34+
}
35+
2636
private fun initStrictMode() {
2737
StrictMode.setThreadPolicy(
2838
ThreadPolicy.Builder()

app/desktop/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ kotlin {
3030
implementation(projects.core.coreResource)
3131
// Module Data
3232
implementation(projects.data.appstate)
33+
// Module Domain
34+
implementation(projects.domain.usecaseSetting)
3335
// Module UI
3436
implementation(projects.ui.sharedviewmodel)
3537
// Module UI Feature

app/desktop/src/desktopMain/kotlin/com/velord/composescreenexample/desktop/Main.kt

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
package com.velord.composescreenexample.desktop
22

33
import androidx.compose.foundation.layout.fillMaxSize
4-
import androidx.compose.ui.Modifier
5-
import androidx.compose.ui.window.Window
6-
import androidx.compose.ui.window.application
7-
import com.velord.core.ui.compose.component.ToastHost
8-
import com.velord.core.ui.compose.component.DesktopBackDispatcher
9-
import com.velord.core.ui.compose.component.LocalDesktopBackDispatcher
104
import androidx.compose.runtime.CompositionLocalProvider
115
import androidx.compose.runtime.remember
6+
import androidx.compose.ui.Modifier
127
import androidx.compose.ui.input.key.Key
138
import androidx.compose.ui.input.key.KeyEventType
149
import androidx.compose.ui.input.key.key
1510
import androidx.compose.ui.input.key.type
11+
import androidx.compose.ui.window.Window
12+
import androidx.compose.ui.window.application
13+
import com.velord.core.ui.compose.component.DesktopBackDispatcher
14+
import com.velord.core.ui.compose.component.LocalDesktopBackDispatcher
15+
import com.velord.core.ui.compose.component.ToastHost
1616
import com.velord.core.ui.theme.AppThemeHost
1717
import com.velord.core.ui.util.ObserveSharedFlow
1818
import com.velord.infrastructure.di.createCommonAppModuleRoster
@@ -21,17 +21,22 @@ import com.velord.model.AppEvent
2121
import com.velord.ui.feature.splash.SplashScreen
2222
import com.velord.ui.feature.splash.SplashVM
2323
import com.velord.ui.sharedviewmodel.MainVM
24+
import com.velord.usecase.setting.InitializeLocalizationUC
25+
import kotlinx.coroutines.runBlocking
2426
import org.koin.compose.koinInject
2527
import org.koin.core.context.startKoin
2628

2729
fun main() = application {
28-
startKoin {
30+
val koin = startKoin {
2931
modules(createCommonAppModuleRoster())
32+
}.koin
33+
34+
runBlocking {
35+
koin.get<InitializeLocalizationUC>()()
3036
}
3137

3238
val splashVM: SplashVM = koinInject()
3339
val mainVM: MainVM = koinInject()
34-
3540
val dispatcher = remember { DesktopBackDispatcher() }
3641

3742
Window(
@@ -43,7 +48,7 @@ fun main() = application {
4348
} else {
4449
false
4550
}
46-
}
51+
},
4752
) {
4853
ObserveSharedFlow(mainVM.appEventFlow) {
4954
when (it) {
@@ -60,7 +65,7 @@ fun main() = application {
6065
modifier = Modifier.fillMaxSize(),
6166
content = {
6267
NavigationHost(navigationLib = mainVM.navigationLib)
63-
}
68+
},
6469
)
6570
}
6671
}

0 commit comments

Comments
 (0)