All Projects → JcMinarro → Philology

JcMinarro / Philology

Licence: apache-2.0
An easy way to dynamically replace Strings of your Android App or provide new languages Over-the-air without needed to publish a new release on Google Play.

Programming Languages

kotlin
9241 projects

Projects that are alternatives of or similar to Philology

tplv
👣 Nano string template library for modern, based on ES6 template string syntax.
Stars: ✭ 31 (-93.23%)
Mutual labels:  strings
indexed-string-variation
Experimental JavaScript module to generate all possible variations of strings over an alphabet using an n-ary virtual tree
Stars: ✭ 16 (-96.51%)
Mutual labels:  strings
Interview Questions In Javascript
A mostly reasonable collection of technical software development interview questions solved in Javascript
Stars: ✭ 3,268 (+613.54%)
Mutual labels:  strings
pytextcodifier
📦 Turn your text files into codified images or your codified images into text files.
Stars: ✭ 14 (-96.94%)
Mutual labels:  strings
learning R
List of resources for learning R
Stars: ✭ 32 (-93.01%)
Mutual labels:  strings
js-utils
A collection of dependency-free JavaScript utilities 🔧
Stars: ✭ 22 (-95.2%)
Mutual labels:  strings
LaTeXStrings.jl
convenient input and display of LaTeX equation strings for the Julia language
Stars: ✭ 152 (-66.81%)
Mutual labels:  strings
Cracking The Coding Interview
📚 C++ and Python solutions with automated tests for Cracking the Coding Interview 6th Edition.
Stars: ✭ 396 (-13.54%)
Mutual labels:  strings
Localizer-Android
Gradle plugin which simplifies Android string resources & translations synchronization with POEditor.
Stars: ✭ 21 (-95.41%)
Mutual labels:  strings
Data Structures Algorithms
My implementation of 85+ popular data structures and algorithms and interview questions in Python 3 and C++
Stars: ✭ 273 (-40.39%)
Mutual labels:  strings
Assembly-Lib
A 16-bits x86 DOS Assembly library that provides many useful functions for developing programs. It has both VGA grapics functions as well as general purpose utilities. The main purpose of this library was to be able to implement simple DOS games (in Assembly) using VGA (320x200, 256 colors) display.
Stars: ✭ 36 (-92.14%)
Mutual labels:  strings
static-string-cpp
Compile-time string manipulation library for modern C++
Stars: ✭ 34 (-92.58%)
Mutual labels:  strings
Cuerdas
String manipulation library for Clojure(Script)
Stars: ✭ 272 (-40.61%)
Mutual labels:  strings
TyStrings
strings file tool for iOS / macOS developers
Stars: ✭ 15 (-96.72%)
Mutual labels:  strings
Androidlocalizeplugin
🌏 Android localization plugin. support multiple languages, no need to apply for key.
Stars: ✭ 352 (-23.14%)
Mutual labels:  strings
strings-truncation
Truncate strings with fullwidth characters and ANSI codes.
Stars: ✭ 45 (-90.17%)
Mutual labels:  strings
BhimIntegers
BhimIntegers🚀 is a C++ library that is useful when we are dealing with BigIntegers💥💥. We can handle big integers (integers having a size bigger than the long long int data type) and we can perform arithmetic operations📘 like addition, multiplication, subtraction, division, equality check, etc📐📐. Also, there are several functions like factorial, …
Stars: ✭ 43 (-90.61%)
Mutual labels:  strings
Stringz
A lightweight and powerful editor for localizing iOS, macOS, tvOS, and watchOS applications.
Stars: ✭ 440 (-3.93%)
Mutual labels:  strings
Stringr
A fresh approach to string manipulation in R
Stars: ✭ 397 (-13.32%)
Mutual labels:  strings
String Theory
Identify and reduce memory used by duplicate .NET strings
Stars: ✭ 273 (-40.39%)
Mutual labels:  strings

Philology

CircleCI Download ko-fi

