Java - Vícejazyčnost

Moderátor: Mods_senior

Matiseli
Level 2.5
Level 2.5
Příspěvky: 381
Registrován: červen 14
Bydliště: Podíváte-li se roku 2023 na oblohu, tak na té planetě více v pravo
Pohlaví: Nespecifikováno
Stav:
Offline

Java - Vícejazyčnost

Příspěvekod Matiseli » 30 lis 2014 12:47

Java - vícejazyčnost

Java.jpg
Java.jpg (8.7 KiB) Zobrazeno 5216 x


Pro každou významnější aplikaci (de fakto tu, od které se očekává oblíbenost mezi početnější skupinou uživatelů) je důležité její překlad do alepoň 2 jazyků. Způsobů, kterým je toto "vylepšení" realizováno je nespočet - stačí jen pátrat v nalezených výsledcích na Google vyhledávači. V čem vyniká a naopak zaostává mé řešení této problematiky se dozvíte v dalších řádcích.

Úvod do mého přístupu
Ještě před započetím psaní oněch kódů, jsem si stanovil jistá pravidla: Jednoduchost, nenáročnost na hardware (RAM i CPU), pochopitelnost (rozuměj jako čistota kódu), rozšířitelnost - čili jeden z principů OOP (viz. Wikipedie). Právě z důvodu rychlosti jsem se rozhodl, že nehodlám veškerý text pro komunikaci s uživatelem (zatím nepoužívám GUI) zapsat do "jazykového souborů/knihovny", jak tomu u spousty programů bývá, nýbrž vytvořit pole, jehož obsah se následně přidá po každém indexu do pole proměnného (zde ArrayList, kolekce generická). Tímto krokem zajistím měnší závislost na OS (operačním systému) a zároveň se mohu vyvarovat použití přílišného množství proměnných/objektů a algoritmů pro zápis do souboru i následného čtení z něj - má aplikace by byla obecně méně náročná a celkově rychlejší.
V následujících sekcích se vám pokusím popsat a objektivně zhodnotit mé řešení, kdy - z důvodu vyšší pochopitelnosti - budu doplňovat povídání samotnými ukázkami kódů a poskytovat vám užitečné odkazy jako osvětu do problematiky.
PS: Základní návrh vícejazyčnosti je sice jednodušší, avšak ne příliš praktický. My se pokusíme zhmotnit představu, kdy jazyk bude uživateli automaticky navržen s tou možností, že ho může při prvním spuštění aplikace svým vstupem změnit.


Návrh
Nyní si představme, že naše aplikace je vlastně operační systém - potřebuje zavaděč. Zde se sice nejedná o zavaděč v pravém slova smyslu (viz. Wikipedie) - tento má totiž za úkol načíst jazykový balíček a následně zavést (nabootovat) tu třídu, v které se nachází samotná logika programu (vlastně hlavní třídu, pouze bez statické metody "main").

Prezentace základní myšlenky - zavaděč a hlavní třída

Obrázek

Pokud máme vytvořené nejméně obě třídy, můžeme se vrhnout do práce - na počátku vytvoříme dva základní jazykové balíčky (o modifikátorech, o statice a modifikátorech ostatních):

Kód: Vybrat vše

package jádro;
public class Zavaděč{

//Český jazykový balíček:
private static String[] naplňČeštinu = null;
//Anglický jazykový balíček:
private static String[] naplňAngli = null;
}

Následně vytvoříme proměnnou kolekci ArrayList, kterou já osobně pojmenuji symbolicky:

Kód: Vybrat vše

//Protected kvůli přístupnosti tohoto objektu z jakékoli třídy v tomto balíku (zde "jádro"):
protected static ArrayList<String> neurčité = null;

ArrayList zásadně neinstancujeme!
Dále, již v metodě "main", vytvoříme (včetně inicializace) pár objektů:

Kód: Vybrat vše

//Textový řetězec (zde statický) určující lokaci, v jakém adresáři nacházet soubor pro uložení jazyku vybraného později uživatelem (zde lokace "C:\Users\[název uživatele]\AppData\Roaming\MaliAplij"):
String cestaKsložce = System.getenv("appdata") + File.separator + "MaliAplij";
//Určuje samotný název souboru (zde "jazyk.ini" - konfigurační soubor):
String cestaKsouboru = cestaKsložce + File.separatorChar+"jazyk.ini";
//Ukládá informaci o názvu souboru, se kterým budeme později pracovat:
String jazyk = "ZměnaJazyku.txt".
//Hlavní třída, která se po veškerém nastavení zavede:
Panřídící hlavní = new Panřídící();

