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.
Android Globalization Best Practices
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 { AndroidDriverdriver; @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; } } ***************************************************************************************************************************
Subscribe to:
Posts (Atom)