<?xml version="1.0" encoding="iso-8859-1" ?>
<?xml-stylesheet href="blog.xsl" type="text/xsl" ?>
<blog>
	<datum>04.08.2026</datum>
	<headline>Android Apps für mehrere Sprachen</headline>
	<teaser>
		Ich habe in den letzten zwei Tagen, meine drei Apps für Android, die auch veröffentlich
		wurden, für unterschiedliche Sprachen vorbereitet. Hatten sie bis dahin nur eine deutsche
		Oberfläche, kommen Sie jetzt in Englisch und nur auf einem deutschen oder österreichischen
		Android sind sie in Deutsch.<br/>
		Hier bringe ich eine kurze Anleitung für Entwickler von Apps für Android, wie 
		sie am besten ihre Programme für die internationalen Märkte vorbereiten können.
	</teaser>
	<para>
		<ul>
			<li><b>Ressourcedatei erzeugen</b><br/>
			Im Verzeichnis &lt;projekt&gt;/res/values erzeugen Sie eine Datei mit den Stringliteralen, 
			die Sie auch für andere Sprachen übersetzen wollen. Wichtig: Das ist die Sprache,
			die verwendet wird, wenn für die aktuelle Sprache, keine Übersetzung in Ihrer 
			App gefunden wird. Boarisch oder eine andere exotische Sprache sind nicht nett.<br/>
			Ein Beispiel finden Sie hier: 
			<a href="https://github.com/mgaeckler1964/GpsWayPoints/blob/main/res/values/strings.xml"
				target="_blank">GitHub</a></li>

			<li><b>Oberfläche anpassen</b><br/>
			In der Oberfläche benutzen Sie statt den Stringliteralen die Verweise auf Ihre
			Stringressourcen wie hier dargestellt.<br/>
			<pre>Aus menu.xml:<br/>&lt;item ... <u>android:title="@string/exit"</u> /&gt;</pre>
			<pre>Aus layout.xml:<br/>&lt;TextView ... <u>android:text="@string/altitudeLabel"</u> /&gt;</pre></li>

			<li><b>Activity anpassen</b><br/>
			Brauchen Sie in Ihrer Activity auch ein Literal, können Sie dieses ganz leicht mit der
			Funktion getString abrufen:
			<pre>setStatus( getString(R.string.gpsDisabled) );</pre></li>

			<li><b>Übersetzung bereitstellen</b><br/>
			Nun müssen Sie für jede Sprache, die Sie unterstützen wollen, eine Übersetzung erzeugen.
			Dazu kopieren Sie die strings.xml in einen Ordner values-&lt;iso&gt; und übersetzen die
			Literale. Jedes Literal, das Sie nicht übersetzen, wird aus der Standardsprache genommen.
			Sie müssen also OK nur dann übersetzen, wenn es wirklich anders heißt. Die URL Ihrer
			Homepage werden Sie auch nie übersetzen.<br/>
			Ein Beispiel finden Sie hier:
			<a href="https://github.com/mgaeckler1964/GpsWayPoints/blob/main/res/values-de/strings.xml"
				target="_blank">GitHub</a></li>

			<li><b>Platzhalter</b><br/>
			Sie können Ihre Stringressourcen wie einen Formatstring benutzen und diesen mit
			Platzhaltern versehen, die dann zur Laufzeit befüllt werden können. Einfach mit
			%&lt;fmt&gt; einen Platzhalter einfügen und diesem mit getString in Ihrer Activity
			befüllen:
			<pre>&lt;string name="invalidRange1"&gt;Invalid value for %s&lt;/string&gt;
showError( unknownStyle, getString(R.string.invalidRange1, unknownStyle));</pre>
			Die möglichen Formate und deren Verwendung entnehmen Sie bitte der Dokumentation 
			von Android. Hier will ich nur erwähnen, dass es ähnlich wie bei printf in C funktioniert:
			s steht für Zeichenketten, d für eine Ganzzahl und f für eine Fließkommazahl. </li>

			<li><b>Zwei Platzhalter und mehr</b><br/>
			Wenn Sie mehrere Platzhalter brauchen, werden Sie in der Reihenfolge eingefügt, in der
			sich auch getString übergeben wurden. Für Sprachen, in denen sich die Reihenfolge ändert,
			können Sie die Platzhalter aber numerieren. Dazu fügen Sie nach dem % &lt;nummer&gt;$ 
			ein.<pre>&lt;string name="accuracy_format"&gt;%1$s Accuracy: %2$.3fm %3$d/%4$d&lt;/string&gt;
m_statusView.setText( getString(R.string.accuracy_format, text,getAccuracy(), getLocationFixCount(), getNumLocations()));</pre></li>

			<li><b>Zahlenformate</b><br/>
			Wenn Sie auch unterschiedliche Zahlenformate berücksichtigen wollen, dürfen Sie nicht die
			Javastandardkonvertierung benutzen. Für die Konvertierung einer Fließkommazahl in einen
			Text verwenden Sie die Funktion String.format.<pre>String.format(Locale.getDefault(), "%.1f", 23.6)</pre>
			Umgekehrt verwenden Sie die Funktion NumberFormat.parse.<br/>
			Leider hat Google bei der Implementierung der UI geschlampt und verwendet beim Eingabetyp
			(android:inputType) "numberDecimal" auch dann in den Eingabefeldern den Dezimalpunkt,
			wenn er eigentlich das Komma hätte verwenden sollen. Daher ersetze ich in meiner
			Implementierung erstmal alle Kommata und alle Punkte durch den DecimalSeperator. Das ist
			nicht toll, aber ich hoffe, dass die Java VM beim Versuch x durch x zu ersetzen, die
			Nulloperation erkennt und sofort aufhört.
			<pre>char localSeparator = DecimalFormatSymbols.getInstance().getDecimalSeparator();
input = input
	.replace('.', localSeparator)
	.replace(',', localSeparator);</pre>
			Ein Beispiel finden Sie hier: 
			<a href="https://github.com/mgaeckler1964/FotoCalc/blob/main/Mobil/src/at/gaeckler/MyActivity.java#L99"
				target="_blank">GitHub</a></li>

			<li><b>Abschluss</b><br/>
			Das ist natürlich jetzt keine Referenzdokumentation, die Sie in alle Feinheiten der
			Androidprogrammierung einweist, es soll aber eine erste Einführung sein und Ihnen zeigen,
			dass der Aufwand relativ gering ist, wenn man die Fallstricke kennt. Was mich beispielsweise
			aufgehalten hat, war, dass es getText() und getString() gibt. Sie arbeiten ähnlich aber nicht
			identisch, was dazu führte, dass ich Fehlermeldungen bekam, die ich nicht verstand, ehe ich
			realisierte, dass ich die falsche Funktion benutzte.<br/>
			Was ich super toll finde: Wenn Sie sich bei den Ressourcen IDs verschreiben, wird das
			schon zur Übersetzungszeit erkannt. Auch die Anzahl und der Typ der Platzhalter wird schon
			bei der Übersetzung überprüft.</li>
		</ul>
	</para>
</blog>