An easy way to dynamically replace Strings of your Android App or provide new languages Over-the-air without needed to publish a new release on Google Play.

Why should I be interested in Philology

How String resources work on Android?

Android Resources provide us with an easy way to internationalise our App: a file with all the strings used by our App and a copy of it for every language the App is translated to. Android OS does the rest choosing the proper file depending on device's language.

That is perfect and I don't want to stop using it.

The problem

These strings are hardcoded inside our App. If there's a typo or you find a better way to express something, a new version of the App needs to be deployed to include the newer translation. This is a slow process and a poor user experience. We all know users take their time to update an app (if they ever do so) and there's also the time Google Play takes to make a new version of an app available to all users.

How Philology solves this problem?

Philology doesn't replace the way you are using resources in your current Android Development. Instead, it improves the process by intercepting the value returned from your hardcoded translation files inside of the app and check if there is a newer value in the server. This allows for typo fixing, better wording or even for adding a new language. All in real time, without releasing a new version of the App.

With Philology you could replace hardcoded texts instantly and win time before the new release is done.

Getting Started

Dependency

Philology use ViewPump library to intercept the view inflate process and reword strings resources. It allows you to use other libraries like Calligraphy that intercept the view inflate process

dependencies {
    compile 'com.jcminarro:Philology:2.1.0'
    compile 'io.github.inflationx:viewpump:2.0.3'
}

Usage

Initialize Philology and ViewPump

Define your PhilologyRepositoryFactory who provides PhilologyRepository according with the selected Locale on the device. Kotlin:

class App : Application() {
    override fun onCreate() {
        super.onCreate()
        // Init Philology with our PhilologyRepositoryFactory
        Philology.init(MyPhilologyRepositoryFactory)
        // Add PhilologyInterceptor to ViewPump
        // If you are already using Calligraphy you can add both interceptors, there is no problem
        ViewPump.init(ViewPump.builder().addInterceptor(PhilologyInterceptor).build())
    }
}

object MyPhilologyRepositoryFactory : PhilologyRepositoryFactory {
    override fun getPhilologyRepository(locale: Locale): PhilologyRepository? = when (locale.language) {
        Locale.ENGLISH.language -> EnglishPhilologyRepository
        Locale("es", "ES").language -> SpanishPhilologyRepository
        // If we don't support a language we could return null as PhilologyRepository and
        // values from the strings resources file will be used
        else -> null
    }
}

object EnglishPhilologyRepository : PhilologyRepository {
    override fun getText(key: String): CharSequence? = when (key) {
        "label" -> "New value for the `label` key, it could be fetched from a database or an external API server"
        // If we don't want reword a strings we could return null and the value from the string resources file will be used
        else -> null
    }

    override fun getPlural(key: String, quantityString: String): CharSequence?  = when ("${key}_$quantityString") {
        "plurals_label_one" -> "New value for the `plurals_label` key and `one` quantity keyword"
        "plurals_label_other" -> "New value for the `plurals_label` key and `other` quantity keyword"
        // If we don't want reword a plural we could return null and the value from the string resources file will be used
        else -> null
    }

   override fun getTextArray(key: String): Array<CharSequence>? = when (key) {
        "days" -> arrayOf(
            "Monday",
            "Tuesday",
            "Wednesday",
            "Thursday",
            "Friday",
            "Saturday",
            "Saturday"
        )
        // If we don't want reword a string array we could return null and the value from the string resources file will be used
        else -> null
    }
}

object SpanishPhilologyRepository : PhilologyRepository { /* Implementation */ }

Java:

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        PhilologyRepositoryFactory repositoryFactory = new MyPhilologyRepositoryFactory();
        Philology.INSTANCE.init(repositoryFactory);
        ViewPump.init(ViewPump.builder().addInterceptor(PhilologyInterceptor.INSTANCE).build());
    }
}

