Jak vytvořit Java aplikaci s podporou více překladů

Při vytváření aplikace musíte myslet na spoustu věcí. Dneska se budu zabývat tvorbou multi jazykových aplikací. K čemu je to vůbec dobré?  Pokud vytvoříte aplikaci v češtině, budou ji používat pouze lidé, kteří rozumí česky. Pokud aplikaci uděláte anglicky, bude rozsah uživatelů, kteří budou schopni s aplikací pracovat mnohem větší. Pořád bude ale rozsah uživatelů omezen použitým jazykem.

Je tedy dobré se tohoto omezení zbavit. Samozřejmě zapomeňte na něco podobného:

if (jazyk == "český")
    zobraz("Ahoj!");
else if (jazyk == "anglicky")
    zobraz("Hello!");
else ...

Tohle je totiž snad ten nejhorší způsob, jak problém s jazyky vyřešit. Co když bude třeba přidat nový jazyk? Bude se muset upravit všechny zdrojáky, které pracují s texty. Každý zásah do zdrojového kódu sebou nese riziko zanesení chyby a v tomto případě, kdy se bude upravovat dost kódu, je velmi pravděpodobné, že dřív nebo později k chybě dojde. Navíc nemáte texty nijak pohromadě a jejich hledání a úprava je složitá.

Mnohem lepší je mít uložené texty někde mimo. Když pak budete chtít editovat texty, stačí jen upravit soubor obsahující texty a nemusíte znovu překládat aplikaci. Pokud bude soubor snadno editovatelný a jeho struktura bude jednoduchá, budou moct na překladu pracovat i uživatelé – neprográmatoři. Ještě lepší řešení je dodávat lokalizační program, který umožní uživatelům editovat jazyky ještě snadněji. Jak toho docílit ve vaší Java aplikaci si ukážeme na názorném příkladu.

Vytvoření projektu

Budu popisovat postup v IDE Eclipse, budu se ale snažit popsat postup i obecně, aby byla možnost využít i jiné nástroje. Nejdříve si vytvoříme nový Java project s názvem LanguageProject.

Nyní vytvoříme novou třídu s názvem LanguageExample, která by měla po vytvoření vypadat takto:

public class LanguageExample {
 
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
	}

}

Jako první si vytvoříme obecné konstanty, které budou určovat název jednotlivých komponent.

        public final static String WINDOW_TITLE = "window_title";
	public final static String LABEL_TEXT = "label_text";
	public final static String BUTTON_OK_TEXT = "button_ok_text";
	public final static String BUTTON_CANCEL_TEXT = "button_cancel_text";

Tento krok se může zdát zbytečný, protože zde se identifikátory konstant shodují s jejich obsahem. Tyto řetězce popisují jejich obsah. Například WINDOW_TITLE má popisovat řetězec okna. Co když ale zjistíme, že řetězec window_title dostatečně nepopisuje daný řetězec? Bude to dělat problémy při lokalizaci aplikace do jiného jazyka. Díky použití konstant můžete jednoduše změnit obsah konstanty, aniž byste museli měnit cokoliv dalšího v kódu.

Použití knihovny LanguageManager

Teď si udělám takovou malou reklamu a doporučím použít knihovnu LanguageManager, která je součásti projektu EasyLocalization. Knihovnu můžete stáhnout přímo z její domovské stránky na SourceForge.net. LanguageManager je dnes k dispozici ve verzi 0.90, používám ho ale bez problémů.

Stáhněte si tedy knihovnu LanguageManager.jar třeba do adresáře lib, který vytvoříte v adresáři projektu.

K tomu, abyste mohli používat tuto knihovnu, musíte ji přidat do Build path. Klikněte v menu na Project -> Properties a zde vyberte v seznamu položku Java Build Path. Poté vyberte záložku Libraries a klikněte na Add External JARs… (viz obrázek)

Nastavení build path v Eclipse