Nyní nám stačí instanciovat samotné "jazykové pole". Nezapomeňme, že jedná se o jazykové balíčky do hlavní třídy, výstup (de fakto komunikaci s uživatelem) v třídě této vyřešíme později. Dále je třeba zmínit, aby index prvku v prvním poli (př. českém) odpovídal indexu jeho překladu v poli druhém (př. anglickém). Pokud nerozumíte, záhy pochopíte onu myšlenku:

Kód: Vybrat vše

//Instancování hlavních jazykových balíčků:
naplňČeštinu = new String[] {"Achoj, co mám ti říci?", "My jsme v kanále?!"};
naplňAngli = new String[]  {"Hello, what I can say to you?", "We are in a channel?!"};


Nyní naše programování konečně začne být "napínavé" - vrháme se do hlavní logiky zavaděče!
Zaprvé, musíme vytvoři základní podmínku týkající se zjištění, zda uživatel spustil naši aplikaci poprvé, či již po několikáté. Jelikož se jedná pouze o dvojici podmínek, použijeme konstrukci "if-else". A jelikož hodláme vměstnat do souborového systému OS nový soubor, do "hlavičky" (kulatých závorek) podmínky "if" si necháme zjistit za pomoci metody "Files.exists()" zjistit, zda náš nově vytvořený soubor již je v soub. sys. přítomný. Zde je právě čas utvořit i zároveň instanciovat další textové pole zastupující jazykový balíček, tentokráte pouze do této třídy pro komunikaci s uživatelem.
PS: Skloubit následující pole s jazykovým balíčkem hlavním není dobrý nápad - zbytečně se do paměti uloží více prakticky dat a v onon poli se i, z důvodu zvýšeného množství Stringů v něm, hůře orientuje.

První spuštění:

Kód: Vybrat vše

//Pro operace se soubory budeme již používat novou třídu "Files":
if(Files.exists(Paths.get(cestaKsouboru)) == false){
   //Podpůrné (mono třídní) jazykové balíčky:
   String[] naplňMainČesky = {"Já protestuji! Je mě umožněno volat pouze v této podmínce!"};
        String[] naplňMainAngli = {"I´am a rebel! You can call me only in this condition!"};
//Zase, pro nás ještě tajemné, proměnné pole sloužící k samotnému volání indexů v jazykových baličcích:
ArrayList<String> mainNeurčité = null;
//Scanner zajistí komunikaci s uživatelem:   
Scanner zamol = new Scanner(System.in);
//Do textového řetězce se uloží informace ohledně nastaveného jazyku v OS:
String zjistiJazyk = System.getProperty("user.language");
//Určuje jazyk, který se dle uživatelské volby po dalším spuštění automaticky nahraje do kolekce, z které snadlo lze získávat jednotlivé indexy (resp. prvky):
boolean identifJazyk = true; //true = čeština; false = angličtina
}

Nyní se program pokusí automaticky zjistit jazyk upředňostňovaný daným jedincem - uživatelem -, aby dorozumívání se s ním bylo co nejjednodušší. Zároveň si v následujících řádcích skutečně odzkoušíme funkčnost volání prvků z abstraktních polí.

Kód: Vybrat vše

//Když systémový jazyk je čeština:   
if(zjistiJazyk .toLowerCase().contains("cs")){
//Abstraktní pole naplníme češtinou pomocí třídy "Arrays" a metody "asList()":
mainNeurčité = new ArrayList<String>(Arrays.asList(naplňMainČesky));
System.out.println("Volám prvek číslo 0: "+mainNeurčité.get(0));
}
//Když systémový jazyk se jeví jako angličtina:
else{
//Naplnit angličtinou:
mainNeurčité = new ArrayList<String>(Arrays.asList(naplňMainAngli));
System.out.println("I call element with number zero: "+mainNeurčité.get(0));
//Identifikátor přepneme na protější hodnotu, false - angličtina:
identifJazyk = false;
}

Jelikož do dynamického pole "mainNeurčité" již nechceme přidávat/odebírat další prvky, pouze je volat, pro ušetření místa v RAM zavoláme metodu ".trimToSize()", která délku pole přizpůsobí nynějšímu počtu prvků v něm (jinak bývá 2x větší, viz. O metodě):

Kód: Vybrat vše

mainNeurčité.trimToSize();

V dalších řádcích se pokusíme s možným uživatelem "domluvit" o automaticky voleném jazyku při dalším spuštění.
PS: V praxi by i pozdější vstup programu se měl uskutečňovat za pomocí volání jednotlivých prvků z kolekce "mainNeurčité" - podpora vícejazyčnosti. Zde však kvůli pochopitelnosti tuto povinost vynecháme.

