Handling translation strings to languages with inflections on Android - android

I'm not sure this is the right forum to post this but I'm unsure how to organize my strings in certain scenarios where nouns in certain languages are inflected. It's easier to explain the problem with an example. Consider the following string:
<string name="my_string">Show you more information in context with each
<xliff:g id="item_name">%s</xliff:g></string>
The element <xliff:g id="item_name">%s</xliff:g> in this case can be replaced by, for example, "alarm" or "alert" depending on the context in my app. However, this doesn't work with languages that inflect the noun, such as Finnish.
In Finnish, %s is substituted with the word "hälytys" (=alarm) in the app though grammatically correct form in this case would be "hälytyksen" (an inflected form of singular alarm in Finnish, caused by a postposition and unfortunately no nice way to circumvent the inflection).
So it seems I can't have this sort of generic string element with replaceable nouns. Do you have any suggestions other than hard-coding the string elements for each possible value of %s?

Put your string this way in string.xml
<string name="my_string">Show you more information in context with each <xliff:g id=\"item_name\"> %s <\/xliff:g></string>
From Java
String s = String.format(getString(R.string.my_string,"alarm")); //put your dynamic value for alarm
Output would be :
Show you more information in context with each <xliff:g id="item_name"> alarm </xliff:g>

Related

Android: Find the string resource key by the string value

