Czy można dynamicznie dodać ciąg do pliku String.xml w systemie Android?

Odpowiedzi:

1033

Formatowanie i stylizacja

Tak, zapoznaj się z następującymi materiałami z zasobów ciągów: Formatowanie i stylowanie

Jeśli musisz sformatować ciągi za pomocą String.format(String, Object...), możesz to zrobić, umieszczając argumenty formatu w zasobie ciągu. Na przykład z następującym zasobem:

<string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>

W tym przykładzie ciąg formatu ma dwa argumenty: %1$sjest ciągiem i %2$djest liczbą dziesiętną. Możesz sformatować ciąg za pomocą argumentów z aplikacji w następujący sposób:

Resources res = getResources();
String text = String.format(res.getString(R.string.welcome_messages), username, mailCount);

Podstawowe użycie

Zauważ, że getStringwystępuje przeciążenie, które wykorzystuje ciąg jako ciąg formatu:

String text = res.getString(R.string.welcome_messages, username, mailCount);

Liczba mnoga

Jeśli potrzebujesz obsługi liczby mnogiej, użyj tego:

<plurals name="welcome_messages">
    <item quantity="one">Hello, %1$s! You have a new message.</item>
    <item quantity="other">Hello, %1$s! You have %2$d new messages.</item>
</plurals>

Pierwszy mailCountparametr służy do decydowania, którego formatu użyć (pojedynczego lub mnogiego), pozostałe parametry to twoje podstawienia:

Resources res = getResources();
String text = res.getQuantityString(R.plurals.welcome_messages, mailCount, username, mailCount);

Aby uzyskać więcej informacji, zobacz Zasoby łańcuchowe: Liczba mnoga .

Megha Joshi - GoogleTV DevRel
źródło
61
Wywołanie String.format w pierwszym przykładzie kodu nie jest w rzeczywistości konieczne, Resources.getString () obsługuje formatowanie, patrz: developer.android.com/reference/android/content/res/… , java.lang.Object ...)
Arnaud
16
dla liczby mnogiej w String.xml musisz podać identyfikator jako R.plurals.welcome_messages zamiast R.string.welcome_messages
om252345
liczba mnoga zwracająca tylko ciąg ostatniego elementu ... każdy pomysł, jak uzyskać ciąg dołączany.
CoDe
1
Podczas korzystania z tej metody do formatowania łańcucha usunął on wszelkie metatagi, takie jak hiperłącza itp., Które mogły być zawarte w tekście łańcucha xml
Jonathan
4
Ciąg oznacza% 1 $ s, dziesiętny dla% 2 $ d, a liczba całkowita oznacza co? co to znaczy% 1,% 2.Czy to zliczanie parametru?. jeśli chcę trzeci parametr Czy wspomnieć% 3?
reegan29
259

Dodatkowa odpowiedź

Kiedy po raz pierwszy zobaczyłem %1$si %2$dw przyjętej odpowiedzi, nie miało to sensu. Oto trochę więcej wyjaśnień.

Nazywa się je specyfikatorami formatu. W ciągu xml mają one postać

%[parameter_index$][format_type] 
  • % : Znak procentowy oznacza początek specyfikatora formatu.
  • indeks parametrów : Jest to liczba, po której następuje znak dolara. Jeśli miał trzy parametry, które chciał wprowadzić do napisu, potem będzie się nazywać 1$, 2$i 3$. Kolejność umieszczania ich w łańcuchu zasobów nie ma znaczenia, tylko kolejność dostarczania parametrów.
  • typ formatu : Istnieje wiele sposobów formatowania rzeczy ( patrz dokumentacja ). Oto kilka typowych:

    • s strunowy
    • d dziesiętna liczba całkowita
    • f liczba zmiennoprzecinkowa

Przykład

Utworzymy następujący sformatowany ciąg, w którym szare części są wstawiane programowo.

Moja siostra Maryma 12lata.

string.xml

<string name="my_xml_string">My sister %1$s is %2$d years old.</string>

MyActivity.java

String myString = "Mary";
int myInt = 12;
String formatted = getString(R.string.my_xml_string, myString, myInt);

Notatki

  • Mógłbym użyć, getStringponieważ byłem w działaniu. Możesz użyć, context.getResources().getString(...)jeśli nie jest dostępne.
  • String.format() sformatuje również ciąg.
  • 1$I 2$warunki nie muszą być stosowane w tej kolejności. To znaczy, 2$może przyjść wcześniej 1$. Jest to przydatne podczas internacjonalizacji aplikacji dla języków, które używają innej kolejności słów.
  • Możesz użyć specyfikatora formatu jak %1$swiele razy w pliku XML, jeśli chcesz go powtórzyć.
  • Użyj, %%aby uzyskać rzeczywistą %postać.
  • Aby uzyskać więcej informacji, przeczytaj następujący pomocny samouczek: Android SDK Szybka wskazówka: Formatowanie ciągów zasobów
Suragch
źródło
125

Jeśli chcesz użyć parametru z rzeczywistego pliku strings.xml bez użycia kodu Java:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE resources [
  <!ENTITY appname "WhereDat">
  <!ENTITY author "Oded">
]>