public class MyPhilologyRepositoryFactory extends PhilologyRepositoryFactory {
    @Nullable
    @Override
    public PhilologyRepository getPhilologyRepository(@NotNull Locale locale) {
        if (Locale.ENGLISH.getLanguage().equals(locale.getLanguage())) {
            return new EnglishPhilologyRepository();
        }
        return null;
    }
}

public class EnglishPhilologyRepository extends PhilologyRepository {
    @Nullable
    @Override
    public CharSequence getText(@NotNull Resource resource) { /* Implementation */}
}

Inject into Context

Wrap the Activity Context. Kotlin:

class BaseActivity : AppCompatActivity() {
    override fun attachBaseContext(newBase: Context) {
        super.attachBaseContext(ViewPumpContextWrapper.wrap(Philology.wrap(newBase)))
    }
}

Java:

public class BaseActivity extends AppCompatActivity {
    @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(ViewPumpContextWrapper.wrap(Philology.INSTANCE.wrap(newBase)));
    }
}

That is all

CustomViews

Philology allows you to reword your own CustomViews, the only that you need to do is provide an implementation of ViewTransformer that rewords the text fields used by your CustomView. The Context used to inflate your CustomView is already wrapped by the library, so, you can assign the @StringRes used on the .xml file that will be provided on the reword() method.

Kotlin:

object MyCustomViewTransformer : ViewTransformer {
    override fun reword(view: View, attributeSet: AttributeSet): View = view.apply {
        when (this) {
            is MyCustomView -> reword(attributeSet)
        }
    }

    private fun MyCustomView.reword(attributeSet: AttributeSet) {
        @StringRes val textResId = context.getStringResourceId(attributeSet, R.styleable.MyCustomView_text)
        if (textResId > 0) setTextToMyCustomView(textResId)
    }
}

Java:

public class MyCustomViewTransformer extends ViewTransformer {
    private static String MY_CUSTOM_ATTRIBUTE_NAME = "text";
    @NotNull
    @Override
    public View reword(@NotNull View view, @NotNull AttributeSet attributeSet) {
        if (view instanceof MyCustomView) {
            MyCustomView myCustomView = (MyCustomView) view;
            int textResId = getStringResourceId(myCustomView.getContext(), attributeSet, R.styleable.MyCustomView_text);
            if (textResId > 0) {
                myCustomView.setTextToMyCustomView(textResId);
            }
        }
        return view;
    }
}

After you implement your ViewTransformer you need to provide it to Philology injecting a ViewTransformerFactory by the init() method Kotlin:

class App : Application() {
    override fun onCreate() {
        super.onCreate()
        Philology.init(MyPhilologyRepositoryFactory, MyViewTransformerFactory)
        ViewPump.init(ViewPump.builder().addInterceptor(PhilologyInterceptor.INSTANCE).build());
    }
}

object MyViewTransformerFactory : ViewTransformerFactory{
    override fun getViewTransformer(view: View): ViewTransformer = when (view) {
        is MyCustomView -> MyCustomViewTransformer
        else -> null
    }
}

Java:

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        PhilologyRepositoryFactory repositoryFactory = new MyPhilologyRepositoryFactory();
        ViewTransformerFactory viewTransformerFactory = new MyCustomViewTransformerFactory();
        Philology.INSTANCE.init(repositoryFactory, viewTransformerFactory);
        ViewPump.init(ViewPump.builder().addInterceptor(PhilologyInterceptor.INSTANCE).build());
    }
}

public class MyCustomViewTransformerFactory implements ViewTransformerFactory {
    @Nullable
    @Override
    public ViewTransformer getViewTransformer(@NotNull View view) {
        if (view instanceof MyCustomView) {
            return new MyViewTransformer();
        }
        return null;
    }
}

Do you want to contribute?

Feel free to add any useful feature to the library, we will be glad to improve it with your help. I'd love to hear about your use case too, especially if it's not covered perfectly.

Developed By

Follow me on Twitter Add me to Linkedin Follow me on Twitter

License

Copyright 2018 Jc Miñarro

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].