Nastavení build path v Eclipse

Díky tomu můžeme v našem projektu pracovat s touto knihovnou. Měl bych ještě uvést, jak tato knihovna pracuje. LanguageManager je pouze interface. Implementace je schovaná ve třídě LanguageManagerImpl. Implementace má private kontsruktor, což znamená, že nemůžete vytvořit instanci třídy pomocí operátoru new. LanguageManagerImpl je totiž singleton, takže najednou může existovat pouze jediná instance této třídy. Instanci získáte zavoláním

LanguageManager lm = LanguageManagerImpl.getInstance();

Po prvním volání getInstance() se načtou jazyky ze souboru ./res/lang.xml. Proto si nyní vytvoříme jednoduchý jazykový soubor. K jeho vytvoření použijeme LanguageEditor, který je součástí projektu EasyLocalization a najdete ho opět na SourceForge.net.

Vytvoření lokalizačního souboru

Spusťte aplikaci LanguageEditor.jar a postupně zadejte Languages -> Add new language a vložte například dva jazyky – english a czech. Poté přidejte jednotlivé řetězce, které se budou lokalizovat. Languages -> Add new string. Nyní vložíme postupně řetězce window_title, label_text, button_ok_text a button_cancel_text.

Až budete mít řetězce vloženy v tabulce, zvolte Main -> Save As a uložte si soubor do adresáře res v adresáři projektu pod názvem lang.xml.

Ukázka LanguageEditoru

Ukázka LanguageEditoru

Obsah souboru nás nemusí zajímat. Pokud ale chcete vědět, jak jsou data uloženy, ukážu zde kód, který aplikace vygeneruje:

< ?xml version="1.0" encoding="UTF-8" standalone="no"?>
<languages>
  <english>
    <window_title>Localized application</window_title>
    <label_text>This is example of localized application.</label_text>
    <button_cancel_text>Cancel</button_cancel_text>
    <button_ok_text>Apply</button_ok_text>
  </english>
  <czech>
    <window_title>Lokalizovaná aplikace</window_title>
    <label_text>Toto je ukázka lokalizované aplikace</label_text>
    <button_cancel_text>Zrušit</button_cancel_text>
    <button_ok_text>Potvrdit</button_ok_text>
  </czech>
</languages>

Použití vytvořených řetězců

Máme tedy k dispozici texty v anglické a české verzi. Ukážeme si tedy jednoduchou GUI aplikaci, na které bude vidět lokalizovaný text. Obsah naší třídy LanguageExample tedy bude následující:

import java.awt.FlowLayout;
 
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
 
import net.dadajax.languagemanager.LanguageManager;
import net.dadajax.languagemanager.LanguageManagerImpl;
 
public class LanguageExample {
 
	public final static String WINDOW_TITLE = "window_title";
	public final static String LABEL_TEXT = "label_text";
	public final static String BUTTON_OK_TEXT = "button_ok_text";
	public final static String BUTTON_CANCEL_TEXT = "button_cancel_text";
 
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// získáme instanci třídy LanguageManagerImpl a načteme data ze souboru
		LanguageManager lm = LanguageManagerImpl.getInstance();
		// nastavíme jazyk na češtinu
		lm.setLanguage("czech");
 
		// Vytvoříme GUI
		JFrame mainWindow = new JFrame();
		mainWindow.setTitle(lm.loc(WINDOW_TITLE));
 
		mainWindow.setLayout(new FlowLayout());
 
		JLabel label = new JLabel();
		label.setText(lm.loc(LABEL_TEXT));
		mainWindow.add(label);
 
		JButton buttonOk = new JButton();
		buttonOk.setText(lm.loc(BUTTON_OK_TEXT));
		mainWindow.add(buttonOk);
 
		JButton buttonCancel = new JButton();
		buttonCancel.setText(lm.loc(BUTTON_CANCEL_TEXT));
		mainWindow.add(buttonCancel);
 
