Skip to content

Safe translations applied #1089

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jan 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ jobs:
# /!\ important: this checks out code from the HEAD of the PR instead of the main branch (for pull_request_target)
ref: ${{ github.event.pull_request.head.sha || github.ref }}

- name: Validate localizations
run: python localizations.py validate

- name: Add Apple Store Key
run: echo "${{ secrets.APPLE_STORE_AUTH_KEY }}" | base64 --decode -o ${{ env.APPLE_STORE_AUTH_KEY_PATH}}

Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,7 @@ Brewfile.lock.json

# this is CI specific
Brewfile_CI
Brewfile_CI.lock.json
Brewfile_CI.lock.json

# Generated localization swift file:
Support/LocalString.swift
6 changes: 6 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ default_install_hook_types: [post-merge, post-checkout, post-rewrite]
repos:
- repo: local
hooks:
- id: generate_localizations
name: "Generate localization swift file"
entry: python localizations.py generate
language: python
always_run: true
stages: [post-checkout, post-merge, post-rewrite]
- id: xcodegen
name: Generate project files for Xcode
description: "Generate project file for Xcode"
Expand Down
4 changes: 3 additions & 1 deletion .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
disabled_rules:
- trailing_whitespace
included:
- Views/Settings/
- Views/Settings/
excluded:
- Support/LocalString.swift
8 changes: 4 additions & 4 deletions App/App_macOS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ struct Kiwix: App {
}.commands {
SidebarCommands()
CommandGroup(replacing: .importExport) {
OpenFileButton(context: .command) { Text("app_macos_commands.open_file".localized) }
OpenFileButton(context: .command) { Text(LocalString.app_macos_commands_open_file) }
}
CommandGroup(replacing: .newItem) {
Button("app_macos_commands.new".localized) {
Button(LocalString.app_macos_commands_new) {
guard let currentWindow = NSApp.keyWindow,
let controller = currentWindow.windowController else { return }
controller.newWindowForTab(nil)
Expand Down Expand Up @@ -85,7 +85,7 @@ struct Kiwix: App {
}
.frame(width: 550, height: 400)
}
Window("payment.donate.title".localized, id: "donation") {
Window(LocalString.payment_donate_title, id: "donation") {
Group {
if let selectedAmount {
PaymentSummary(selectedAmount: selectedAmount, onComplete: {
Expand Down Expand Up @@ -187,7 +187,7 @@ struct RootView: View {
Label(navigationItem.name, systemImage: navigationItem.icon)
}
if FeatureFlags.hasLibrary {
Section("app_macos_navigation.button.library".localized) {
Section(LocalString.app_macos_navigation_button_library) {
ForEach(libraryItems, id: \.self) { navigationItem in
Label(navigationItem.name, systemImage: navigationItem.icon)
}
Expand Down
12 changes: 6 additions & 6 deletions App/CompactViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ final class CompactViewController: UIHostingController<AnyView>, UISearchControl
searchController.delegate = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.showsSearchResultsController = true
searchController.searchBar.searchTextField.placeholder = "common.search".localized
searchController.searchBar.searchTextField.placeholder = LocalString.common_search

searchTextObserver = searchViewModel.$searchText.sink { [weak self] searchText in
guard self?.searchController.searchBar.text != searchText else { return }
Expand All @@ -107,7 +107,7 @@ final class CompactViewController: UIHostingController<AnyView>, UISearchControl
trailingNavItemGroups = navigationItem.trailingItemGroups
navigationItem.setRightBarButton(
UIBarButtonItem(
title: "common.button.cancel".localized,
title: LocalString.common_button_cancel,
style: .done,
target: self,
action: #selector(onSearchCancelled)
Expand Down Expand Up @@ -185,14 +185,14 @@ private struct CompactView: View {
Button {
presentedSheet = .library
} label: {
Label("common.tab.menu.library".localized, systemImage: "folder")
Label(LocalString.common_tab_menu_library, systemImage: "folder")
}
Spacer()
}
Button {
presentedSheet = .settings
} label: {
Label("common.tab.menu.settings".localized, systemImage: "gear")
Label(LocalString.common_tab_menu_settings, systemImage: "gear")
}
Spacer()
}
Expand All @@ -209,7 +209,7 @@ private struct CompactView: View {
Button {
self.presentedSheet = nil
} label: {
Text("common.button.done".localized).fontWeight(.semibold)
Text(LocalString.common_button_done).fontWeight(.semibold)
}
}
}
Expand Down Expand Up @@ -285,7 +285,7 @@ private struct Content<LaunchModel>: View where LaunchModel: LaunchProtocol {
}
.toolbar {
ToolbarItemGroup(placement: .primaryAction) {
Button("article_shortcut.random.button.title.ios".localized,
Button(LocalString.article_shortcut_random_button_title_ios,
systemImage: "die.face.5",
action: { browser.loadRandomArticle() })
.disabled(zimFiles.isEmpty)
Expand Down
12 changes: 6 additions & 6 deletions App/SidebarViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class SidebarViewController: UICollectionViewController, NSFetchedResultsControl
},
menu: UIMenu(children: [
UIAction(
title: "sidebar_view.navigation.button.close".localized,
title: LocalString.sidebar_view_navigation_button_close,
image: UIImage(systemName: "xmark.square"),
attributes: .destructive
) { [unowned self] _ in
Expand All @@ -114,7 +114,7 @@ class SidebarViewController: UICollectionViewController, NSFetchedResultsControl
navigationViewModel.deleteTab(tabID: tabID)
},
UIAction(
title: "sidebar_view.navigation.button.close_all".localized,
title: LocalString.sidebar_view_navigation_button_close_all,
image: UIImage(systemName: "xmark.square.fill"),
attributes: .destructive
) { [unowned self] _ in
Expand Down Expand Up @@ -196,7 +196,7 @@ class SidebarViewController: UICollectionViewController, NSFetchedResultsControl
if case let .tab(objectID) = item,
let tab = try? Database.shared.viewContext.existingObject(with: objectID) as? Tab {
var config = cell.defaultContentConfiguration()
config.text = tab.title ?? "common.tab.menu.new_tab".localized
config.text = tab.title ?? LocalString.common_tab_menu_new_tab
if let zimFile = tab.zimFile, let category = Category(rawValue: zimFile.category) {
config.textProperties.numberOfLines = 1
if let imgData = zimFile.faviconData {
Expand Down Expand Up @@ -224,11 +224,11 @@ class SidebarViewController: UICollectionViewController, NSFetchedResultsControl
switch section {
case .tabs:
var config = UIListContentConfiguration.sidebarHeader()
config.text = "common.tab.navigation.title".localized
config.text = LocalString.common_tab_navigation_title
headerView.contentConfiguration = config
case .library:
var config = UIListContentConfiguration.sidebarHeader()
config.text = "common.tab.menu.library".localized
config.text = LocalString.common_tab_menu_library
headerView.contentConfiguration = config
default:
headerView.contentConfiguration = nil
Expand All @@ -239,7 +239,7 @@ class SidebarViewController: UICollectionViewController, NSFetchedResultsControl
guard let navigationViewModel,
let item = dataSource.itemIdentifier(for: indexPath),
case let .tab(tabID) = item else { return nil }
let title = "sidebar_view.navigation.button.close".localized
let title = LocalString.sidebar_view_navigation_button_close
let action = UIContextualAction(style: .destructive,
title: title) { [weak navigationViewModel] _, _, _ in
navigationViewModel?.deleteTab(tabID: tabID)
Expand Down
1 change: 1 addition & 0 deletions Brewfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ at_exit do
system "cp Support/CoreKiwix.modulemap CoreKiwix.xcframework/ios-arm64/Headers/module.modulemap"
system "cp Support/CoreKiwix.modulemap CoreKiwix.xcframework/ios-arm64_x86_64-simulator/Headers/module.modulemap"
system "cp Support/CoreKiwix.modulemap CoreKiwix.xcframework/macos-arm64_x86_64/Headers/module.modulemap"
system "python localizations.py generate"
system "xcodegen"
end
2 changes: 1 addition & 1 deletion Model/Brand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ enum Brand {
static let loadingLogoImage: String = "welcomeLogo"
static var loadingLogoSize: CGSize = ImageInfo.sizeOf(imageName: loadingLogoImage)!

static let aboutText: String = Config.value(for: .aboutText) ?? "settings.about.description".localized
static let aboutText: String = Config.value(for: .aboutText) ?? LocalString.settings_about_description
static let aboutWebsite: String = Config.value(for: .aboutWebsite) ?? "https://www.kiwix.org"
// currently only used under the Kiwix brand
// if this is set to true in Support/Info.plist the support/donation button is hidden (for macOS FTP)
Expand Down
4 changes: 2 additions & 2 deletions Model/DownloadService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -254,10 +254,10 @@ final class DownloadService: NSObject, URLSessionDelegate, URLSessionTaskDelegat
Database.shared.performBackgroundTask { context in
// configure notification content
let content = UNMutableNotificationContent()
content.title = "download_service.complete.title".localized
content.title = LocalString.download_service_complete_title
content.sound = .default
if let zimFile = try? context.fetch(ZimFile.fetchRequest(fileID: zimFileID)).first {
content.body = "download_service.complete.description".localizedWithFormat(withArgs: zimFile.name)
content.body = LocalString.download_service_complete_description(withArgs: zimFile.name)
}

// schedule notification
Expand Down
6 changes: 3 additions & 3 deletions Model/Entities/Errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ public enum LibraryRefreshError: LocalizedError {
public var errorDescription: String? {
switch self {
case .retrieve(let description):
let prefix = "library_refresh_error.retrieve.description".localizedWith(comment: "Library Refresh Error")
let prefix = LocalString.library_refresh_error_retrieve_description
return [prefix, description].compactMap({ $0 }).joined(separator: " ")
case .parse:
return "library_refresh_error.parse.description".localizedWith(comment: "Library Refresh Error")
return LocalString.library_refresh_error_parse_description
case .process:
return "library_refresh_error.process.description".localizedWith(comment: "Library Refresh Error")
return LocalString.library_refresh_error_process_description
}
}
}
6 changes: 3 additions & 3 deletions Model/Payment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ struct Payment {
request.supportedNetworks = Self.supportedNetworks
request.requiredBillingContactFields = [.emailAddress]
let recurring: PKRecurringPaymentRequest? = if selectedAmount.isMonthly {
PKRecurringPaymentRequest(paymentDescription: "payment.description.label".localized,
regularBilling: .init(label: "payment.monthly_support.label".localized,
PKRecurringPaymentRequest(paymentDescription: LocalString.payment_description_label,
regularBilling: .init(label: LocalString.payment_monthly_support_label,
amount: NSDecimalNumber(value: selectedAmount.value),
type: .final),
managementURL: URL(string: Self.paymentSubscriptionManagingURL)!)
Expand All @@ -157,7 +157,7 @@ struct Payment {
request.recurringPaymentRequest = recurring
request.paymentSummaryItems = [
PKPaymentSummaryItem(
label: "payment.summary.title".localized,
label: LocalString.payment_summary_title,
amount: NSDecimalNumber(value: selectedAmount.value),
type: .final
)
Expand Down
40 changes: 0 additions & 40 deletions Model/Utilities/String+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,46 +17,6 @@ import Foundation

extension String {

var localized: String {
localizedWithFallback()
}

func localizedWith(comment: String) -> String {
localizedWithFallback(comment: comment)
}

func localizedWithFormat(withArgs: CVarArg...) -> String {
let format = localizedWithFallback()
switch withArgs.count {
case 1: return String.localizedStringWithFormat(format, withArgs[0])
case 2: return String.localizedStringWithFormat(format, withArgs[0], withArgs[1])
default: return String.localizedStringWithFormat(format, withArgs)
}
}

private func localizedWithFallback(
bundle: Bundle = Bundle.main,
comment: String = ""
) -> String {
let englishValue: String
if let path = Bundle.main.path(forResource: "en", ofType: "lproj"),
let bundle = Bundle(path: path) {
englishValue = NSLocalizedString(self, bundle: bundle, comment: comment)
if NSLocale.preferredLanguages.first == "en" {
return englishValue
}
} else {
englishValue = ""
}
return NSLocalizedString(
self,
tableName: nil,
bundle: bundle,
value: englishValue, // fall back to this, if translation not found
comment: comment
)
}

func removingPrefix(_ value: String) -> String {
guard hasPrefix(value) else { return self }
return String(dropFirst(value.count))
Expand Down
56 changes: 56 additions & 0 deletions Support/StringLocalExtension.swift_temp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// This file is part of Kiwix for iOS & macOS.
//
// Kiwix is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// any later version.
//
// Kiwix is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kiwix; If not, see https://www.gnu.org/licenses/.

import Foundation

fileprivate extension String {

var localized: String {
localizedWithFallback()
}

func localizedWithFormat(withArgs: CVarArg...) -> String {
let format = localizedWithFallback()
switch withArgs.count {
case 1: return String.localizedStringWithFormat(format, withArgs[0])
case 2: return String.localizedStringWithFormat(format, withArgs[0], withArgs[1])
default: return String.localizedStringWithFormat(format, withArgs)
}
}

private func localizedWithFallback(
bundle: Bundle = Bundle.main,
comment: String = ""
) -> String {
let englishValue: String
if let path = Bundle.main.path(forResource: "en", ofType: "lproj"),
let bundle = Bundle(path: path) {
englishValue = NSLocalizedString(self, bundle: bundle, comment: comment)
if NSLocale.preferredLanguages.first == "en" {
return englishValue
}
} else {
englishValue = ""
}
return NSLocalizedString(
self,
tableName: nil,
bundle: bundle,
value: englishValue, // fall back to this, if translation not found
comment: comment
)
}
}

6 changes: 2 additions & 4 deletions Support/br.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
"common.tab.list.close" = "Serriñ ar steudenn";
"common.tab.menu.library" = "Levraoueg";
"common.tab.menu.settings" = "Arventennoù";
"common.support.app_name" = "Skoazellañ %@";
"common.export_file.alert.title" = "Ezporzhiañ ar restr";
"common.export_file.alert.description" = "Fellout a ra deoc'h ezporzhiañ ar restr %@?";
"common.export_file.alert.button.title" = "Ezporzhiañ";
Expand All @@ -51,7 +50,7 @@
"flavor_tag.help.no_pic" = "lamet eo bet darn vrasañ ar skeudennoù";
"library_refresh_time.last" = "Nevez zo";
"library_refresh_time.never" = "James";
"zim_file_cell_article_count_suffix" = "pennadoù";
"zim_file_cell.article_count.suffix" = "pennadoù";
"zim_file_missing_indicator.help" = "Ar restr ZIM a vank.";
"library.zim_file_context.main_page.label" = "Degemer";
"library.zim_file_context.random.label" = "Pajenn dre zegouezh";
Expand All @@ -65,7 +64,7 @@
"zim_file_category.section.empty.message" = "Restr ZIM ebet er rummad-mañ.";
"zim_file_downloads.toolbar.show_sidebar.label" = "Diskouez ar varrenn-gostez";
"zim_file_new_overlay.empty" = "Restr ZIM nevez ebet";
"zim_file_new_button_refresh" = "Freskaat";
"zim_file_new.button.refresh" = "Freskaat";
"zim_file.list.name.text" = "Anv";
"zim_file.list.description.text" = "Deskrivadur";
"zim_file.list.actions.text" = "Oberoù";
Expand Down Expand Up @@ -144,7 +143,6 @@
"app_macos_commands.open_file" = "Digeriñ...";
"app_macos_commands.new" = "Steudenn nevez";
"app_macos_navigation.button.library" = "Levraoueg";
"app_macos_navigation.show_sidebar" = "Diskouez ar varrenn-gostez";
"sidebar_view.navigation.button.close" = "Serriñ";
"sidebar_view.navigation.button.close_all" = "Serriñ an holl steudennoù";
"enum.category.wikipedia" = "Wikipedia";
Expand Down
4 changes: 2 additions & 2 deletions Support/dag.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"flavor_tag.help.mini" = "Sabbu ŋɔ bela koŋko nyɛ din be ni, di yi pa shɛli tuuli yaɣili";
"library_refresh_time.last" = "Kulla saha ŋɔ";
"library_refresh_time.never" = "Abada";
"zim_file_cell_article_count_suffix" = "Lahabaya";
"zim_file_cell.article_count.suffix" = "Lahabaya";
"zim_file_missing_indicator.help" = "Zim fasara nyɛla din kani.";
// Fuzzy
"library.zim_file_details.side_panel.message" = "Piimi zim fasara n- nya bayana";
Expand All @@ -71,7 +71,7 @@
"zim_file_downloads.overlay.empty.message" = "Deebu tuma nima kani";
"zim_file_downloads.toolbar.show_sidebar.label" = "Wuhimi \"Sidebar\"";
"zim_file_new_overlay.empty" = "Zim fasara palli kani";
"zim_file_new_button_refresh" = "Kahigi";
"zim_file_new.button.refresh" = "Kahigi";
"zim_file.list.name.text" = "Yuli";
"zim_file.list.description.text" = "Buɣisibu";
"zim_file.list.actions.text" = "Niŋsim";
Expand Down
Loading