<resources>
    <string name="app_name">&appname;</string>
    <string name="description">The &appname; app was created by &author;</string>
</resources>

Nie działa to w przypadku plików zasobów, tzn. Zmienne należy skopiować do każdego pliku XML, który ich potrzebuje.

Oded Breiner
źródło
To dobra odpowiedź, z wyjątkiem sytuacji, gdy masz parametr <! [CDATA [& param; ]]>
Hermann Poilpre
2
Czy istnieje sposób zdefiniowania <!DOCTYPE... ]>części w oddzielnym pliku i włączenia jej do wielu plików zasobów? Jakaś sztuczka, aby to osiągnąć?
prom85 20.10.2018
18

Szukałem tego samego i wreszcie znalazłem następujące bardzo proste rozwiązanie. Najlepsze: działa od razu po wyjęciu z pudełka.
1. zmień zasób swojego ciągu:

<string name="welcome_messages">Hello, <xliff:g name="name">%s</xliff:g>! You have 
<xliff:g name="count">%d</xliff:g> new messages.</string>

2. użyj podstawienia łańcucha:

c.getString(R.string.welcome_messages,name,count);

gdzie c jest kontekstem, nazwa jest zmienną łańcuchową i policz zmienną int

Musisz uwzględnić

<resources xmlns:xliff="http://schemas.android.com/apk/res-auto">

w twoim res / strings.xml. Pracuje dla mnie. :)

użytkownik3016503
źródło
2
Jaki jest sens xlifftagów wokół specyfikatorów formatu? Jaką dodatkową wartość dodają, a nie tylko same używają specyfikatorów %si %d?
Richard Le Mesurier
Atrybut „name” w tagu xliff jest tylko sposobem, aby dać tłumaczowi podpowiedź na temat tego, co zostanie tam zastąpione. Czasami nie jest łatwo zgadnąć, co oznacza „% s”.
hugomg
3

W Kotlin wystarczy ustawić wartość ciągu w następujący sposób:

<string name="song_number_and_title">"%1$d ~ %2$s"</string>

Utwórz widok tekstu w swoim układzie:

<TextView android:id="@+id/song_number_and_title"/>

Zrób to w kodzie, jeśli używasz Anko:

val song = database.use { // get your song from the database }
song_number_and_title.setText(resources.getString(R.string.song_number_and_title, song.number, song.title))  

Może być konieczne pobranie zasobów z kontekstu aplikacji.

msbodw001
źródło
5
Czym różni się to od przykładów Java? Nie widzę różnicy
Janusz Hain,
1

w res / wartości / string.xml

<resources>
    <string name="app_name">Hello World</string>
    <string name="my_application">Application name: %s, package name: %s</string>
</resources>

w kodzie java

String[] args = new String[2];
args[0] = context.getString(R.string.app_name);
args[1] = context.getPackageName();
String textMessage = context.getString(R.string.my_application,(Object[]) args);
Chanh
źródło
1

Jeśli chcesz zapisać procent (%), skopiuj go:

<string name="percent">%1$d%%</string>

label.text = getString(R.string.percent, 75) // Output: 75%.

Jeśli piszesz po prostu %1$d%, otrzymasz błąd: Format string 'percent' is not a valid format string so it should not be passed to String.format.

CoolMind
źródło
0

Tak! możesz to zrobić bez pisania kodu Java / Kotlin, tylko XML, korzystając z tej małej biblioteki, którą utworzyłem, która robi to w czasie kompilacji, więc nie wpłynie to na twoją aplikację: https://github.com/LikeTheSalad/android -string-referencja

Stosowanie

Twoje sznurki:

<resources>
    <string name="app_name">My App Name</string>
    <string name="template_welcome_message">Welcome to ${app_name}</string>
</resources>

Wygenerowany ciąg po zbudowaniu:

<!--resolved.xml-->
<resources>
    <string name="welcome_message">Welcome to My App Name</string>
</resources>
César Muñoz
źródło
0

Bezpośrednie rozwiązanie problemu przez Kotlin:

strings.xml

<string name="customer_message">Hello, %1$s!\nYou have %2$d Products in your cart.</string>

kotlinActivityORFragmentFile.kt:

val username = "Andrew"
val products = 1000
val text: String = String.format(
      resources.getString(R.string.customer_message), username, products )
nyxee
źródło
0

Użyj tego w swoim pliku łańcuchowym

<string name="redeem_point"> You currently have %s points(%s points = 1 %s)</string>

I w swoim kodzie użyj odpowiednio

coinsTextTV.setText(String.format(getContext().getString(R.string.redeem_point), rewardPoints.getReward_points()
                        , rewardPoints.getConversion_rate(), getString(R.string.rs)));
Soni Kumar
źródło
-1

Wersja zaakceptowanej odpowiedzi Kotlin ...

val res = resources
val text = String.format(res.getString(R.string.welcome_messages), username, mailCount)
jesses.co.tt
źródło
3
Bardziej poprawnym sposobem jest użycie resources.getString(int, ... args)metody z argumentami zamiast String.format. W tym kodzie nie ma też szczegółów kotlin, oprócz valsłów kluczowych. Zobacz odpowiedź msbodw001
dant3