Kód: Vybrat vše

System.out.println("Přejete si tento jazyk, český, ponechat?");
System.out.println("1) Ano\n2) Kdepak");
//Získáme od uživatele vstup:
switch(zamol.nextInt()){
//Změna jazyku:
case 2:
System.out.println("1) Angličtina");
//Kdyby si uživatel výběr rozmyslel
System.out.println("2) Čeština");
switch(zamol.nextInt()){
case 1:
//Reálně se změní jazyk až později:
identifJazyk = false;
break;
default:
identifJazyk = true;
}
break;
default:

}

Teď, když již uživatel zvolil si upředňostňovaný jazyk, musíme ony potřebná data zapsat do určitého souboru. Jeho jméno již známe - nese ho String "jazyk" ("ZměnaJazyku.txt"). Ten vytvoříme v společně s adresářem určeným ve Stringu "cestaKsložce" (v "%appdata%").
Pokračujeme tedy v přepínači "switch" u možnosti "default":

Kód: Vybrat vše

default:
//Pro následující jednotlivé operace důrezně doporučuji vytvořit si vlasní metody nejlépe v oddělené třídě:
Files.createDirectory(Paths.get(cestaKsložce));
Files.createFile(Paths.get(cestaKsouboru+jazyk));
BufferedWriter napiš = Files.newBufferedWriter(Paths.get(cestaKsouboru+jazyk), Charset.defaultCharset());
      napiš.write(String.valueOf(identifJazyk));
                napiš.flush();

Scanner již nebudeme dále potřebovat, proto ho necháme napospas Garbage Collectoru):
Ostatní objekty, de fakto podpůrné jazykové balíčky atd., se nachází v samotné podmínce "if" - po vyjetí z ní se automaticky objekty deklarované v ní odstraní, potažmo uvolní místo v paměti - není tedy nutno je značit jako "null".

Kód: Vybrat vše

zamol = null;

Po další čas se budeme zaměřovat na možnost, která se uplatní vždy po zvolení preferovaného jazyka - další spuštění aplikace. Abychom tento pojem adaptovali našemu činění, vysvětleme si onu skutečnost takto: Při opakovaném spuštění či po zvolení upředňostňovaného jazyka (proto zde vynecháme podmínku "else", která by zabránila přechodu do ní z "if") se pokusíme získat data z onoho souboru "ZměnaJazyku.txt":

Několikáté spuštění:

Kód: Vybrat vše

//Čtení z souboru (reálně, znovu opakuji, je velice užitečné si vytvořit pro tento účel metody):
               
                //Proměnný textový řetězec "StringBuilder" - společně se "StringBuffer" tvoří asi nejvhodnější objekt, do jakého lze ukládat proměnná data (de fakto abstraktní text) - u programátorů si získal oblibu hlavně díky rychlosti vkládání/mazání dat do/z něj. Dále obsahuje spoustu užitečných metod, viz. https://docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html
                StringBuilder data = new StringBuilder();
      BufferedReader čti = Files.newBufferedReader(Paths.get(cestaKsouboru), Charset.defaultCharset());
      //Jeden index v dynamickém poli "data" = jeden řádek v souboru.   
      String čtečka = "";
      while ((čtečka = čti.readLine() )!= null) {
         data.append(čtečka);
         }
//Načítání jazykového balíku do Hlavní třídy dle identifikátoru obsaženého v souboru "ZměnaJazyku.txt":
if(data.equals(true)){
   neurčité = new ArrayList<String>(Arrays.asList(naplňČeštinu));   //Čeština
   }
   else{
           neurčité = new ArrayList<String>(Arrays.asList(naplňAngli));   //Angličtina
   }

Nebojte, jsme téměř u konce - jako poslední zajistíme, komunikaci s hlavní třídou a zavaděčem. Zprostředkovatel bude jednoduchý "boolean" vytvořený v oné hlavní třídě (zde jednoduše "Panřídící"), který pomocí návratové hodnoty zajistí, aby zavaděč reagoval na onu hodnotu - buď aplikace bude ukončena, či "pseudomain" metoda (vyjímaje pomocnou metodu vracející onen "boolean", jediná ve třídě "Panřídící" - zde ji pojmenujeme jako "běž()") bude znovu zavolána.
Je nutno uvést příklad? Uživatel v hlavní třídě zadal špatnou hodnotu do Stringu, proto ho požádáme, aby akci znovu, a tentokráte správně, učinil - potřebujeme znovu zavolat metodu běž().
Samozřejmě, ukončování/restartování vašeho programu lze uskutečnit v těle "běž()". Já jsem toto povinost však přenechal zavaděči.
Inu, pojďmě ony poslední řádky dopsat:

