Compare commits

..

23 Commits

Author SHA1 Message Date
Grishka
b5f661f1af I forgot to increment the version code 2023-09-25 19:25:59 +03:00
Grishka
0015f3f0bf Merge branch 'l10n_master' 2023-09-25 19:22:38 +03:00
Eugen Rochko
c5d0fdd645 New translations strings.xml (Turkish) 2023-09-25 18:20:56 +02:00
Grishka
2d09ad44fb Merge branch 'l10n_master' 2023-09-25 19:18:24 +03:00
Eugen Rochko
667fffd124 New translations strings.xml (Chinese Traditional) 2023-09-25 18:18:22 +02:00
Eugen Rochko
699233d8c7 New translations strings.xml (Filipino) 2023-09-25 18:18:05 +02:00
Grishka
56aabdc4a6 Fix empty view text style
closes #701
2023-09-25 19:12:04 +03:00
Grishka
443e2c7a6f Add a tool to detect invalid formatting in localized strings 2023-09-25 18:51:49 +03:00
Eugen Rochko
985b0f6e63 New translations strings.xml (Filipino) 2023-09-25 17:49:57 +02:00
Eugen Rochko
f71d1bc5d3 New translations strings.xml (Greek) 2023-09-24 23:27:13 +02:00
Eugen Rochko
6bcdbaba34 New translations strings.xml (Turkish) 2023-09-24 08:49:38 +02:00
Eugen Rochko
a2beead3a5 New translations strings.xml (Chinese Simplified) 2023-09-23 18:34:38 +02:00
Eugen Rochko
e7a25e353d New translations strings.xml (Japanese) 2023-09-23 14:15:37 +02:00
Eugen Rochko
af04a01130 New translations strings.xml (Japanese) 2023-09-23 13:16:04 +02:00
Eugen Rochko
b248797bb0 New translations strings.xml (Russian) 2023-09-22 20:28:14 +02:00
Eugen Rochko
0e89559a47 New translations strings.xml (Slovenian) 2023-09-22 19:30:53 +02:00
Eugen Rochko
d02a72e079 New translations strings.xml (Japanese) 2023-09-22 13:01:51 +02:00
Eugen Rochko
3be57d1b0b New translations strings.xml (Japanese) 2023-09-22 11:08:13 +02:00
Eugen Rochko
bed550e97c New translations strings.xml (Russian) 2023-09-22 09:19:11 +02:00
Eugen Rochko
7e2619ea75 New translations strings.xml (Italian) 2023-09-22 01:48:10 +02:00
Eugen Rochko
4b22f1d3a7 New translations strings.xml (Thai) 2023-09-21 21:39:59 +02:00
Eugen Rochko
9dcc7e293f New translations strings.xml (Icelandic) 2023-09-21 15:39:27 +02:00
Eugen Rochko
6a68cf5e41 New translations strings.xml (Persian) 2023-09-21 13:13:31 +02:00
16 changed files with 238 additions and 19 deletions

View File

@@ -9,8 +9,8 @@ android {
applicationId "org.joinmastodon.android"
minSdk 23
targetSdk 33
versionCode 66
versionName "2.1.0"
versionCode 67
versionName "2.1.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resConfigs "ar-rSA", "be-rBY", "bn-rBD", "bs-rBA", "ca-rES", "cs-rCZ", "da-rDK", "de-rDE", "el-rGR", "es-rES", "eu-rES", "fa-rIR", "fi-rFI", "fil-rPH", "fr-rFR", "ga-rIE", "gd-rGB", "gl-rES", "hi-rIN", "hr-rHR", "hu-rHU", "hy-rAM", "ig-rNG", "in-rID", "is-rIS", "it-rIT", "iw-rIL", "ja-rJP", "kab", "ko-rKR", "my-rMM", "nl-rNL", "no-rNO", "oc-rFR", "pl-rPL", "pt-rBR", "pt-rPT", "ro-rRO", "ru-rRU", "si-rLK", "sl-rSI", "sv-rSE", "th-rTH", "tr-rTR", "uk-rUA", "ur-rIN", "vi-rVN", "zh-rCN", "zh-rTW"
}
@@ -76,7 +76,7 @@ dependencies {
implementation 'me.grishka.litex:viewpager:1.0.0'
implementation 'me.grishka.litex:viewpager2:1.0.0'
implementation 'me.grishka.litex:palette:1.0.0'
implementation 'me.grishka.appkit:appkit:1.2.10'
implementation 'me.grishka.appkit:appkit:1.2.11'
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'org.jsoup:jsoup:1.14.3'
implementation 'com.squareup:otto:1.3.8'

View File

@@ -2,10 +2,6 @@ package org.joinmastodon.android.fragments;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toolbar;
import org.joinmastodon.android.R;
@@ -47,14 +43,6 @@ public abstract class MastodonRecyclerFragment<T> extends BaseRecyclerFragment<T
refreshLayout.setProgressBackgroundColorSchemeColor(UiUtils.alphaBlendColors(colorBackground, colorPrimary, 0.11f));
refreshLayout.setColorSchemeColors(colorPrimary);
}
// This is to set the color of the 'This list is empty'
for (int i=0; i < ((LinearLayout) emptyView).getChildCount(); i++) {
View v = ((LinearLayout) emptyView).getChildAt(i);
if(v instanceof TextView) {
((TextView) v).setTextColor(UiUtils.getThemeColor(getContext(), android.R.attr.textColorSecondary));
}
}
}
@Override