There are a lot of explanations out there in how to retrieve a string resource value by its key. But I actually need the solution for the reverse case - retrieving the key by the value instead.
You may wonder why would I ever need something like that. Well, I got speech recognition in my app and in case there's a non-english speaker input, I need to recover the localized string key from the raw voice-to-text input so I can have multilanguage speech recognition support in my app.
So imagine I had a string resource:
// EN
<string name="not_a_dog">Cat</string>
// DE
<string name="not_a_dog">Katze</string>
So in case user says "Cat" (or "Katze" for German locale), I would get "not_a_dog".
you don't need to declare mutiple strings for different languages
Just create string.xml for each languages like described here; then you can do : if(yourText.equals(getString(R.string.not_a_dog)){
//do what you want
}

How to set string resource length limit in Android?

It is known that Androd string resources support xliff namespace to annotate non-translatable string formatting placeholders, like this
<string name="max_file_size_exceeded_template">File
<xliff:g example="some_image.jpg" id="file_name">%1$s</xliff:g>
is too big and could not be uploaded.</string>
It helps translators to undestand what parts of string should not be modified. But sometimes I need to annotate some strings max length it they are used in UI control with limited size. What I want is add text length limit to warn translators about this. Something like max-length="24" max-lines="2" length-unit="char" Maybe, xliff supports such thing or it can be achieved in other way.
I use Weblate for translations if it matters.
You can set this in Weblate, the Andoid format does not support this directly.
Click on edit (pencil) icon next to flags on the string.
Enter max-length:LENGTH as check flag.
See also https://docs.weblate.org/en/latest/admin/translating.html#additional-information-on-source-strings

How to use Android xliff:g

Can someone please explain the xliff:g for strings/localization.
I understand that xliff:g is not supposed to translate anything inside the <> things, but I'm confused how exactly I'd use this in code.
An example I have in my case is the practice spanish translations that I have has:
<string name="order_quantity">Cantidad: <xliff:g id="quantity" example="2">%d/xliff:g</string>
I am now trying to get localized strings with xliff:g to work.
What is id here and what does it do? And what does it call?
Also what is the %d and what does it do? What is the point of example? Also, how would I call that into code, if at all?
Why can't someone just do the following code to insert the following xml:
<string name="quant">Quantity: </string>
into java like so:
getString(R.string.quant) + quantity
so that way it concactenates the quantity variable into the getString?
Minor typo in your example, there should be a closing tag:
<string name="order_quantity">Cantidad: <xliff:g id="quantity" example="2">%d</xliff:g></string>
The id attribute is just used to identify what the substitution parameter represents (in your case, it represents the quantity). It's as you said, a note, and not actually used programmatically.
That said, in Android Studio, if you have Code Folding enabled for strings, it will substitute in the ID when it shows the collapsed string. You'd see something like this:
// This...
mTextView.setText(getString(R.string.order_quantity, 2));
// Will show as this when folded:
mTextView.setText("Cantidad: {quantity}");
As for your second question, why not just use string concatenation? In other languages, the substitution may not go at the end of the string. You could have something like:
values/strings.xml
<string name="order_quantity">%d items</string>
values-es/strings.xml
<string name="order_quantity">Cantidad: %d</string>
So you can see that in this case, simply appending the strings together would not give you a valid result.
%d is used to represent a part of memory as an integer.
It's most commonly used to print some number to standard output, as follows:
#include <stdio.h>
int main()
{
int n = 42;
printf("The answer to life, universe and everything is %d", n);
return 0;
}
Unlike Java, where you simply concatenate numbers and strings etc., C uses this %something to indicate what is being written. %d indicates, that for example in the printf(), after the comma there will be an argument (in our case it's n), which should be represented as an int.
Refer to List of all format specifiers in C programming for a complete list of format specifiers
Also refer to Official Android Developers Documentation

Best way to store multilanguage values on a database using strings.xml?

this is my first question :)
I'm developing an application that stores animal species in a database. The app must be multilanguage, so I tought to take advantage of using strings.xml resource files.
The idea is to store the english name of the species on the db, for example "cat", "dog" etc.. and then display to the user the actual translation, based on an xml like this (for italian):
<string name="dog">Cane</string>
<string name="cat">Gatto</string>
The problem is that R.string contains the name dog and cat, but they are actually int, so I'm searching a way to use the "dog" string to be used to compare the R.string.dog translated value.
I'm almost sure that my design is terribly wrong, but don't know what the correct way to doing this kind of work, since the app is now in a very early stage of development.
Thank you
EDIT with example
This example illustrates the problem:
Database data:
row1: id="1", value="dog"
row2: id="2", value="cat"
String file strings.xml:
<string name="dog">Dog</string>
<string name="cat">Cat</string>
String file strings-it.xml:
<string name="dog">Cane</string>
<string name="cat">Gatto</string>
My problem is: the user want to insert a specie in his native language (eg. "Cane"), and I want to search in the DB for its existence before inserting.
I should loop for every row on the DB (where values are stored in english), get the the translation of each row (eg: I found cat, then I translate to "Gatto") and compare with the user input.
Is it possible to do that?
If you have a string name you want to use, you can use getIdentifier() to get the string id. As an example, to find R.string.cat:
Resources res = getResources();
int stringId = res.getIdentifier("cat", "string", packageName);
In the above example, if there is no R.string.cat found, it will simply return 0. It's an easy test to see if a string exists.
Alternatively, you can get an array of all the string ids in your R.java by using something like:
Field[] fields = R.string.class.getFields();
int[] ids = new int[fields.length];
for(int i=0;i<field.length;i++)
ids[i] = field[i].getInt(null);
Of course, that will also look for any strings that you don't really intend as translations, such as dialog/window titles, label/button captions, etc. I wouldn't advise it in the general case. If I had to do it, I'd prefix the "translation" strings with something so I could easily tell what is what, something like "entry_cat".
Note that we're using reflection, and if you have a lot of strings, it could slow you down. If you are going to loop through R.java, I'd advise only doing it on start-up, and saving the values in some sort of array/list.
First read this.
http://developer.android.com/training/basics/supporting-devices/languages.html
You can create value folder with many language's i.e janapee,dutch etc
you can find out value folder inside the res folder in your project. and create new value folders.
res/
values/
strings.xml
values-es/
strings.xml
values-fr/
strings.xml
JUST TRANSLATE YOUR WORDS BY GOOGLE TRANSLATOR IN ANY LANGUAGE AND PUT INSIDE THE STRING.XML FILE .
Well, first of all, start reading this here:
Suppose that your application's default language is English. Suppose
also that you want to localize all the text in your application to
French, and most of the text in your application (everything except
the application's title) to Japanese. In this case, you could create
three alternative strings.xml files, each stored in a locale-specific
resource directory:
res/values/strings.xml Contains English text for all the strings that
the application uses, including text for a string named title.
res/values-fr/strings.xml Contain French text for all the strings,
including title. res/values-ja/strings.xml Contain Japanese text for
all the strings except title. If your Java code refers to
R.string.title, here is what will happen at runtime:
If the device is set to any language other than French, Android will
load title from the res/values/strings.xml file. If the device is set
to French, Android will load title from the res/values-fr/strings.xml
file. Notice that if the device is set to Japanese, Android will look
for title in the res/values-ja/strings.xml file. But because no such
string is included in that file, Android will fall back to the
default, and will load title in English from the
res/values/strings.xml file.

Plurals not working as intended in android

I am using Plural strings provided by android-sdk. I have used following code to create a plural string:
<plurals name="valuestr">
<item quantity="zero">Choose a value.</item>
<item quantity="one">%d unit.</item>
<item quantity="other">%d units.</item>
</plurals>
Java Code:
textView.setText(getResources().getQuantityString(R.plurals.valuestr,0,0));
When i am setting any value other than '0', this is working fine but when i am setting '0' it is showing '0 unit.'.
Please help!
Update
While searching more on the internet i came across a workaround which uses java.text.MessageFormat class:
<resources>
<string name="item_shop">{0,choice,0#No items|1#One item|1<{0} items}</string>
</resources>
Then, from the code all you have to do is the following:
String fmt = resources.getText(R.string.item_shop);
textView.setText(MessageFormat.format(fmt, amount));
You can read more about the format strings in the javadocs for MessageFormat
A post was recently made on G+ about this.
In short, it is because this will not pick the closest match by Integer ( 0 = zero), but because it will look for the best grammatical pick.
In your example, you use units.
The correct usage would be;
0 units
1 unit
2 units
Making, zero equal to pretty much any other quantity above 1
Read the full story here;
https://plus.google.com/116539451797396019960/posts/VYcxa1jUGNo
Plurals defined in <plurals> sections of resource files are only to be used for a grammatical distinction with respect to singular/plural strings. You should not use them for other display logic, as you did. You should add some checking logic in your code instead.
The Android developer's guide clearly states this:
Although historically called "quantity strings" (and still called that
in API), quantity strings should only be used for plurals. It would be
a mistake to use quantity strings to implement something like Gmail's
"Inbox" versus "Inbox (12)" when there are unread messages, for
example. It might seem convenient to use quantity strings instead of
an if statement, but it's important to note that some languages (such
as Chinese) don't make these grammatical distinctions at all, so
you'll always get the other string.
Your workaround - although working technically for your current implementation - does not appear like a clean solution either, in my opinion. Future business requirements may make it necessary to include more sophisticated logic than just displaying a different text. Or you may have a generic "no items selected" string in your resource file used at different locations, which could be reused only if you did not stick to your solution.
Generally, I would avoid using two different formatting techniques (String.format style formatter %d vs. MessageFormat style formatter {0} and pick one that you'd stick to in your whole application.

Categories

Resources