pebble/devsite/source/_guides/tools-and-resources/internationalization.md
2025-02-24 18:58:29 -08:00

9.6 KiB

title description guide_group order
Internationalization How to localize an app to multiple languages. tools-and-resources 5

When distributing an app in the Pebble appstore, it can be downloaded by Pebble users all over the world. Depending on the app, this means that developers may want to internationalize their apps for a varierty of different locales. The locale is the region in the world in which the user may be using an app. The strings used in the app to convey information should be available as translations in locales where the app is used by speakers of a different language. This is the process of localization. For example, users in France may prefer to see an app in French, if the translation is available.

Internationalization on Pebble

The Pebble SDK allows an app to be localized with the Internationalization API. Developers can use this to adjust how their app displays and behaves to cater for users in non-English speaking countries. By default all apps are assumed to be in English. Choose the user selected locale using i18n_get_system_locale() or to force one using setlocale().

Note: The app's locale also affects strftime(), which will output different strings for different languages. Bear in mind that these strings may be different lengths and use different character sets, so the app's layout should scale accordingly.

Locales Supported By Pebble

This is the set of locales that are currently supported:

Language Region Value returned by i18n_get_system_locale()
English United States "en_US"
French France "fr_FR"
German Germany "de_DE"
Spanish Spain "es_ES"
Italian Italy "it_IT"
Portuguese Portugal "pt_PT"
Chinese China "en_CN"
Chinese Taiwan "en_TW"

When the user's preferred language is set using the Pebble Time mobile app, the required characters will be loaded onto Pebble and will be used by the compatible system fonts. This means that any custom fonts used should include the necessary locale-specific characters in order to display correctly.

Translating an App

By calling setlocale(LC_ALL, ""), the app can tell the system that it supports internationalization. Use the value returned by setlocale() to translate any app strings. The implementation follows the libc convention. Users may expect text strings, images, time display formats, and numbers to change if they use an app in a certain language.

Below is a simple approach to providing a translation:

// Use selocale() to obtain the system locale for translation
char *sys_locale = setlocale(LC_ALL, "");

// Set the TextLayer's contents depending on locale
if (strcmp("fr_FR", sys_locale) == 0) {
  text_layer_set_text(s_output_layer, "Bonjour tout le monde!");
} else if ( /* Next locale string comparison */ ) {
  /* other language cases... */
} else {
  // Fall back to English
  text_layer_set_text(s_output_layer, "Hello, world!");
}

The above method is most suitable for a few strings in a small number of languages, but may become unwieldly if an app uses many strings. A more streamlined approach for these situations is given below in Using Locale Dictionaries.

Using the Locale in JavaScript

Determine the language used by the user's phone in PebbleKit JS using the standard navigator property:

console.log('Phone language is ' + navigator.language);
[INFO    ] js-i18n-example__1.0/index.js:19 Phone language is en-US

This will reflect the user's choice of 'Language & Input' -> 'Language' on Android and 'General' -> 'Language & Region' -> 'i[Pod or Phone] Language' on iOS.

Note: Changing the language on these platforms will require a force close of the Pebble app or device restart before changes take effect.

Choosing the App's Locale

It is also possible to explicitly set an app's locale using setlocale(). This is useful for providing a language selection option for users who wish to do so. This function takes two arguments; the category and the locale string. To set localization only for the current time, use LC_TIME as the category, else use LC_ALL. The locale argument accepts the ISO locale code, such as "fr_FR". Alternatively, set locale to NULL to query the current locale or "" (an empty string) to set the app's locale to the system default.

// Force the app's locale to French
setlocale(LC_ALL, "fr_FR");

To adapt the way an application displays time, call setlocale(LC_TIME, ""). This will change the locale used to display time and dates in strftime() without translating any strings.

Effect of Setting a Locale

Besides returning the value of the current system locale, calling setlocale() will have a few other effects:

  • Translate month and day names returned by strftime() %a, %A, %b, and %B.

  • Translate the date and time representation returned by strftime() %c.

  • Translate the date representation returned by strftime() %x.

Note that currently the SDK will not change the decimal separator added by the printf() family of functions when the locale changes; it will always be a . regardless of the currently selected locale.

Using Locale Dictionaries

A more advanced method to include multiple translations of strings in an app (without needing a large number of if, else statements) is to use the Locale Framework. This framework works by wrapping every string in the project's src directory in the _() and replacing it with with a hashed value, which is then used with the current locale to look up the translated string from a binary resource file for that language.

Instructions for using this framework are as follows:

  • Add hash.h, localize.h and localize.c to the project. This will be the src directory in the native SDK.

  • Include localize.h in any file to be localized:

#include "localize.h"
  • Initalize the framework at the start of the app's execution:
int main(void) {
  // Init locale framework
  locale_init();

  /** Other app setup code **/
}
  • For every string in each source file to be translated, wrap it in _():
text_layer_set_text(some_layer, _("Meal application"));
  • Save all source files (this will require downloading and extracting the project from 'Settings' on CloudPebble), then run get_dict.py from the project root directory to get a JSON file containing the hashed strings to be translated. This file will look like the one below:
{
  "1204784839": "Breakfast Time",
  "1383429240": "Meal application",
  "1426781285": "A fine meal with family",
  "1674248270": "Lunch Time",
  "1753964326": "Healthy in a hurry",
  "1879903262": "Start your day right",
  "2100983732": "Dinner Time"
}
  • Create a copy of the JSON file and perform translation of each string, keeping the equivalent hash values the same. Name the file according to the language, such as locale_french.json.

  • Convert both JSON files into app binary resource files:

$ python dict2bin.py locale_english.json
$ python dict2bin.py locale_french.json
  • Add the output binary files as project resources as described in {% guide_link app-resources/raw-data-files %}.

When the app is compiled and run, the _() macro will be replaced with calls to locale_str(), which will use the app's locale to load the translated string out of the binary resource files.

Note: If the translation lookup fails, the framework will fall back to the English binary resource file.

Publishing Localized Apps

The appstore does not yet support localizing an app's resources (such as name, description, images etc), so use this guide to prepare the app itself. To cater for users viewing appstore listings in a different locale, include a list of supported languages in the listing description, which itself can be written in multiple languages.

The format for a multi-lingual appstore description should display the supported languages at the top and a include a copy in each language, as shown in the example below:

Now supports - French, German and Spanish.

This compass app allows you to navigate in any directions from your wrist! Simply open the app and tilt to show the layout you prefer.

Français

Cette application de la boussole vous permet de naviguer dans toutes les directions à partir de votre poignet! Il suffit d'ouvrir l'application et de l'inclinaison pour montrer la disposition que vous préférez.

Deutsch

Dieser Kompass App ermöglicht es Ihnen, in jeder Richtung vom Handgelenk zu navigieren! Öffnen Sie einfach die App und kippen, um das Layout Sie bevorzugen zu zeigen.

Español

Esta aplicación brújula le permite navegar en cualquier dirección de la muñeca ! Basta con abrir la aplicación y la inclinación para mostrar el diseño que prefiera.