View File

@@ -387,6 +387,7 @@
<string name="welcome_to_mastodon">Καλώς ήρθες στο Mastodon</string>
<string name="welcome_paragraph1">Το Mastodon είναι ένα αποκεντρωμένο κοινωνικό δίκτυο που σημαίνει ότι καμία εταιρεία δεν το ελέγχει. Αποτελείται από πολλούς ανεξάρτητους διακομιστές, όλοι συνδεδεμένοι μαζί.</string>
<string name="what_are_servers">Τι είναι οι διακομιστές;</string>
<string name="welcome_paragraph2">Κάθε λογαριασμός Mastodon φιλοξενείται σε ένα διακομιστή - ο καθένας με τις δικές του αξίες, κανόνες &amp; διαχειριστές. Ανεξάρτητα από το ποιον μπορεί να επιλέξεις, μπορείς να ακολουθήσεις και να αλληλεπιδράσεις με άτομα από οποιονδήποτε διακομιστή.</string>
<string name="opening_link">Άνοιγμα συνδέσμου…</string>
<string name="link_not_supported">Αυτός ο σύνδεσμος δεν υποστηρίζεται στην εφαρμογή</string>
<string name="log_out_all_accounts">Αποσύνδεση από όλους τους λογαριασμούς</string>
@@ -582,5 +583,20 @@
<string name="time_hours_ago_short">%dώ πριν</string>
<string name="time_days_ago_short">%dημ πριν</string>
<!-- %s is the name of the post language -->
<string name="translate_post">Μετάφραση από %s</string>
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">Μεταφράστηκε από %1$s χρησιμοποιώντας %2$s</string>
<string name="translation_show_original">Εμφάνιση αρχικού</string>
<string name="translation_failed">Η μετάφραση απέτυχε. Ίσως ο διαχειριστής δεν έχει ενεργοποιήσει μεταφράσεις σε αυτόν τον διακομιστή ή αυτός ο διακομιστής εκτελεί μια παλαιότερη έκδοση του Mastodon όπου οι μεταφράσεις δεν υποστηρίζονται ακόμα.</string>
<string name="settings_privacy">Ιδιωτικότητα και προσιτότητα</string>
<string name="settings_discoverable">Παροχή προφίλ και δημοσιεύσεων σε αλγορίθμους ανακάλυψης</string>
<string name="settings_indexable">Συμπερίληψη δημόσιων αναρτήσεων στα αποτελέσματα αναζήτησης</string>
<plurals name="x_participants">
<item quantity="one">%,d συμμετέχων</item>
<item quantity="other">%,d συμμετέχοντες</item>
</plurals>
<plurals name="x_posts_today">
<item quantity="one">%,d ανάρτηση σήμερα</item>
<item quantity="other">%,d αναρτήσεις σήμερα</item>
</plurals>
</resources>

View File

@@ -588,6 +588,9 @@
<string name="post_translated">ترجمه از %1$s با %2$s</string>
<string name="translation_show_original">نمایش اصلی</string>
<string name="translation_failed">ترجمه ناموفق بود. شاید مدیر ترجمه‌ها را در این کارساز فعال نکرده باشد یا این کارساز نسخه قدیمی ماستودون را اجرا می کند که در آن ترجمه‌ها هنوز پشتیبانی نمی شوند.</string>
<string name="settings_privacy">محرمانگی و دسترسی</string>
<string name="settings_discoverable">مشخص کردن مشخصات و فرسته‌ها در الگوریتم‌های اکتشاف</string>
<string name="settings_indexable">قرار دادن فرسته‌های عمومی در نتایج جستجو</string>
<plurals name="x_participants">
<item quantity="one">%,d شرکت کننده</item>
<item quantity="other">%,d شرکت‌کننده</item>