Kód: Vybrat vše

//Zase ušetříme pomocí "ořezání délky" abstraktního pole místo v RAM:
neurčité.trimToSize();
//Zavedení hlavní třídy v cyklu zajišťující včasné (chtěné) ukončení programu:
while(hlavní.vraťStav() == true){ //Pokud se rovná "stav" false, vyjet z cyklu - vypnout aplikaci
hlavní.běž();
}
System.exit(0);
}
}

A metoda "vraťStav()" - jen pro orientaci:

Kód: Vybrat vše

//Obyčejný getter:
public boolean vraťStav(){

return stav;


Závěr
Jak jste si sami mohli všimnout, i z tohoto způsobu realizace vícejazyčnosti se odvíjí spousta jiných (jistě i obecně lepších) řešení této problematiky. Jako reakci na tento fakt bych konstoval tedy na rozloučenou: Naučil-li jsem vás novým pohledům, jsem rád; naleznete-li však řešení výhodnější, můžeme být rádi všichni.

Uvolněný zdrojový kód
Naposledy upravil(a) Matiseli dne 17 led 2015 20:44, celkem upraveno 1 x.

Reklama
Uživatelský avatar
domitea
Tvůrce článků
Level 4.5
Level 4.5
Příspěvky: 1966
Registrován: červen 09
Bydliště: Královehradecký kraj
Pohlaví: Muž
Stav:
Offline
Kontakt:

Re: Java - Vícejazyčnost

Příspěvekod domitea » 06 pro 2014 21:28

Nenáročnost na HW a Java? To možná na superpočítači :lol: Ale abych nehanil, tak tu mám kritiku:

Přijde mi, že jsi objevil kolo. Pokud vím, tak v Javě třída Locale a soubory *.properties. To je přímo na takovéhle potřeby :wink:

A teď ke kódu. Java sice jede v UTF, takže čeština není problém, ale pokud zdrojáky budou cestovat půlku světa, tak jsem zvědav, jak našim názvům budou rozumět :lol:
UNIX je systém jednoduchý, jen musíte být geniální, aby jste tu jednoduchost pochopili. Jedině OSS, vše co napíšu je pod GNU/GPL
Linux je mé koření života. Nikdy nevím, co pokazím! Registered user #550849

Dnešní počítače mi nestačí, pracuji na vlastním

Matiseli
Level 2.5
Level 2.5
Příspěvky: 381
Registrován: červen 14
Bydliště: Podíváte-li se roku 2023 na oblohu, tak na té planetě více v pravo
Pohlaví: Nespecifikováno
Stav:
Offline

Re: Java - Vícejazyčnost

Příspěvekod Matiseli » 07 pro 2014 12:59

Nenáročnost na HW a Java?

Asi jsi špatně onen text pochopil - zde nekonstatuji, že by Java byla nenáročná na hardware, nýbrž že můj postup samotný je k HW šetrný.

Přijde mi, že jsi objevil kolo. Pokud vím, tak v Javě třída Locale a soubory *.properties. To je přímo na takovéhle potřeby

O ní (té třídě) toho příliš nevím - mrknu se.
ÚPRAVA:
Dle seznámení jedoho usuzuji, že jedná se spíše o třídu pro zjištění měny, času atd; avšak i - jak si již konstatoval - podporuje onu vícejazyčnost. Přesto se však jedná o postup dosti odlišný - také proto vznik tohoto návodu.


A teď ke kódu. Java sice jede v UTF, takže čeština není problém, ale pokud zdrojáky budou cestovat půlku světa, tak jsem zvědav, jak našim názvům budou rozumět

Ač zde jsem používal diakritiku ze stejného důvodu, jako jsem vynechával OOP - kvůli pochopitelnosti -, tuto chybu činím i ve svém dlouhodobém projektu - přijímám tvou kritiku.

Každý, kdo mi lichotí, je mým nepřítelem. Každý, kdo mne kritizuje, je mým učitelem.
- Čínské přísloví


  • Mohlo by vás zajímat
    Odpovědi
    Zobrazení
    Poslední příspěvek
  • Java vers. Java Příloha(y)
    od Fanobrel » 11 čer 2023 15:15 » v Vše ostatní (sw)
    3
    1175
    od petr22 Zobrazit poslední příspěvek
    11 čer 2023 15:45

Zpět na “Software články”

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 1 host