Skip to content

Commit 4891717

Browse files
committed
feat: default language
1 parent fb0f7b7 commit 4891717

5 files changed

Lines changed: 84 additions & 2 deletions

File tree

core/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,24 @@ Tolgee.init {
161161
}
162162
```
163163

164+
#### Default Language Fallback
165+
166+
Configure a default language to use when the user's locale is not available:
167+
168+
```kotlin
169+
Tolgee.init {
170+
contentDelivery {
171+
url = "https://cdn.tolg.ee/your-cdn-url-prefix"
172+
}
173+
defaultLanguage("en") // Fallback to English when user's locale is unavailable
174+
}
175+
```
176+
177+
When a user's locale (e.g., "zh-CN") is not available in your project:
178+
1. Tolgee first tries to find the exact locale match
179+
2. If not found, tries the base language (e.g., "zh-CN" → "zh")
180+
3. If still not found, uses the default language (e.g., "en")
181+
164182
#### Preloading Translations
165183

166184
```kotlin

core/api/android/core.api

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public class io/tolgee/Tolgee {
1313
public static final fun new (Lio/tolgee/Tolgee$Config;)Lio/tolgee/TolgeeAndroid;
1414
public static final fun new (Lkotlin/jvm/functions/Function1;)Lio/tolgee/TolgeeAndroid;
1515
public fun preload (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
16+
public fun preloadAll (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
1617
public final fun removeChangeListener (Lio/tolgee/Tolgee$ChangeListener;)Z
1718
protected final fun resolveLocale (Ljava/util/Locale;)Ljava/util/Locale;
1819
public fun setLocale (Ljava/lang/String;)Ljava/util/Locale;
@@ -47,9 +48,11 @@ public final class io/tolgee/Tolgee$Config {
4748
public final fun component2 ()Lio/tolgee/Tolgee$Config$Network;
4849
public final fun component3 ()Lio/tolgee/Tolgee$Config$ContentDelivery;
4950
public final fun component4 ()Ljava/util/List;
51+
public final fun component5 ()Ljava/util/Locale;
5052
public fun equals (Ljava/lang/Object;)Z
5153
public final fun getAvailableLocales ()Ljava/util/List;
5254
public final fun getContentDelivery ()Lio/tolgee/Tolgee$Config$ContentDelivery;
55+
public final fun getDefaultLanguage ()Ljava/util/Locale;
5356
public final fun getLocale ()Ljava/util/Locale;
5457
public final fun getNetwork ()Lio/tolgee/Tolgee$Config$Network;
5558
public fun hashCode ()I
@@ -68,8 +71,11 @@ public final class io/tolgee/Tolgee$Config$Builder {
6871
public final fun contentDelivery (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Lio/tolgee/Tolgee$Config$Builder;
6972
public final fun contentDelivery (Lkotlin/jvm/functions/Function1;)Lio/tolgee/Tolgee$Config$Builder;
7073
public static synthetic fun contentDelivery$default (Lio/tolgee/Tolgee$Config$Builder;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lio/tolgee/Tolgee$Config$Builder;
74+
public final fun defaultLanguage (Ljava/lang/String;)Lio/tolgee/Tolgee$Config$Builder;
75+
public final fun defaultLanguage (Ljava/util/Locale;)Lio/tolgee/Tolgee$Config$Builder;
7176
public final fun getAvailableLocales ()Ljava/util/List;
7277
public final fun getContentDelivery ()Lio/tolgee/Tolgee$Config$ContentDelivery;
78+
public final fun getDefaultLanguage ()Ljava/util/Locale;
7379
public final fun getLocale ()Ljava/util/Locale;
7480
public final fun getNetwork ()Lio/tolgee/Tolgee$Config$Network;
7581
public final fun locale (Ljava/lang/String;)Lio/tolgee/Tolgee$Config$Builder;
@@ -78,6 +84,7 @@ public final class io/tolgee/Tolgee$Config$Builder {
7884
public final fun network (Lkotlin/jvm/functions/Function1;)Lio/tolgee/Tolgee$Config$Builder;
7985
public final fun setAvailableLocales (Ljava/util/List;)V
8086
public final fun setContentDelivery (Lio/tolgee/Tolgee$Config$ContentDelivery;)V
87+
public final fun setDefaultLanguage (Ljava/util/Locale;)V
8188
public final fun setLocale (Ljava/util/Locale;)V
8289
public final fun setNetwork (Lio/tolgee/Tolgee$Config$Network;)V
8390
}
@@ -182,6 +189,9 @@ public final class io/tolgee/TolgeeAndroid : io/tolgee/Tolgee {
182189
public fun getConfig ()Lio/tolgee/Tolgee$Config;
183190
public fun hashCode ()I
184191
public final fun preload (Landroidx/lifecycle/LifecycleOwner;)Lkotlinx/coroutines/Job;
192+
public final fun preloadAll (Landroidx/lifecycle/LifecycleOwner;)Lkotlinx/coroutines/Job;
193+
public final fun retranslate (Landroid/app/Activity;)V
194+
public final fun retranslate (Landroid/view/View;)V
185195
public final fun t (Landroid/content/Context;I)Ljava/lang/String;
186196
public final fun t (Landroid/content/Context;I[Ljava/lang/Object;)Ljava/lang/String;
187197
public final fun t (Landroid/content/res/Resources;I)Ljava/lang/String;
@@ -209,9 +219,14 @@ public final class io/tolgee/TolgeeAndroid$Companion {
209219

210220
public final class io/tolgee/TolgeeContextWrapper : android/content/ContextWrapper {
211221
public static final field Companion Lio/tolgee/TolgeeContextWrapper$Companion;
212-
public fun <init> (Landroid/content/Context;Lio/tolgee/Tolgee;)V
222+
public fun <init> (Landroid/content/Context;Lio/tolgee/Tolgee;ZZZ)V
223+
public synthetic fun <init> (Landroid/content/Context;Lio/tolgee/Tolgee;ZZZILkotlin/jvm/internal/DefaultConstructorMarker;)V
224+
public final fun getArgumentLayoutInflater ()Z
213225
public final fun getBase ()Landroid/content/Context;
226+
public final fun getInterceptGetString ()Z
227+
public final fun getInterceptGetText ()Z
214228
public fun getResources ()Landroid/content/res/Resources;
229+
public fun getSystemService (Ljava/lang/String;)Ljava/lang/Object;
215230
public final fun getTolgee ()Lio/tolgee/Tolgee;
216231
public static final fun wrap (Landroid/content/Context;)Landroid/content/ContextWrapper;
217232
public static final fun wrap (Landroid/content/Context;Lio/tolgee/Tolgee;)Landroid/content/ContextWrapper;

core/api/jvm/core.api

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public class io/tolgee/Tolgee {
1313
public static final fun new (Lio/tolgee/Tolgee$Config;)Lio/tolgee/common/PlatformTolgee;
1414
public static final fun new (Lkotlin/jvm/functions/Function1;)Lio/tolgee/common/PlatformTolgee;
1515
public fun preload (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
16+
public fun preloadAll (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
1617
public final fun removeChangeListener (Lio/tolgee/Tolgee$ChangeListener;)Z
1718
protected final fun resolveLocale (Ljava/util/Locale;)Ljava/util/Locale;
1819
public fun setLocale (Ljava/lang/String;)Ljava/util/Locale;
@@ -47,9 +48,11 @@ public final class io/tolgee/Tolgee$Config {
4748
public final fun component2 ()Lio/tolgee/Tolgee$Config$Network;
4849
public final fun component3 ()Lio/tolgee/Tolgee$Config$ContentDelivery;
4950
public final fun component4 ()Ljava/util/List;
51+
public final fun component5 ()Ljava/util/Locale;
5052
public fun equals (Ljava/lang/Object;)Z
5153
public final fun getAvailableLocales ()Ljava/util/List;
5254
public final fun getContentDelivery ()Lio/tolgee/Tolgee$Config$ContentDelivery;
55+
public final fun getDefaultLanguage ()Ljava/util/Locale;
5356
public final fun getLocale ()Ljava/util/Locale;
5457
public final fun getNetwork ()Lio/tolgee/Tolgee$Config$Network;
5558
public fun hashCode ()I
@@ -68,8 +71,11 @@ public final class io/tolgee/Tolgee$Config$Builder {
6871
public final fun contentDelivery (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Lio/tolgee/Tolgee$Config$Builder;
6972
public final fun contentDelivery (Lkotlin/jvm/functions/Function1;)Lio/tolgee/Tolgee$Config$Builder;
7073
public static synthetic fun contentDelivery$default (Lio/tolgee/Tolgee$Config$Builder;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lio/tolgee/Tolgee$Config$Builder;
74+
public final fun defaultLanguage (Ljava/lang/String;)Lio/tolgee/Tolgee$Config$Builder;
75+
public final fun defaultLanguage (Ljava/util/Locale;)Lio/tolgee/Tolgee$Config$Builder;
7176
public final fun getAvailableLocales ()Ljava/util/List;
7277
public final fun getContentDelivery ()Lio/tolgee/Tolgee$Config$ContentDelivery;
78+
public final fun getDefaultLanguage ()Ljava/util/Locale;
7379
public final fun getLocale ()Ljava/util/Locale;
7480
public final fun getNetwork ()Lio/tolgee/Tolgee$Config$Network;
7581
public final fun locale (Ljava/lang/String;)Lio/tolgee/Tolgee$Config$Builder;
@@ -78,6 +84,7 @@ public final class io/tolgee/Tolgee$Config$Builder {
7884
public final fun network (Lkotlin/jvm/functions/Function1;)Lio/tolgee/Tolgee$Config$Builder;
7985
public final fun setAvailableLocales (Ljava/util/List;)V
8086
public final fun setContentDelivery (Lio/tolgee/Tolgee$Config$ContentDelivery;)V
87+
public final fun setDefaultLanguage (Ljava/util/Locale;)V
8188
public final fun setLocale (Ljava/util/Locale;)V
8289
public final fun setNetwork (Lio/tolgee/Tolgee$Config$Network;)V
8390
}

core/src/commonMain/kotlin/io/tolgee/Tolgee.kt

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ open class Tolgee(
165165
* Resolution strategy:
166166
* 1. If the exact locale is available, return it (e.g., "en-US" → "en-US")
167167
* 2. Otherwise, try to find an exact match for the base language (e.g., "en-US" → "en")
168+
* 3. If still not found, use the default language if configured
168169
*
169170
* Available locales are determined from:
170171
* 1. `config.availableLocales` (if manually specified)
@@ -194,13 +195,21 @@ open class Tolgee(
194195

195196
// Fallback: Look for exact base language match only
196197
// Find exact match for base language (e.g., "en" without region/script)
197-
return availableLocales.firstOrNull { availableLocale ->
198+
val baseLanguageMatch = availableLocales.firstOrNull { availableLocale ->
198199
// Match only if:
199200
// 1. The language matches
200201
// 2. It's a base language (no region/script), checked by comparing tag to language
201202
availableLocale.language == locale.language &&
202203
availableLocale.toTag("-") == availableLocale.language
203204
}
205+
206+
if (baseLanguageMatch != null) {
207+
return baseLanguageMatch
208+
}
209+
210+
// Final fallback: Use default language if configured, otherwise null
211+
// We assume the default language is available
212+
return config.defaultLanguage
204213
}
205214

206215
/**
@@ -462,6 +471,7 @@ open class Tolgee(
462471
val network: Network,
463472
val contentDelivery: ContentDelivery,
464473
val availableLocales: List<Locale>?,
474+
val defaultLanguage: Locale?,
465475
) {
466476

467477
/**
@@ -493,6 +503,21 @@ open class Tolgee(
493503
*/
494504
var availableLocales: List<Locale>? = null
495505

506+
/**
507+
* The default language to use as a final fallback when the requested locale
508+
* and its base language are not available. This ensures that users with
509+
* unsupported languages receive translations from the CDN (in the default language)
510+
* instead of falling back to native bundled translations.
511+
*
512+
* Example: If a user has locale "zh-CN" and it's not available, but "en" is set
513+
* as the default language, the app will fetch and display English translations
514+
* from the CDN rather than using bundled translations.
515+
*
516+
* If null (default), the fallback chain ends with returning null from resolveLocale(),
517+
* which eventually leads to using TranslationEmpty and bundled translations.
518+
*/
519+
var defaultLanguage: Locale? = null
520+
496521
/**
497522
* Represents the network configuration used within the `Builder`.
498523
* This property defines the HTTP client and coroutine context used for executing network operations.
@@ -568,6 +593,21 @@ open class Tolgee(
568593
*/
569594
fun availableLocaleTags(vararg localeTags: String) = availableLocales(localeTags.map(::forLocaleTag))
570595

596+
/**
597+
* Sets the default language to use as a final fallback when the requested locale is not available.
598+
*
599+
* @param locale The locale to use as the default fallback language.
600+
*/
601+
fun defaultLanguage(locale: Locale) = apply {
602+
this.defaultLanguage = locale
603+
}
604+
605+
/**
606+
* Sets the default language to use as a final fallback when the requested locale is not available.
607+
*
608+
* @param localeTag A locale string in the format of a language tag (e.g., "en", "fr", "es").
609+
*/
610+
fun defaultLanguage(localeTag: String) = defaultLanguage(forLocaleTag(localeTag))
571611

572612
/**
573613
* Configures the network settings for the builder.
@@ -641,6 +681,7 @@ open class Tolgee(
641681
availableLocales = availableLocales,
642682
network = network,
643683
contentDelivery = contentDelivery,
684+
defaultLanguage = defaultLanguage,
644685
)
645686
}
646687

demo/exampleandroid/src/main/java/io/tolgee/demo/exampleandroid/MyApplication.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class MyApplication : Application() {
1515
storage = TolgeeStorageProviderAndroid(this@MyApplication, BuildConfig.VERSION_CODE)
1616
availableLocaleTags("cs", "en", "fr", "sv")
1717
}
18+
defaultLanguage("en")
1819
}
1920
}
2021
}

0 commit comments

Comments
 (0)