View File

@@ -211,12 +211,12 @@
<item quantity="other">%,d tagasunod</item>
</plurals>
<plurals name="x_following">
<item quantity="one">%, d Sumusunod</item>
<item quantity="other">%, d Sumusunod</item>
<item quantity="one">%,d Sumusunod</item>
<item quantity="other">%,d Sumusunod</item>
</plurals>
<plurals name="x_favorites">
<item quantity="one">%, d Paborito</item>
<item quantity="other">%, d paborito</item>
<item quantity="one">%,d Paborito</item>
<item quantity="other">%,d paborito</item>
</plurals>
<string name="timestamp_via_app">%1$s sa pamamagitan ng %2$s</string>
<string name="time_now">ngayon</string>

View File

@@ -583,5 +583,20 @@
<string name="time_hours_ago_short">fyrir %dh síðan</string>
<string name="time_days_ago_short">fyrir %dd síðan</string>
<!-- %s is the name of the post language -->
<string name="translate_post">Þýða úr %s</string>
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">Þýtt úr %1$s með %2$s</string>
<string name="translation_show_original">Sýna upprunalegt</string>
<string name="translation_failed">Þýðing mistókst. Mögulega hefur kerfisstjórinn ekki virkjað þýðingar á þessum netþjóni, eða að netþjónninn sé keyrður á eldri útgáfu Mastodon þar sem þýðingar séu ekki studdar.</string>
<string name="settings_privacy">Gagnaleynd og útbreiðsla</string>
<string name="settings_discoverable">Hafa notandasnið og færslur með í reikniritum leitar</string>
<string name="settings_indexable">Hafa opinberar færslur með í leitarniðurstöðum</string>
<plurals name="x_participants">
<item quantity="one">%,d þátttakandi</item>
<item quantity="other">%,d þátttakendur</item>
</plurals>
<plurals name="x_posts_today">
<item quantity="one">%,d færsla í dag</item>
<item quantity="other">%,d færslur í dag</item>
</plurals>
</resources>

View File

@@ -588,6 +588,7 @@
<string name="post_translated">Tradotto da %1$s utilizzando %2$s</string>
<string name="translation_show_original">Mostra originale</string>
<string name="translation_failed">Traduzione fallita. Forse l\'amministratore non ha abilitato le traduzioni su questo server, o su questo server è in esecuzione una versione precedente di Mastodon in cui le traduzioni non sono ancora supportate.</string>
<string name="settings_indexable">Includi i post pubblici nei risultati di ricerca</string>
<plurals name="x_participants">
<item quantity="one">%,d participante</item>
<item quantity="other">%,d partecipanti</item>

View File

@@ -554,5 +554,18 @@
<string name="time_hours_ago_short">%d 時間前</string>
<string name="time_days_ago_short">%d 日前</string>
<!-- %s is the name of the post language -->
<string name="translate_post">%s から翻訳</string>
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">%2$s による %1$s からの翻訳</string>
<string name="translation_show_original">原文を表示</string>
<string name="translation_failed">翻訳に失敗しました。このサーバーは翻訳機能を有効にしていないか、翻訳機能のない旧バージョンの Mastodon を実行しているのかもしれません。</string>
<string name="settings_privacy">プライバシーとつながりやすさ</string>
<string name="settings_discoverable">アカウントを見つけやすくする</string>
<string name="settings_indexable">公開投稿を検索できるようにする</string>
<plurals name="x_participants">
<item quantity="other">参加者 %d 人</item>
</plurals>
<plurals name="x_posts_today">
<item quantity="other">今日の投稿 %,d 件</item>
</plurals>
</resources>

View File

