-
Notifications
You must be signed in to change notification settings - Fork 9
Home
Loquacious is a library for storing localized resources.
Loquacious requires only a minimum api level of 14.
This library is born as a proof of concept, aiming to decrease the size of android applications. For this, this library aims at:
- Reducing the .arsc symbol table. Instead of having a lot of localization files with strings, they are retrieved on demand. Making the .arsc only have 1 symbol per entry
- Reducing the res/ files. As now you should only define the resources, but empty (they will get downloaded at a later stage)
- Keeping the developer ways of coding intact, you will still reference them as
R.whatever.whatever
Please note that there are still features unimplemented (although the objective is to have them), such as multiple decentralized stores. In the Future
section I describe the missing ones.
Add it to your dependencies build.gradle
compile 'com.saantiaguilera.loquacious:loquacious:latest.version'
compile 'com.saantiaguliera.loquacious:locales:latest.version'
compile 'com.saantiaguilera.loquacious:etc:latest.version' // Unimplemented
First, initialize Loquacious.
Loquacious.initialize(context)
.with(LocaleStore(context)) // Implemented
.with(dimensionStore) // Unimplemented
.with(imagesStore) // Unimplemented
...
Careful this should only be done once!
Forget about which locale you are currently on, simply create the element you would like to save, and commit it to the resources. This will save it for the current system locale
// A string:
Loquacious.resources.put(Item(R.string.string, "string says whatever"))
// An int:
Loquacious.resources.put(Item(R.integer.int, 1234))
// A plural of type 'two'
Loquacious.resources.put(Item(R.plurals.plural, "plural for TWO", 2))
Or in batches
Loquacious.resources.putAll(items)
Since your server wont probably know whats the int value of R.string.whatever, you should rely on Resources#getIdentifier(String,String,String)
, and map the name your server gives you with its integer value.
As you would do normally today on android, but simply use our resources! The methods are exactly the same, so dont worry about anything:
Loquacious.resources.getQuantityString(R.plurals.whatever, 2)
Loquacious.resources.getString(R.string.whatever)
Loquacious.resources.getDimensionPixelSize(R.dimen.whatever) // No idea why would you store a dimension localized.. But you can.
Loquacious.resources.clear()
And we will clear all the stores
If you wish, you can override activity / application / whatever context wrapper you use and do:
override fun attachBaseContext(base: Context?) = super.attachBaseContext(Loquacious.wrap(base!!))
You should do this after initialization!
This will make the context.resources
be the same as Loquacious, thus you can avoid the boilerplate of calling Loquacious.resources
:)
If you haven't noted, the Item
class provides whichever type of value you'd like for storing. This means you can store whichever DTO / object you want in a localized way if you want to.
Loquacious.resources.put(Item(R.string.dto, MyDto(...))
Loquacious.resources.get<MyDto>(R.string.dto)
The locale api currently supports every type of resource except drawable
, as it stores in plain text (and we wont do ultra ugly base64 transformations)
Of course, you should have an easy way to know when the locale changed, so you can retrieve the new strings.. Since I already have to detect this I provide a simple interface for subscribing to this events. Watchout I keep them as strong references!
Loquacious.instance.subscribe { locale: Locale ->
Log.w("Test", "Locale changed to $locale!")
}
And of course, you can unsubscribe them with Loquacious#unsubscribe((Locale) -> Unit)
Of course, you can implement your own storage! Simply implement the Store
class and when initializing add it with .with(store)
:)
If you'd like to store something in a specific storage (else we will find the first that fits that type of resource), you can do it specifying it:
Loquacious.resources.put(Item(R.string.hello, "Hej!"), LocaleStore::class)
Since it would be tedious to keep all instances of the created stores, and there can only be one for each type, just specify the ::class
and we will do the rest.
Pretty much the same deal as storing
Loquacious.resources.get(R.string.hello, LocaleStore::class)
Again, pretty much the same as getting or putting:
Loquacious.resources.clear(LocaleStore::class)
Loquacious already supports proguard transitively. So no need to add custom rules :)
- Create other stores (supporting screen size changes || dpi changes || drawables support || raw files support)
- Add a
loadResources
from raw, with this:- We can have defaults
- We can remove them, lets say the terms&conditions once they have agreed.
- We avoid the network latency it imposes on those resources
In the demo-app you can find a simple example to retrieve a "Hello World" string in the language the phone sets, you'll realize that even though we get the resource as a normal developer does, theres no string written in the resources xmls
If you would wish to check out the demo application, here are the steps to make it work:
- Clone the repository
- Run
./gradlew server:run
on a console. Leave it as it is, since it will be running the server - Run the
demo-app
in an emulator (since I have retrofit configured with the IP of a localhost redirect emulator) - Use it.