Reputation: 9674
The title says it all. I found a couple of ways to set the application's default layout to RTL using Facebook's I18nManager, but it does that only on second app launch.
code example: I18nManager.forceRTL(true)
I do not want to give users the ability to change languages because the application itself is in Arabic. I've searched everywhere but all talk about how to support RTL and not actually use it as the default layout.
Is there a way to achieve this with I18nManager or do I have to do a couple of changes to my native code?
Upvotes: 16
Views: 8711
Reputation: 2555
the answers by @ataravati and @MageNative are both correct, but they're in Java - while the modern android apps are written in Kotlin. So do add the RTL support in the manifest, and then, in your MainActivity.kt
, do:
// import these in the imports block
import android.content.res.Configuration
import java.util.Locale
// and then, inside the class
override fun onCreate(savedInstanceState: Bundle?) {
// ...[some generated code]
val locale = Locale("he_IL")
Locale.setDefault(locale)
val config = Configuration()
config.setLocale(locale)
resources.updateConfiguration(config, resources.displayMetrics)
// this is autogenerated too, needs to be the last row of the function AFAIK
super.onCreate(null)
}
The latest React Native team recommendation is to use frameworks, and Expo is the only one out there. The way you change native code with Expo is by using plugins and mods (see docs). So here's the expo plugin that will implement the above changes to your built native code every time the app is built from scratch (android
folder doesn't exist):
const { withMainActivity, withAndroidManifest } = require('expo/config-plugins');
function indent(text, spaces = 4) {
return text
.split('\n')
.map((line) => ' '.repeat(spaces) + line)
.join('\n');
}
function updateMainActivity(fileContent) {
const importStatement = 'import android.content.res.Configuration\nimport java.util.Locale\n';
const rtlSupportCode = [
indent('val locale = Locale("he_IL")'),
indent('Locale.setDefault(locale)'),
indent('val config = Configuration()'),
indent('config.setLocale(locale)'),
indent('resources.updateConfiguration(config, resources.displayMetrics)'),
];
const updatedContent = fileContent.split('\n');
// Find the index of the class declaration
const classIndex = updatedContent.findIndex((line) => line.includes('class MainActivity'));
// Insert the import statement before the class declaration
updatedContent.splice(classIndex, 0, importStatement);
// Find the index of the onCreate method
const onCreateIndex = updatedContent.findIndex((line) => line.includes('override fun onCreate'));
// Find the index of the super.onCreate call within the onCreate method
const superOnCreateIndex = updatedContent.findIndex(
(line, index) => index > onCreateIndex && line.includes('super.onCreate'),
);
// Insert the RTL support code before the super.onCreate call
updatedContent.splice(superOnCreateIndex, 0, ...rtlSupportCode);
return updatedContent.join('\n');
}
const withRtlAndroidMainActivity = (config) => {
return withMainActivity(config, async (config) => {
config.modResults.contents = updateMainActivity(config.modResults.contents);
return config;
});
};
const withRtlAndroidManifest = (config) => {
return withAndroidManifest(config, async (config) => {
manifest = config.modResults.manifest;
manifest.application[0].$['android:supportsRtl'] = true;
return config;
});
};
module.exports = [withRtlAndroidMainActivity, withRtlAndroidManifest];
and then use plugin chaining to apply the plugins. Voila :)
Upvotes: 1
Reputation: 5381
You have to do this in two places:
First: In your Manifest's application tag, add support for RTL like this:
<application
...
android:supportsRtl="true"
..>
</application>
Second one: Add this as first line of your onCreate()
method of your activity:
getWindow().getDecorView().setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
If you have a base activity, you can do the same and it will be applied to other child activities.
Upvotes: 0
Reputation: 9155
MageNative's answer is correct. The only thing is setting the locale
like that is deprecated. You need to use the setLocale()
method, like this:
Locale locale = new Locale("fa_IR"); // This is for Persian (Iran)
Locale.setDefault(locale);
Configuration config = new Configuration();
config.setLocale(locale);
getApplicationContext().getResources().updateConfiguration(config, getApplicationContext().getResources().getDisplayMetrics());
You'll need to import java.util.Locale
and android.content.res.Configuration
.
Upvotes: 4
Reputation: 702
First, add RTL support in the manifest like this:
<application
android:name=".application.SampleApplication"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
</application>
Then, on your launcher activity add the following code in onCreate()
.
Locale locale = new Locale("ar");
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getApplicationContext().getResources().updateConfiguration(config, getApplicationContext().getResources().getDisplayMetrics());
Upvotes: 9
Reputation: 359
add this line of code to the most top of the onCreate method (before super and setContentView) of all of your activities:
getWindow().getDecorView().setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
and sure that you have supportRtl equal to True in manifest.
Upvotes: 14