@@ -641,5 +641,24 @@
<string name="time_hours_ago_short">%d ч. назад</string>
<string name="time_days_ago_short">%d д. назад</string>
<!-- %s is the name of the post language -->
<string name="translate_post">Перевести %s</string>
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">Переведено с %1$s с помощью %2$s</string>
<string name="translation_show_original">Показать оригинал</string>
<string name="translation_failed">Перевод не удался. Возможно, администратор не включил переводы на этом сервере или на этом сервере установлена ​​более старая версия Mastodon, где переводы еще не поддерживаются.</string>
<string name="settings_privacy">Приватность и доступ</string>
<string name="settings_discoverable">Показывать профиль и посты в алгоритмах рекомендаций</string>
<string name="settings_indexable">Включить публичные посты в результаты поиска</string>
<plurals name="x_participants">
<item quantity="one">%,d участник</item>
<item quantity="few">%,d участника</item>
<item quantity="many">%,d участников</item>
<item quantity="other">%,d участников</item>
</plurals>
<plurals name="x_posts_today">
<item quantity="one">%,d пост сегодня</item>
<item quantity="few">%,d поста сегодня</item>
<item quantity="many">%,d постов сегодня</item>
<item quantity="other">%,d постов сегодня</item>
</plurals>
</resources>

View File

@@ -274,6 +274,8 @@
<string name="trending_posts_info_banner">To so objave, ki plenijo pozornost po Mastodonu.</string>
<string name="trending_links_info_banner">To so novice, o katerih se govori na Mastodonu.</string>
<!-- %s is the server domain -->
<string name="local_timeline_info_banner">To so vse objave vseh uporabnikov na vašem strežniku (%s).</string>
<string name="recommended_accounts_info_banner">Glede na to, komu sledite, vam bodo ti računi všeč.</string>
<string name="see_new_posts">Pokaži nove objave</string>
<string name="load_missing_posts">Naloži manjkajoče objave</string>
<string name="follow_back">Sledijo nazaj</string>
@@ -455,8 +457,11 @@
<!-- %s is the app name (Mastodon, key app_name). I made it a placeholder so everything Just Works™ with forks -->
<string name="about_app">O programu %s</string>
<string name="default_post_language">Privzeti jezik objave</string>
<string name="settings_confirm_delete_post">Vprašaj pred brisanjem objav</string>
<string name="pause_all_notifications">Premor za vse</string>
<string name="pause_notifications_off">Izklopljeno</string>
<string name="notifications_policy_anyone">Kdor koli</string>
<string name="notifications_policy_followed">Ljudje, ki vam sledijo</string>
<string name="notifications_policy_follower">Ljudje, ki jim sledite</string>
<string name="notifications_policy_no_one">Nihče</string>
<string name="notification_type_mentions_and_replies">Omembe in odgovori</string>
@@ -504,6 +509,7 @@
<string name="filter_context_profiles">Profili</string>
<string name="settings_filter_title">Naslov</string>
<string name="settings_delete_filter_title">Ali želite izbrisati filter »%s«?</string>
<string name="settings_delete_filter_confirmation">Ta filter bo izbrisan iz vašega računa na vseh vaših napravah.</string>
<string name="add_muted_word">Dodaj utišano besedo</string>
<string name="edit_muted_word">Uredi utišano besedo</string>
<string name="add">Dodaj</string>
@@ -533,5 +539,12 @@
<string name="time_hours_ago_short">pred %dh urami</string>
<string name="time_days_ago_short">pred %d dnemi</string>
<!-- %s is the name of the post language -->
<string name="translate_post">Prevedi iz jezika: %s</string>
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">Prevedeno iz %1$s s pomočjo %2$s</string>
<string name="translation_show_original">Pokaži izvirnik</string>
<string name="translation_failed">Prevod je spodletel. Morda skrbnik ni omogočil prevajanja na tem strežniku ali pa strežnik teče na starejši različici Masotodona, na kateri prevajanje še ni podprto.</string>
<string name="settings_privacy">Zasebnost in dosegljivost</string>
<string name="settings_discoverable">Izpostavljaj profile in objave v algoritmih odkrivanja</string>
<string name="settings_indexable">Med zadetke iskanja vključi javne objave</string>
</resources>

View File

@@ -559,6 +559,9 @@
<string name="post_translated">แปลจาก %1$s โดยใช้ %2$s</string>
<string name="translation_show_original">แสดงดั้งเดิม</string>
<string name="translation_failed">การแปลล้มเหลว บางทีผู้ดูแลอาจไม่ได้เปิดใช้งานการแปลในเซิร์ฟเวอร์นี้หรือเซิร์ฟเวอร์นี้กำลังใช้ Mastodon รุ่นเก่ากว่าที่ยังไม่รองรับการแปล</string>
<string name="settings_privacy">ความเป็นส่วนตัวและการเข้าถึง</string>
<string name="settings_discoverable">แสดงโปรไฟล์และโพสต์ในอัลกอริทึมการค้นพบ</string>
<string name="settings_indexable">รวมโพสต์สาธารณะในผลลัพธ์การค้นหา</string>
<plurals name="x_participants">
<item quantity="other">%,d ผู้มีส่วนร่วม</item>
</plurals>

View File

@@ -387,6 +387,7 @@
<string name="welcome_to_mastodon">Mastodon\'a hoş geldiniz</string>
<string name="welcome_paragraph1">Mastodon merkezi olmayan bir sosyal ağdır, yani onu tek bir şirket kontrol etmiyor. Hepsi birbirine bağlı, bağımsız olarak çalışan birçok sunucudan oluşur.</string>
<string name="what_are_servers">Sunucular nedir?</string>
<string name="welcome_paragraph2">Her Mastodon hesabı bir sunucuda barındırılır - her birinin kendi değerleri, kuralları ve yöneticileri vardır. Hangisini seçerseniz seçin, herhangi bir sunucudaki insanları takip edebilir ve onlarla etkileşime geçebilirsiniz.</string>
<string name="opening_link">Bağlantıılıyor…</string>
<string name="link_not_supported">Bu bağlantı uygulamada desteklenmiyor</string>
<string name="log_out_all_accounts">Tüm hesaplardan çıkış yap</string>
@@ -582,5 +583,20 @@
<string name="time_hours_ago_short">%dsa önce</string>
<string name="time_days_ago_short">%dg önce</string>
<!-- %s is the name of the post language -->
<string name="translate_post">%s dilinden çevrildi</string>
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">%2$s kullanılarak %1$s dilinden çevrildi</string>
<string name="translation_show_original">Özgün içeriği göster</string>
<string name="translation_failed">Çeviri başarısız oldu. Yönetici bu sunucuda çevirileri etkinleştirmemiş olabilir veya bu sunucu çevirilerin henüz desteklenmediği eski bir Mastodon sürümünü çalıştırıyor olabilir.</string>
<string name="settings_privacy">Gizlilik ve erişim</string>
<string name="settings_discoverable">Profil ve gönderileri keşif algoritmalarında kullan</string>
<string name="settings_indexable">Herkese açık gönderileri arama sonuçlarına ekle</string>
<plurals name="x_participants">
<item quantity="one">%d katılımcılar</item>
<item quantity="other">%d katılımcılar</item>
</plurals>
<plurals name="x_posts_today">
<item quantity="one">%,d bunu gönder</item>
<item quantity="other">%,d bunları gönder</item>
</plurals>
</resources>

View File

@@ -553,5 +553,12 @@
<string name="time_hours_ago_short">%d 小时前</string>
<string name="time_days_ago_short">%d 天前</string>
<!-- %s is the name of the post language -->
<string name="translate_post">从 %s 翻译</string>
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">从 %1$s 翻译成 %2$s</string>
<string name="translation_show_original">显示原文</string>
<string name="translation_failed">翻译失败。此服务器运行的 Mastodon 版本不支持翻译功能,或管理员未将翻译功能开启。</string>
<string name="settings_privacy">隐私与可达性</string>
<string name="settings_discoverable">在发现算法中展示您的个人资料和嘟文</string>
<string name="settings_indexable">将您的公开嘟文纳入搜索范围</string>
</resources>

View File

@@ -559,6 +559,9 @@
<string name="post_translated">透過 %2$s 翻譯 %1$s</string>
<string name="translation_show_original">顯示原文</string>
<string name="translation_failed">翻譯失敗。也許管理員未於此伺服器啟用翻譯功能,或此伺服器為未支援翻譯功能之舊版本 Mastodon。</string>
<string name="settings_privacy">隱私權及觸及</string>
<string name="settings_discoverable">於探索演算法中推薦個人檔案及嘟文</string>
<string name="settings_indexable">允許公開嘟文顯示於搜尋結果中</string>
<plurals name="x_participants">
<item quantity="other">%,d 位參與者</item>
</plurals>

View File

@@ -21,6 +21,7 @@
<item name="android:actionModeBackground">@color/m3_sys_light_primary</item>
<item name="android:actionModeStyle">@style/Widget.Mastodon.Toolbar.ActionMode</item>
<item name="android:actionModeCloseDrawable">@drawable/ic_actionmode_close</item>
<item name="appkitEmptyTextAppearance">@style/empty_text</item>
<!-- M3 colors -->
<item name="colorM3Primary">@color/m3_sys_light_primary</item>
@@ -85,6 +86,7 @@
<item name="android:windowActionModeOverlay">true</item>
<item name="android:actionModeBackground">@color/m3_sys_dark_primary</item>
<item name="android:actionModeCloseDrawable">@drawable/ic_actionmode_close</item>
<item name="appkitEmptyTextAppearance">@style/empty_text</item>
<!-- M3 colors -->
<item name="colorM3Primary">@color/m3_sys_dark_primary</item>
@@ -399,4 +401,8 @@
<style name="window_fade_out">
<item name="android:windowExitAnimation">@anim/fade_out_fast</item>
</style>
<style name="empty_text" parent="m3_body_large">
<item name="android:textColor">?colorM3OnSurfaceVariant</item>
</style>
</resources>

View File

@@ -0,0 +1,116 @@
// run: java tools/VerifyTranslatedStringFormatting.java
// Reads all localized strings and makes sure they contain valid formatting placeholders matching the original English strings to avoid crashes.
import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.*;
import java.util.*;
import java.util.regex.*;
public class VerifyTranslatedStringFormatting{
// %[argument_index$][flags][width][.precision][t]conversion
private static final String formatSpecifier="%(\\d+\\$)?([-#+ 0,(\\<]*)?(\\d+)?(\\.\\d+)?([tT])?([a-zA-Z%])";
private static final Pattern fsPattern=Pattern.compile(formatSpecifier);
private static HashMap<String, List<String>> placeholdersInStrings=new HashMap<>();
private static int errorCount=0;
public static void main(String[] args) throws Exception{
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false);
DocumentBuilder builder=factory.newDocumentBuilder();
Document doc;
try(FileInputStream in=new FileInputStream("mastodon/src/main/res/values/strings.xml")){
doc=builder.parse(in);
}
NodeList list=doc.getDocumentElement().getChildNodes(); // why does this stupid NodeList thing exist at all?
for(int i=0;i<list.getLength();i++){
if(list.item(i) instanceof Element el){
String name=el.getAttribute("name");
String value;
if("string".equals(el.getTagName())){
value=el.getTextContent();
}else if("plurals".equals(el.getTagName())){
value=el.getElementsByTagName("item").item(0).getTextContent();
}else{
System.out.println("Warning: unexpected tag "+name);
continue;
}
ArrayList<String> placeholders=new ArrayList<>();
Matcher matcher=fsPattern.matcher(value);
while(matcher.find()){
placeholders.add(matcher.group());
}
placeholdersInStrings.put(name, placeholders);
}
}
for(File file:new File("mastodon/src/main/res").listFiles()){
if(file.getName().startsWith("values-")){
File stringsXml=new File(file, "strings.xml");
if(stringsXml.exists()){
processFile(stringsXml);
}
}
}
if(errorCount>0){
System.err.println("Found "+errorCount+" problems in localized strings");
System.exit(1);
}
}
private static void processFile(File file) throws Exception{
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false);
DocumentBuilder builder=factory.newDocumentBuilder();
Document doc;
try(FileInputStream in=new FileInputStream(file)){
doc=builder.parse(in);
}
NodeList list=doc.getDocumentElement().getChildNodes();
for(int i=0;i<list.getLength();i++){
if(list.item(i) instanceof Element el){
String name=el.getAttribute("name");
String value;
if("string".equals(el.getTagName())){
value=el.getTextContent();
if(!verifyString(value, placeholdersInStrings.get(name))){
errorCount++;
System.out.println(file+": string "+name+" is missing placeholders");
}
}else if("plurals".equals(el.getTagName())){
NodeList items=el.getElementsByTagName("item");
for(int j=0;j<items.getLength();j++){
Element item=(Element)items.item(j);
value=item.getTextContent();
String quantity=item.getAttribute("quantity");
if(!verifyString(value, placeholdersInStrings.get(name))){
// Some languages use zero/one/two for just these numbers so they may skip the placeholder
// still make sure that there's no '%' characters to avoid crashes
if(List.of("zero", "one", "two").contains(quantity) && !value.contains("%")){
continue;
}
errorCount++;
System.out.println(file+": string "+name+"["+quantity+"] is missing placeholders");
}
}
}else{
System.out.println("Warning: unexpected tag "+name);
continue;
}
}
}
}
private static boolean verifyString(String str, List<String> placeholders){
for(String placeholder:placeholders){
if(placeholder.equals("%,d")){
// %,d and %d are interchangeable but %,d provides nicer formatting
if(!str.contains(placeholder) && !str.contains("%d"))
return false;
}else if(!str.contains(placeholder)){
return false;
}
}
return true;
}
}