Skip to content

Commit f0c2bf2

Browse files
authored
Merge pull request #8 from tolgee/jeffretz/fix-contextwrapper
2 parents dd08ac2 + d7fc67d commit f0c2bf2

4 files changed

Lines changed: 398 additions & 43 deletions

File tree

core/src/androidMain/kotlin/io/tolgee/TolgeeAndroid.kt

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ data class TolgeeAndroid internal constructor(
105105
} ?: context.getString(id)
106106
}
107107

108+
fun t(resources: Resources, @StringRes id: Int): String {
109+
return getKeyFromResources(resources, id)?.let { key ->
110+
t(key)
111+
} ?: resources.getString(id)
112+
}
113+
108114
/**
109115
* Provides an immediate translation for a given string resource ID with optional format arguments.
110116
* If the translation key is found in the string resource, it retrieves the translation; otherwise,
@@ -121,6 +127,12 @@ data class TolgeeAndroid internal constructor(
121127
} ?: context.getString(id, *formatArgs)
122128
}
123129

130+
fun t(resources: Resources, @StringRes id: Int, vararg formatArgs: Any): String {
131+
return getKeyFromResources(resources, id)?.let { key ->
132+
t(key, TolgeeMessageParams.Indexed(*formatArgs))
133+
} ?: resources.getString(id, *formatArgs)
134+
}
135+
124136
fun tPlural(resources: Resources, @PluralsRes id: Int, quantity: Int): String {
125137
return getKeyFromResources(resources, id)?.let { key ->
126138
t(key, TolgeeMessageParams.Indexed(quantity))
@@ -159,6 +171,32 @@ data class TolgeeAndroid internal constructor(
159171
} ?: context.getText(id)
160172
}
161173

174+
fun tStyled(resources: Resources, @StringRes id: Int): CharSequence {
175+
return getKeyFromResources(resources, id)?.let { key ->
176+
t(key)
177+
} ?: resources.getText(id)
178+
}
179+
180+
fun tStyled(resources: Resources, @StringRes id: Int, def: CharSequence?): CharSequence? {
181+
return id.takeUnless { it == 0 }?.let {
182+
getKeyFromResources(resources, it)?.let { key ->
183+
t(key)
184+
}
185+
} ?: resources.getText(id, def)
186+
}
187+
188+
fun tPluralStyled(resources: Resources, @PluralsRes id: Int, quantity: Int): CharSequence {
189+
return getKeyFromResources(resources, id)?.let { key ->
190+
t(key, TolgeeMessageParams.Indexed(quantity))
191+
} ?: resources.getQuantityText(id, quantity)
192+
}
193+
194+
fun tArrayStyled(resources: Resources, @ArrayRes id: Int): Array<out CharSequence> {
195+
return getKeyFromResources(resources, id)?.let { key ->
196+
tArray(key).toTypedArray()
197+
} ?: resources.getTextArray(id)
198+
}
199+
162200
/**
163201
* Preloads the required languages and their translations for the current Tolgee instance.
164202
*

core/src/androidMain/kotlin/io/tolgee/TolgeeContextWrapper.kt

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,18 @@ class TolgeeContextWrapper(
1919
val tolgee: Tolgee
2020
) : ContextWrapper(base) {
2121

22-
private val res = atomic<Resources?>(null)
22+
private var baseRes by atomic<Resources?>(null)
23+
private var res by atomic<Resources?>(baseRes)
2324

2425
override fun getResources(): Resources? {
25-
if (res.value == null) {
26-
val superResources: Resources? = super.getResources()
27-
28-
if (superResources != null) {
29-
res.compareAndSet(null, TolgeeResources(
30-
baseContext = base,
31-
base = superResources,
32-
tolgee = tolgee
33-
))
34-
}
26+
val base = super.getResources() ?: return res
3527

28+
if (res == null || baseRes != base) {
29+
res = TolgeeResources(base, tolgee)
30+
baseRes = base
3631
}
37-
return res.value ?: super.getResources()
32+
33+
return res ?: base
3834
}
3935

4036
companion object {
Lines changed: 257 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,48 @@
11
package io.tolgee
22

3-
import android.content.Context
3+
import android.annotation.SuppressLint
4+
import android.content.res.AssetFileDescriptor
5+
import android.content.res.ColorStateList
6+
import android.content.res.Configuration
47
import android.content.res.Resources
8+
import android.content.res.TypedArray
9+
import android.content.res.XmlResourceParser
10+
import android.content.res.loader.ResourcesLoader
11+
import android.graphics.Movie
12+
import android.graphics.Typeface
13+
import android.graphics.drawable.Drawable
14+
import android.os.Build
15+
import android.os.Bundle
16+
import android.util.AttributeSet
17+
import android.util.DisplayMetrics
18+
import android.util.TypedValue
19+
import androidx.annotation.AnimRes
20+
import androidx.annotation.AnimatorRes
21+
import androidx.annotation.AnyRes
22+
import androidx.annotation.ArrayRes
23+
import androidx.annotation.BoolRes
24+
import androidx.annotation.ColorInt
25+
import androidx.annotation.ColorRes
26+
import androidx.annotation.DimenRes
27+
import androidx.annotation.Discouraged
28+
import androidx.annotation.DrawableRes
29+
import androidx.annotation.FontRes
30+
import androidx.annotation.FractionRes
31+
import androidx.annotation.IntegerRes
32+
import androidx.annotation.LayoutRes
33+
import androidx.annotation.PluralsRes
34+
import androidx.annotation.RawRes
35+
import androidx.annotation.RequiresApi
36+
import androidx.annotation.StringRes
37+
import androidx.annotation.StyleableRes
38+
import androidx.annotation.XmlRes
539
import io.tolgee.common.getQuantityStringT
40+
import io.tolgee.common.getQuantityTextT
641
import io.tolgee.common.getStringArrayT
742
import io.tolgee.common.getStringT
43+
import io.tolgee.common.getTextArrayT
844
import io.tolgee.common.getTextT
45+
import java.io.InputStream
946

1047
/**
1148
* Ignore Deprecation: Resources constructor is not really deprecated, apps should just not create
@@ -14,32 +51,238 @@ import io.tolgee.common.getTextT
1451
*/
1552
@Suppress("DEPRECATION")
1653
internal class TolgeeResources(
17-
val baseContext: Context,
1854
val base: Resources,
1955
val tolgee: Tolgee
2056
) : Resources(base.assets, base.displayMetrics, base.configuration) {
2157

22-
override fun getString(id: Int): String {
23-
return baseContext.getStringT(tolgee, id)
58+
/**
59+
* Following methods are intercepted by Tolgee.
60+
*/
61+
62+
override fun getString(@StringRes id: Int): String {
63+
return base.getStringT(tolgee, id)
64+
}
65+
66+
override fun getString(@StringRes id: Int, vararg formatArgs: Any?): String {
67+
return base.getStringT(tolgee, id, *formatArgs.filterNotNull().toTypedArray())
68+
}
69+
70+
override fun getQuantityString(@PluralsRes id: Int, quantity: Int): String {
71+
return base.getQuantityStringT(tolgee, id, quantity)
72+
}
73+
74+
override fun getQuantityString(@PluralsRes id: Int, quantity: Int, vararg formatArgs: Any?): String {
75+
return base.getQuantityStringT(tolgee, id, quantity, *formatArgs.filterNotNull().toTypedArray())
76+
}
77+
78+
override fun getStringArray(@ArrayRes id: Int): Array<out String?> {
79+
return base.getStringArrayT(tolgee, id)
80+
}
81+
82+
override fun getText(@StringRes id: Int): CharSequence {
83+
return base.getTextT(tolgee, id)
84+
}
85+
86+
override fun getQuantityText(@PluralsRes id: Int, quantity: Int): CharSequence {
87+
return base.getQuantityTextT(tolgee, id, quantity)
88+
}
89+
90+
override fun getTextArray(id: Int): Array<out CharSequence?> {
91+
return base.getTextArrayT(tolgee, id)
92+
}
93+
94+
override fun getText(@StringRes id: Int, def: CharSequence?): CharSequence? {
95+
return base.getTextT(tolgee, id, def)
96+
}
97+
98+
/**
99+
* Following methods are proxied to preserve original behavior.
100+
*/
101+
102+
@RequiresApi(Build.VERSION_CODES.O)
103+
override fun getFont(@FontRes id: Int): Typeface {
104+
return base.getFont(id)
105+
}
106+
107+
override fun getIntArray(@ArrayRes id: Int): IntArray {
108+
return base.getIntArray(id)
109+
}
110+
111+
override fun obtainTypedArray(@ArrayRes id: Int): TypedArray {
112+
return base.obtainTypedArray(id)
113+
}
114+
115+
override fun getDimension(@DimenRes id: Int): Float {
116+
return base.getDimension(id)
117+
}
118+
119+
override fun getDimensionPixelOffset(@DimenRes id: Int): Int {
120+
return base.getDimensionPixelOffset(id)
121+
}
122+
123+
override fun getDimensionPixelSize(@DimenRes id: Int): Int {
124+
return base.getDimensionPixelSize(id)
125+
}
126+
127+
override fun getFraction(@FractionRes id: Int, base: Int, pbase: Int): Float {
128+
return this.base.getFraction(id, base, pbase)
129+
}
130+
131+
@Deprecated("Proxied Deprecation")
132+
override fun getDrawable(@DrawableRes id: Int): Drawable? {
133+
return base.getDrawable(id)
134+
}
135+
136+
override fun getDrawable(@DrawableRes id: Int, theme: Theme?): Drawable? {
137+
return base.getDrawable(id, theme)
138+
}
139+
140+
@Deprecated("Proxied Deprecation")
141+
override fun getDrawableForDensity(@DrawableRes id: Int, density: Int): Drawable? {
142+
return base.getDrawableForDensity(id, density)
143+
}
144+
145+
override fun getDrawableForDensity(@DrawableRes id: Int, density: Int, theme: Theme?): Drawable? {
146+
return base.getDrawableForDensity(id, density, theme)
147+
}
148+
149+
@Deprecated("Proxied Deprecation")
150+
override fun getMovie(@RawRes id: Int): Movie? {
151+
return base.getMovie(id)
152+
}
153+
154+
@ColorInt
155+
@Deprecated("Proxied Deprecation")
156+
override fun getColor(@ColorRes id: Int): Int {
157+
return base.getColor(id)
158+
}
159+
160+
@ColorInt
161+
@RequiresApi(Build.VERSION_CODES.M)
162+
override fun getColor(@ColorRes id: Int, theme: Theme?): Int {
163+
return base.getColor(id, theme)
164+
}
165+
166+
@Deprecated("Proxied Deprecation")
167+
override fun getColorStateList(@ColorRes id: Int): ColorStateList {
168+
return base.getColorStateList(id)
169+
}
170+
171+
@RequiresApi(Build.VERSION_CODES.M)
172+
override fun getColorStateList(@ColorRes id: Int, theme: Theme?): ColorStateList {
173+
return base.getColorStateList(id, theme)
174+
}
175+
176+
override fun getBoolean(@BoolRes id: Int): Boolean {
177+
return base.getBoolean(id)
178+
}
179+
180+
override fun getInteger(@IntegerRes id: Int): Int {
181+
return base.getInteger(id)
182+
}
183+
184+
@RequiresApi(Build.VERSION_CODES.Q)
185+
override fun getFloat(@DimenRes id: Int): Float {
186+
return base.getFloat(id)
187+
}
188+
189+
override fun getLayout(@LayoutRes id: Int): XmlResourceParser {
190+
return base.getLayout(id)
191+
}
192+
193+
override fun getAnimation(@AnimatorRes @AnimRes id: Int): XmlResourceParser {
194+
return base.getAnimation(id)
195+
}
196+
197+
override fun getXml(@XmlRes id: Int): XmlResourceParser {
198+
return base.getXml(id)
199+
}
200+
201+
override fun openRawResource(@RawRes id: Int): InputStream {
202+
return base.openRawResource(id)
203+
}
204+
205+
override fun openRawResource(@RawRes id: Int, value: TypedValue?): InputStream {
206+
return base.openRawResource(id, value)
207+
}
208+
209+
override fun openRawResourceFd(@RawRes id: Int): AssetFileDescriptor? {
210+
return base.openRawResourceFd(id)
211+
}
212+
213+
override fun getValue(@AnyRes id: Int, outValue: TypedValue?, resolveRefs: Boolean) {
214+
return base.getValue(id, outValue, resolveRefs)
215+
}
216+
217+
override fun getValueForDensity(
218+
@AnyRes id: Int,
219+
density: Int,
220+
outValue: TypedValue?,
221+
resolveRefs: Boolean
222+
) {
223+
return base.getValueForDensity(id, density, outValue, resolveRefs)
224+
}
225+
226+
@SuppressLint("DiscouragedApi")
227+
@Discouraged("Proxied Discourage")
228+
override fun getValue(name: String?, outValue: TypedValue?, resolveRefs: Boolean) {
229+
return base.getValue(name, outValue, resolveRefs)
230+
}
231+
232+
override fun obtainAttributes(set: AttributeSet?, @StyleableRes attrs: IntArray?): TypedArray? {
233+
return base.obtainAttributes(set, attrs)
234+
}
235+
236+
@Deprecated("Proxied Deprecation")
237+
override fun updateConfiguration(config: Configuration?, metrics: DisplayMetrics?) {
238+
return base.updateConfiguration(config, metrics)
239+
}
240+
241+
override fun getDisplayMetrics(): DisplayMetrics? {
242+
return base.displayMetrics
243+
}
244+
245+
override fun getConfiguration(): Configuration? {
246+
return base.configuration
247+
}
248+
249+
@SuppressLint("DiscouragedApi")
250+
@Discouraged("Proxied Discourage")
251+
override fun getIdentifier(name: String?, defType: String?, defPackage: String?): Int {
252+
return base.getIdentifier(name, defType, defPackage)
253+
}
254+
255+
override fun getResourceName(@AnyRes resid: Int): String? {
256+
return base.getResourceName(resid)
257+
}
258+
259+
override fun getResourcePackageName(@AnyRes resid: Int): String? {
260+
return base.getResourcePackageName(resid)
261+
}
262+
263+
override fun getResourceEntryName(@AnyRes resid: Int): String? {
264+
return base.getResourceEntryName(resid)
24265
}
25266

26-
override fun getString(id: Int, vararg formatArgs: Any?): String {
27-
return baseContext.getStringT(tolgee, id, *formatArgs.filterNotNull().toTypedArray())
267+
override fun parseBundleExtras(parser: XmlResourceParser?, outBundle: Bundle?) {
268+
return base.parseBundleExtras(parser, outBundle)
28269
}
29270

30-
override fun getQuantityString(id: Int, quantity: Int): String {
31-
return baseContext.resources.getQuantityStringT(tolgee, id, quantity)
271+
override fun parseBundleExtra(tagName: String?, attrs: AttributeSet?, outBundle: Bundle?) {
272+
return base.parseBundleExtra(tagName, attrs, outBundle)
32273
}
33274

34-
override fun getQuantityString(id: Int, quantity: Int, vararg formatArgs: Any?): String {
35-
return baseContext.resources.getQuantityStringT(tolgee, id, quantity, *formatArgs.filterNotNull().toTypedArray())
275+
@RequiresApi(Build.VERSION_CODES.R)
276+
override fun addLoaders(vararg loaders: ResourcesLoader?) {
277+
return base.addLoaders(*loaders)
36278
}
37279

38-
override fun getStringArray(id: Int): Array<out String?> {
39-
return baseContext.resources.getStringArrayT(tolgee, id)
280+
@RequiresApi(Build.VERSION_CODES.R)
281+
override fun removeLoaders(vararg loaders: ResourcesLoader?) {
282+
return base.removeLoaders(*loaders)
40283
}
41284

42-
override fun getText(id: Int): CharSequence {
43-
return baseContext.getTextT(tolgee, id)
285+
override fun getResourceTypeName(@AnyRes resid: Int): String? {
286+
return base.getResourceTypeName(resid)
44287
}
45288
}

0 commit comments

Comments
 (0)