		mainWindow.setVisible(true);
		mainWindow.pack();
	}
 
}

Po spuštění aplikace uvidíme toto:

Česká verze programu

Česká verze programu

Pokud změníme řádek

lm.setLanguage("czech");

na

lm.setLanguage("english");

bude vypadat aplikace takto:

Anglická verze programu

Anglická verze programu

Shrnutí

Jak vidíte, vytvoření takto lehce přeložitelné aplikace nebylo vůbec složité. Vytvoření dalších překladů je už otázka chvilky. Stačí upravit soubor lang.xml (nejlépe pomocí aplikace LanguageEditor). Celý projekt EasyLocalization je navíc uvolněn jako open source, takže si jej můžete upravit dle vlastních představ.

Pokud chcete nabídnout uživateli na výběr z dostupných jazyků, můžete k tomu použít metodu getAvailableLanguagesNames(), která vráti kolekci List<String>, která obsahuje názvy dostupných jazyků.

Určitě vás napadne, jestli je možné jazyky přepínat za běhu aplikace. Ano, je to možné, ale museli byste k tomu aplikaci připravit. To znamená, že byste museli vytvořit nějakou aktualizační metodu, která by nastavila všem komponentám znovu popisek. Tento způsob je ale docela pracný a stále je možnost, že něco zapomenete aktualizovat.

Proto doporučuju při změně jazyku uložit nový jazyk do nějakého konfiguračního souboru a z toho potom při startu aplikace načíst název jazyka. Díky tomu budete mít jistotu, že bude přeloženo vše korektně a nebude vás to stát žádný čas navíc. Změna jazyka v aplikaci je navíc operace, kterou uživatel provede nejčastěji jednou, takže jeden restart aplikace určitě nikomu tolik vadit nebude. Samozřejmě, že jsou případy, kdy aplikace musí běžet nonstop, takže u takových aplikací musíte sáhnout po složitějším způsobu.

Možná vás napadne, co se stane, když se nějaký řetězec v souboru lang.xml nepřeloží. Bude poté aplikace fungovat? Pokud LanguageManager nenajde lokalizovaný řetězec v souboru, vrátí původní řetězec ohraničený otazníky. Takže třeba v našem případě by volání lm.loc(ahoj); vrátilo „?ahoj?“. Díky tomu bude uživatel alespoň trochu schopný se v aplikaci pohybovat a například přepnout jazyk na jiný. Proto je dobré uvádět popisné řetězce co nejpopisněji. Takové „button1“ uživateli asi neřekne tolik, jako třeba „button_ok“. Taky to usnadní práci těm, kteří budou aplikaci překládat do jiných jazyků.

Myslím, že už jsem zde uvedl vše, co jsem původně zamýšlel. Budu rád za jakékoliv připomínky k tomuto článku. Pokud je vám něco z článku nejasné, klidně se zeptejte v komentářích pod článkem 😉

Příspěvek byl publikován v rubrice Programování. Můžete si uložit jeho odkaz mezi své oblíbené záložky.

1 komentář u Jak vytvořit Java aplikaci s podporou více překladů

  1. dadajax napsal:

    Včera jsem ještě dodatečně objevil chyby v knihovně LanguageManager. Dnes ráno jsem to opravil a vydal aktualizovanou verzi 0.91. Stahovat můžete opět ze stránky Sourceforge.net.

    Knihovna obsahovala několik chyb, které se týkaly defaultního umístění lokalizačního souboru. Pokud se soubor nacházel jinde, způsobovalo to pád aplikace. Nyní by mělo být už vše ok a LanguageManager funguje i v případě, že žádný lokalizační soubor neexistuje. V tomto případě vrací jen původní řetězce obehnané otazníky.

    Pokud tedy stáhnete LanguageManager nyní, nebudete mít žádné problémy a tento komentář můžete ignorovat 😉

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *