Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
fd07fec
ADFA-4795: extract Wizard hardcoded strings to resources
luisguzman-adfa Jul 21, 2026
347dbaa
ADFA-4795: localize Wizard + nav strings across 33 locales
luisguzman-adfa Jul 21, 2026
27f8c2b
ADFA-4795: extract + localize Settings strings across 33 locales
luisguzman-adfa Jul 21, 2026
d8201a0
ADFA-4795: extract Clone/Connect Java string literals to resources
luisguzman-adfa Jul 21, 2026
1fcb27e
ADFA-4795: extract Clone layout string literals to resources
luisguzman-adfa Jul 21, 2026
8ecd325
ADFA-4795: localize Clone send-spine strings across 33 locales
luisguzman-adfa Jul 21, 2026
2cbe896
ADFA-4795: localize Clone receive/confirm/scan strings across 33 locales
luisguzman-adfa Jul 22, 2026
c916581
ADFA-4795: localize Clone incompat/send-app + Connect strings across …
luisguzman-adfa Jul 22, 2026
2182a32
ADFA-4795: localize remaining redesign strings across 33 locales
luisguzman-adfa Jul 22, 2026
55c20a5
ADFA-4795: extract Settings menu + Advanced sub-screen strings to res…
luisguzman-adfa Jul 22, 2026
2a453a5
ADFA-4795: localize Settings menu + Advanced sub-screen across 33 loc…
luisguzman-adfa Jul 22, 2026
3e09e79
ADFA-4795: extract redesign dialog/toast/misc strings to resources (s…
luisguzman-adfa Jul 22, 2026
21f504b
ADFA-4795: rewire dialog/toast/misc literals to extracted resources
luisguzman-adfa Jul 22, 2026
7435198
ADFA-4795: localize redesign dialogs/toasts/misc strings across 33 lo…
luisguzman-adfa Jul 22, 2026
4341cbe
ADFA-4795: extract redesign dynamic text to resources (sweep 3)
luisguzman-adfa Jul 22, 2026
14d45ae
ADFA-4795: localize redesign dynamic text across 33 locales (sweep 3)
luisguzman-adfa Jul 22, 2026
d4d1b1c
ADFA-4795: localize storage-bar legend across 33 locales
luisguzman-adfa Jul 22, 2026
e8bfe92
ADFA-4795: localize permission action state (Allow/Granted)
luisguzman-adfa Jul 22, 2026
7a50c8b
ADFA-4795: extract clone back-header, ready/step states, paste hint, …
luisguzman-adfa Jul 22, 2026
e89fd29
ADFA-4795: localize clone header/ready/step/paste-hint, Soon badge, f…
luisguzman-adfa Jul 22, 2026
c53500c
ADFA-4795: extract + localize arch technical labels (incompat flow)
luisguzman-adfa Jul 22, 2026
e6e3c37
ADFA-4795: localize Lottie OPEN/CLOSED sign + global font + wider board
luisguzman-adfa Jul 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,15 @@ private void renderHotspot() {
LocalHotspotManager.Phase phase = (st != null) ? st.phase : LocalHotspotManager.Phase.OFF;

if (!LocalHotspotManager.isSupported()) {
simpleState("Hotspot needs Android 8 or newer", "Try the Wi-Fi option instead.");
simpleState(getString(R.string.k2go_connect_hotspot_unsupported), getString(R.string.k2go_connect_try_wifi));
return;
}
if (phase == LocalHotspotManager.Phase.OFF || phase == LocalHotspotManager.Phase.STARTING) {
simpleState("Starting hotspot…", "");
simpleState(getString(R.string.k2go_connect_starting_hotspot), "");
return;
}
if (phase == LocalHotspotManager.Phase.FAILED) {
simpleState("Couldn't start the hotspot", "Enable Location, then tap Hotspot again.");
simpleState(getString(R.string.k2go_connect_hotspot_failed), getString(R.string.k2go_connect_enable_location));
return;
}

Expand All @@ -149,17 +149,17 @@ private void renderHotspot() {
setQr("WIFI:S:" + ssid + ";T:WPA;P:" + pass + ";;");
caption.setText(R.string.k2go_scan_join_hotspot);
subCaption.setText(R.string.k2go_just_scan);
setFallback(new String[]{"Wi-Fi: " + ssid, "Password: " + pass});
setFallback(new String[]{getString(R.string.k2go_fallback_wifi, ssid), getString(R.string.k2go_fallback_pass, pass)});
advance.setText(R.string.k2go_connect_shownext);
styleAdvance(true);
} else {
String ip = NetworkInterfaces.discover().hotspotIp;
if (ip == null) ip = "192.168.49.1";
setQr(browseUrl(ip));
caption.setText("Scan to open the library");
subCaption.setText("Read-only access to your content.");
caption.setText(getString(R.string.k2go_connect_scan_open));
subCaption.setText(getString(R.string.k2go_connect_readonly));
setFallback(new String[]{browseUrl(ip)});
advance.setText("‹ Back to step 1");
advance.setText(getString(R.string.k2go_clone_back_step1));
styleAdvance(false);
finish.setVisibility(openDone ? View.GONE : View.VISIBLE);
advance.setVisibility(openDone ? View.GONE : View.VISIBLE);
Expand All @@ -171,12 +171,12 @@ private void renderWifi() {
advance.setVisibility(View.GONE);
String ip = NetworkInterfaces.discover().wifiIp;
if (ip == null) {
simpleState("Not on a Wi-Fi network", "Join a Wi-Fi, or use Hotspot.");
simpleState(getString(R.string.k2go_connect_no_wifi), getString(R.string.k2go_connect_join_wifi));
return;
}
setQr(browseUrl(ip));
caption.setText("Scan to open the library");
subCaption.setText("You're on the same Wi-Fi — one code.");
caption.setText(getString(R.string.k2go_connect_scan_open));
subCaption.setText(getString(R.string.k2go_connect_same_wifi));
setFallback(new String[]{browseUrl(ip)});
finish.setVisibility(View.VISIBLE); // same forward exit back to the library
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,19 @@ protected void onCreate(Bundle savedInstanceState) {
installBar = findViewById(R.id.k2go_install_bar);
installDetail = findViewById(R.id.k2go_install_detail);
installing = getIntent().getBooleanExtra(EXTRA_INSTALLING, false);
// The Lottie has a text layer (OPEN/CLOSED sign) referencing "Atkinson Hyperlegible".
// Without this delegate Lottie looks for assets/fonts/Atkinson Hyperlegible.ttf and
// crashes (Font asset not found). Feed it the app's Atkinson font resource instead.
// The Lottie has a text layer (OPEN/CLOSED sign). Use the system typeface (Noto-based,
// global script fallback) so localized words render in any language; a TextDelegate maps
// the OPEN/CLOSED source text to the localized @string values.
bootGate.setFontAssetDelegate(new com.airbnb.lottie.FontAssetDelegate() {
@Override
public android.graphics.Typeface fetchFont(String fontFamily) {
android.graphics.Typeface tf = androidx.core.content.res.ResourcesCompat.getFont(
LibraryActivity.this, R.font.atkinson_hyperlegible);
return tf != null ? tf : android.graphics.Typeface.DEFAULT;
return android.graphics.Typeface.create(android.graphics.Typeface.DEFAULT, android.graphics.Typeface.BOLD);
}
});
com.airbnb.lottie.TextDelegate signText = new com.airbnb.lottie.TextDelegate(bootGate);
signText.setText("OPEN", getString(R.string.k2go_sign_open));
signText.setText("CLOSED", getString(R.string.k2go_sign_closed));
bootGate.setTextDelegate(signText);
if (!reduceMotion()) {
bootGate.setAnimation(R.raw.library_animation);
bootGate.setMinAndMaxFrame("A_ENTRY_LOOP");
Expand Down Expand Up @@ -152,12 +154,12 @@ private void showInstallProgress(InstallState st) {
if (installProgress == null || st == null || !st.isRunning()) return;
installProgress.setVisibility(View.VISIBLE);
if (st.phase == InstallState.Phase.DOWNLOADING) {
installStatus.setText("Downloading your library…");
installStatus.setText(getString(R.string.k2go_downloading_library));
installBar.setIndeterminate(false);
installBar.setProgress(st.percent);
installDetail.setText(st.percent + "%" + (st.speed.isEmpty() ? "" : " · " + st.speed));
} else {
installStatus.setText(st.message.isEmpty() ? "Setting up your library…" : st.message);
installStatus.setText(st.message.isEmpty() ? getString(R.string.k2go_setting_up_library) : st.message);
installBar.setIndeterminate(true);
installDetail.setText("");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
homeStatusDot = root.findViewById(R.id.k2go_home_status_dot);

cards.clear();
cards.add(new Card("books", "Read a book", false, R.drawable.ic_card_book));
cards.add(new Card("code", "Code on the Go", false, R.drawable.ic_card_code));
cards.add(new Card("kiwix", "Explore Wikipedia", true, R.drawable.ic_card_wikipedia));
cards.add(new Card("kolibri", "Take courses", false, R.drawable.ic_card_courses));
cards.add(new Card("maps", "Navigate maps", false, R.drawable.ic_card_maps));
cards.add(new Card("books", getString(R.string.k2go_card_books), false, R.drawable.ic_card_book));
cards.add(new Card("code", getString(R.string.k2go_card_code), false, R.drawable.ic_card_code));
cards.add(new Card("kiwix", getString(R.string.k2go_card_wikipedia), true, R.drawable.ic_card_wikipedia));
cards.add(new Card("kolibri", getString(R.string.k2go_card_courses), false, R.drawable.ic_card_courses));
cards.add(new Card("maps", getString(R.string.k2go_card_maps), false, R.drawable.ic_card_maps));

buildCards(inflater, root.findViewById(R.id.k2go_cards));

Expand Down Expand Up @@ -123,7 +123,7 @@ private void onCardClick(Card c) {
final int st = probe(c.endpoint);
main.post(() -> { if (isAdded()) applyState(c, (st == GREEN || st == GRAY) ? st : AMBER); });
});
Toast.makeText(requireContext(), "Retrying…", Toast.LENGTH_SHORT).show();
Toast.makeText(requireContext(), getString(R.string.k2go_retrying), Toast.LENGTH_SHORT).show();
}
}

Expand All @@ -132,12 +132,12 @@ private void onCardClick(Card c) {

private void refreshStatuses() {
boolean alive = ServerStateRepository.get().current().alive;
if (homeStatus != null) homeStatus.setText(alive ? "Ready to explore" : "Starting your library…");
if (homeStatus != null) homeStatus.setText(alive ? getString(R.string.k2go_home_ready) : getString(R.string.k2go_starting_library));
if (homeStatusDot != null) tint(homeStatusDot, alive ? R.color.k2go_leaf : R.color.k2go_amber);
for (final Card c : cards) {
if (c.requires64 && android.os.Build.SUPPORTED_64_BIT_ABIS.length == 0) {
applyState(c, GRAY);
if (c.status != null) c.status.setText("Not supported");
if (c.status != null) c.status.setText(getString(R.string.k2go_not_supported));
continue;
}
if (!alive) { applyState(c, GRAY); continue; }
Expand All @@ -158,10 +158,10 @@ private void applyState(Card c, int st) {
int dotColor, textColor;
String label;
switch (st) {
case GREEN: dotColor = R.color.k2go_leaf; textColor = R.color.k2go_leaf; label = "Ready"; break;
case AMBER: dotColor = R.color.k2go_amber; textColor = R.color.k2go_amber_text; label = "Connecting"; break;
case RED: dotColor = R.color.k2go_clay; textColor = R.color.k2go_clay; label = "Unavailable · tap to retry"; break;
default: dotColor = R.color.k2go_muted; textColor = R.color.k2go_muted; label = "Not installed"; break;
case GREEN: dotColor = R.color.k2go_leaf; textColor = R.color.k2go_leaf; label = getString(R.string.k2go_card_ready); break;
case AMBER: dotColor = R.color.k2go_amber; textColor = R.color.k2go_amber_text; label = getString(R.string.k2go_card_connecting); break;
case RED: dotColor = R.color.k2go_clay; textColor = R.color.k2go_clay; label = getString(R.string.k2go_card_unavailable); break;
default: dotColor = R.color.k2go_muted; textColor = R.color.k2go_muted; label = getString(R.string.k2go_card_not_installed); break;
}
tint(c.dot, dotColor);
c.status.setText(label);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
LinearLayout list = root.findViewById(R.id.k2go_settings_list);
LinearLayout footer = root.findViewById(R.id.k2go_settings_footer);

SettingsUi.row(ctx, list, "Language", null, null, v -> openSub("language"));
SettingsUi.row(ctx, list, "Theme", null, themeLabel(), v -> chooseTheme());
SettingsUi.preview(ctx, list, "Help", null);
SettingsUi.row(ctx, list, "Send feedback", null, null, v -> openFeedback());
SettingsUi.row(ctx, list, "About", null, versionName(), v -> openSub("about"));
SettingsUi.row(ctx, list, "Advanced", "System, backups, developer tools", null, v -> openSub("advanced"));
SettingsUi.row(ctx, list, getString(R.string.k2go_settings_language), null, null, v -> openSub("language"));
SettingsUi.row(ctx, list, getString(R.string.k2go_settings_theme), null, themeLabel(), v -> chooseTheme());
SettingsUi.preview(ctx, list, getString(R.string.k2go_settings_help), null);
SettingsUi.row(ctx, list, getString(R.string.k2go_settings_send_feedback), null, null, v -> openFeedback());
SettingsUi.row(ctx, list, getString(R.string.k2go_settings_about), null, versionName(), v -> openSub("about"));
SettingsUi.row(ctx, list, getString(R.string.k2go_settings_advanced), getString(R.string.k2go_settings_advanced_sub), null, v -> openSub("advanced"));

buildFooter(ctx, footer);
return root;
Expand All @@ -55,13 +55,13 @@ private void openFeedback() {
}

private void chooseTheme() {
final String[] labels = {"Light", "Follow system", "Dark"};
final String[] labels = {getString(R.string.k2go_theme_light), getString(R.string.k2go_theme_system), getString(R.string.k2go_theme_dark)};
final int[] modes = {
AppCompatDelegate.MODE_NIGHT_NO,
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM,
AppCompatDelegate.MODE_NIGHT_YES};
new AlertDialog.Builder(requireContext())
.setTitle("Theme")
.setTitle(getString(R.string.k2go_settings_theme))
.setItems(labels, (d, w) -> {
prefs().edit().putInt("k2go_theme", modes[w]).apply();
AppCompatDelegate.setDefaultNightMode(modes[w]);
Expand All @@ -71,23 +71,23 @@ private void chooseTheme() {

private String themeLabel() {
switch (prefs().getInt("k2go_theme", AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)) {
case AppCompatDelegate.MODE_NIGHT_NO: return "Light";
case AppCompatDelegate.MODE_NIGHT_YES: return "Dark";
default: return "Follow system";
case AppCompatDelegate.MODE_NIGHT_NO: return getString(R.string.k2go_theme_light);
case AppCompatDelegate.MODE_NIGHT_YES: return getString(R.string.k2go_theme_dark);
default: return getString(R.string.k2go_theme_system);
}
}

private void buildFooter(Context ctx, LinearLayout footer) {
TextView note = new TextView(ctx);
note.setText("K2Go keeps running in the background until you turn it off.");
note.setText(getString(R.string.k2go_settings_running_note));
note.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodySmall);
note.setTextColor(ContextCompat.getColor(ctx, R.color.k2go_muted));
LinearLayout.LayoutParams np = new LinearLayout.LayoutParams(-1, -2);
np.bottomMargin = SettingsUi.dp(ctx, 8);
footer.addView(note, np);

TextView off = new TextView(ctx);
off.setText("Turn off K2Go");
off.setText(getString(R.string.k2go_settings_turn_off));
off.setGravity(Gravity.CENTER);
off.setPadding(SettingsUi.dp(ctx, 16), SettingsUi.dp(ctx, 16), SettingsUi.dp(ctx, 16), SettingsUi.dp(ctx, 16));
off.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_TitleLarge);
Expand All @@ -100,10 +100,10 @@ private void buildFooter(Context ctx, LinearLayout footer) {

private void confirmTurnOff() {
new AlertDialog.Builder(requireContext())
.setTitle("Turn off K2Go?")
.setMessage("This stops the library and closes the app. (Home or back only minimize it — it keeps running in the background.)")
.setNegativeButton("Cancel", null)
.setPositiveButton("Turn off", (d, w) -> {
.setTitle(getString(R.string.k2go_settings_turnoff_title))
.setMessage(getString(R.string.k2go_settings_turnoff_msg))
.setNegativeButton(getString(R.string.k2go_cancel), null)
.setPositiveButton(getString(R.string.k2go_settings_turnoff_confirm), (d, w) -> {
if (getActivity() instanceof LibraryActivity) {
((LibraryActivity) getActivity()).turnOffK2Go();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,17 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c

String screen = getArguments() != null ? getArguments().getString(ARG, "") : "";
switch (screen) {
case "language": title.setText("Language"); buildLanguage(ctx, list); break;
case "about": title.setText("About"); buildAbout(ctx, list); break;
case "advanced": title.setText("Advanced"); buildAdvanced(ctx, list); break;
default: title.setText("Settings");
case "language": title.setText(getString(R.string.k2go_settings_language)); buildLanguage(ctx, list); break;
case "about": title.setText(getString(R.string.k2go_settings_about)); buildAbout(ctx, list); break;
case "advanced": title.setText(getString(R.string.k2go_settings_advanced)); buildAdvanced(ctx, list); break;
default: title.setText(getString(R.string.k2go_tab_settings));
}
return root;
}

// ---- Language: one choice sets BOTH the app UI locale and the content language ----
private void buildLanguage(Context ctx, LinearLayout list) {
SettingsUi.caption(ctx, list, "Sets the app language and the default content language.");
SettingsUi.caption(ctx, list, getString(R.string.k2go_settings_lang_caption));
List<AppLanguage> langs = SupportedAppLanguages.all(getString(R.string.setup_app_lang_system));
String current = AppLocaleController.currentTag();
for (AppLanguage lang : langs) {
Expand All @@ -82,14 +82,14 @@ private void applyLanguage(Context ctx, String tag) {

// ---- About ----
private void buildAbout(Context ctx, LinearLayout list) {
SettingsUi.infoRow(ctx, list, "App version", versionName(ctx));
SettingsUi.row(ctx, list, "Permissions", null, null, v -> openAppSettings(ctx));
SettingsUi.toggle(ctx, list, "Share usage statistics", AnalyticsConsent.isEnabled(ctx), checked -> {
SettingsUi.infoRow(ctx, list, getString(R.string.k2go_settings_app_version), versionName(ctx));
SettingsUi.row(ctx, list, getString(R.string.k2go_settings_permissions), null, null, v -> openAppSettings(ctx));
SettingsUi.toggle(ctx, list, getString(R.string.k2go_settings_usage_stats), AnalyticsConsent.isEnabled(ctx), checked -> {
AnalyticsConsent.setEnabled(ctx, checked);
org.iiab.controller.analytics.AnalyticsClient.with(ctx).applyConsent();
});
SettingsUi.preview(ctx, list, "Open-source licenses", null);
SettingsUi.preview(ctx, list, "Privacy", null);
SettingsUi.preview(ctx, list, getString(R.string.k2go_settings_licenses), null);
SettingsUi.preview(ctx, list, getString(R.string.k2go_settings_privacy), null);
}

private void openAppSettings(Context ctx) {
Expand All @@ -109,13 +109,13 @@ private void openTerminal(Context ctx) {

// ---- Advanced (power-user features — preview for now) ----
private void buildAdvanced(Context ctx, LinearLayout list) {
SettingsUi.caption(ctx, list, "For power users.");
SettingsUi.sectionHeader(ctx, list, "SYSTEM");
SettingsUi.preview(ctx, list, "Module management", "Tier, add modules, hide");
SettingsUi.preview(ctx, list, "Backups & recovery", null);
SettingsUi.sectionHeader(ctx, list, "DEVELOPER");
SettingsUi.caption(ctx, list, getString(R.string.k2go_settings_power_users));
SettingsUi.sectionHeader(ctx, list, getString(R.string.k2go_settings_sec_system));
SettingsUi.preview(ctx, list, getString(R.string.k2go_settings_module_mgmt), getString(R.string.k2go_settings_module_mgmt_sub));
SettingsUi.preview(ctx, list, getString(R.string.k2go_settings_backups), null);
SettingsUi.sectionHeader(ctx, list, getString(R.string.k2go_settings_sec_developer));
SettingsUi.preview(ctx, list, "ADB", null);
SettingsUi.preview(ctx, list, "Network & DNS", null);
SettingsUi.preview(ctx, list, getString(R.string.k2go_settings_network_dns), null);
SettingsUi.row(ctx, list, "Terminal (Debian)", null, null, v -> openTerminal(ctx));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ static void preview(Context c, LinearLayout list, String title, String subtitle)
col.addView(title(c, title));
if (subtitle != null && !subtitle.isEmpty()) col.addView(sub(c, subtitle));
row.addView(col);
row.addView(sub(c, "Soon"));
row.addView(sub(c, c.getString(R.string.k2go_soon)));
}

static void toggle(Context c, LinearLayout list, String titleText, boolean checked, OnToggle cb) {
Expand Down
Loading