Android Globalization Best Practices

First, what is Globalization?
Globalization, also referred to as Internationalization or the i18n standard; is the process of designing 
a software application so that it can potentially be adapted to various languages and regions without engineering changes.

It's a process that affects how you engineer the UX, UI and code of your application. It's not an easy 
process to cover all aspects, but once you get your application guidelines right, and build your design 
and engineering processes around it, you should be able to pull it through.

What about Localization?
Localization; also referred to as i10n, is different from Globalization. Localization requires you to 
add appropriate resources to your software to ensure that a given country, locale, language, or culture
 is supported. Or, its the process of adding another language to your app, which is hopefully designed for i18n!

All Text Must be Resource Based
Well, this is a basic thing, but it is important to highlight. Don't hardcode any strings either in your 
screen layouts nor in your application code; strings.xml is a key artifact in your application. If you mistakenly 
hardcode strings, it will be a costly process to fix.

Android Studio will warn you if you leave a string hardcoded, but I prefer to treat these as errors and log an 
issue when one is detected and fix prior to a release.


This is a common pitfall that designers fall in. We usually design our layouts with a single language in mind;
 typically English, and assume that translations will fall into place; Unfortunately, not all languages are 
equal. You should always allow extra space in your layout for text to grow and shrink based on the language 
translation. Perhaps leave a 40-50% space to cater for that. In some cases, you might have to create separate 
layouts to cater for extreme cases.

The IBM Globalization Guidelines page has a good table that compares text size increase when translating from English.

Number of Characters in Text Additional Physical Space Required
Up to 10 100% to 200%
11 to 20 80% to 100%
21 to 30 60% to 80%
31 to 50 40% to 60%
51 to 70 31% to 40%
Over 70 30%
This calculation is based on the number of characters in the text string and includes the spaces and punctuation 
marks within the string. For example, the string "Hello World!" contains twelve characters.

Add Comments to String Resources
There are many cases where strings we use make sense in a one language but can't be translated directly to other
 languages. Especially if we use playful terms. In these cases, ensure your resource file has comments on the context 
of the messages to help your translators better understand the message you need to convey and provide proper translations 
in the target language; whether in a localized playful manner, or a more standard language.

Never, Ever Concatenate
We tend to fall into the temptation of concatenating strings to build dynamic messages, and we forget that word ordering 
is different across languages. Whether we are adding user names, amounts, we should always use string formatting.



Use Proper Plural Strings

Don't try to build your quantity/amount texts in code by assigning plural nouns based on the value you have, as 
different languages will have different ways of representing amounts and quantities. So if you are trying to say: 
I ate 3 cookies, don't use the following resource strings


Handle Dates Properly

Date formats vary across cultures, so make sure that your application uses the correct format for handling dates
 by using the DateUtils and DateFormat classes. Don’t use hardcoded date formats such as MM/dd/yyyy, you’ll just 
confuse everyone.

You can use DateUtils to show a relative timespan string


It’s not only display that needs to be catered for. When you accept date values from users, or try to capture stamps,
 make sure you convert them to a standard culture-neutral format prior to storage. Otherwise, you won’t be able to 
analyze or render properly if a user switches cultures.


Dynamic Formatting

When you need to format or highlight part of the text you are showing (color, weight, etc.) don’t use index to 
manipulate a ForegroundColorSpan. This will get you in trouble with translated strings. Use HTML formatting 
instead within your resource strings.


   
Colors

This is a frequently missed one. Colors have different meanings in different cultures. For example, while Green
 is used to indicate positive increase or trend; like in a stock price, in China, Red is used for that. You should 
also cater for this and support different colors for different cultures.

Mobile Automation using Appium and Java (Page Objects)


********************************Main Test File:-*************************************************************
package com.example;
 import io.appium.java_client.android.AndroidDriver;
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.concurrent.TimeUnit;
 import org.openqa.selenium.By;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.remote.DesiredCapabilities;
 import org.openqa.selenium.support.ui.ExpectedConditions;
 import org.openqa.selenium.support.ui.WebDriverWait;
 import org.testng.Assert;
 import org.testng.annotations.AfterTest;
 import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;

import com.example.pages.HannaPagesTest;
 public class HannaTest 
 {
  AndroidDriver driver;
  @BeforeTest
  public void setUp() throws MalformedURLException 
  {
      
      DesiredCapabilities capabilities = new DesiredCapabilities();
      capabilities.setCapability("deviceName", "ZX1B32FFXF");
      capabilities.setCapability("appPackage", "com.hannainst.hannalab");
      capabilities.setCapability("appActivity","com.hannainst.hannalab.ManagerActivity");
      driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
      driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
      WebDriverWait wait = new WebDriverWait(driver, 300);
      wait.until(ExpectedConditions.elementToBeClickable(By.className("android.widget.RelativeLayout")));
      
}
  @Test(priority = 0)
  public void checkAppElementPresent() 
  {
   HannaPagesTest hanna=new HannaPagesTest(driver); 
   if(hanna.verifyResult1("No Probe Connected"))
    System.out.println("App Launch TC Passed");
   else
    System.out.println("App Launch TC Failed");
      
  }
  
  @Test(priority = 1)
  public void CheckAppVersion() 
  {
   HannaPagesTest hanna=new HannaPagesTest(driver); 
   if(hanna.verifyResult2("Version 2.0.0 Beta"))
    System.out.println("App Version TC Passed");
   else
    System.out.println("App Version TC Failed");
      
  }
  
  
  @AfterTest
  public void End() throws IOException 
  {
   
   //driver.removeApp("com.hannainst.hannalab");
   driver.resetApp();
   driver.quit();  
   //driver.close();
  }
 }


************************Page Object Test File************************************
package com.example.pages;

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.PageFactory;

import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.pagefactory.AndroidFindBy;
import io.appium.java_client.pagefactory.AppiumFieldDecorator;

public class HannaPagesTest 
{
 
 public HannaPagesTest(AndroidDriver driver)
 {
  PageFactory.initElements( new AppiumFieldDecorator(driver), this);
 }
 @AndroidFindBy(name="No Probe Connected")
 public static WebElement text1;
 
 @AndroidFindBy(xpath="//*[@class='android.widget.ImageButton' and @content-desc='Navigate up']")
 public static WebElement text2;
 
 @AndroidFindBy(id="com.hannainst.hannalab:id/versionName")
 public static WebElement text3;
 
 public boolean verifyResult1(String result)
 {
  if(text1.getText().equals(result))
   return true;
   else
   return false;
 } 
 
 public boolean verifyResult2(String result)
 {
  text2.click();
  if(text3.getText().equals(result))
   return true;
   else
   return false;
 } 
   
 }

***************************************************************************************************************************