diff --git a/ios/HackerNews.xcodeproj/project.pbxproj b/ios/HackerNews.xcodeproj/project.pbxproj index 90354fe1..db07f8d6 100644 --- a/ios/HackerNews.xcodeproj/project.pbxproj +++ b/ios/HackerNews.xcodeproj/project.pbxproj @@ -692,6 +692,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; @@ -747,6 +748,7 @@ MTL_FAST_MATH = YES; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-O"; VALIDATE_PRODUCT = YES; }; @@ -782,6 +784,7 @@ "@executable_path/Frameworks", ); LIBRARY_SEARCH_PATHS = "\"$(PROJECT_DIR)/Frameworks/Reaper.xcframework\""; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MARKETING_VERSION = 3.10; OTHER_LDFLAGS = "-fprofile-instr-generate"; OTHER_SWIFT_FLAGS = "-profile-generate -profile-coverage-mapping"; @@ -826,6 +829,7 @@ "@executable_path/Frameworks", ); LIBRARY_SEARCH_PATHS = "\"$(PROJECT_DIR)/Frameworks/Reaper.xcframework\""; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MARKETING_VERSION = 3.10; PRODUCT_BUNDLE_IDENTIFIER = com.emergetools.hackernews; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1030,6 +1034,7 @@ MTL_FAST_MATH = YES; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-O"; VALIDATE_PRODUCT = YES; }; @@ -1064,6 +1069,7 @@ "@executable_path/Frameworks", ); LIBRARY_SEARCH_PATHS = "\"$(PROJECT_DIR)/Frameworks/Reaper.xcframework\""; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MARKETING_VERSION = 3.10; PRODUCT_BUNDLE_IDENTIFIER = com.emergetools.hackernews; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/ios/HackerNews/Auth/LoginRow.swift b/ios/HackerNews/Auth/LoginRow.swift index 645c7956..4d03ffa3 100644 --- a/ios/HackerNews/Auth/LoginRow.swift +++ b/ios/HackerNews/Auth/LoginRow.swift @@ -41,7 +41,7 @@ struct LoginRow: View { } func loginText() -> String { - return loggedIn ? "Logout" : "Login" + return loggedIn ? String(localized: "auth.button.logout") : String(localized: "auth.button.login") } func glowColor() -> Color { diff --git a/ios/HackerNews/Auth/LoginScreen.swift b/ios/HackerNews/Auth/LoginScreen.swift index e9e21c2a..4c4fd205 100644 --- a/ios/HackerNews/Auth/LoginScreen.swift +++ b/ios/HackerNews/Auth/LoginScreen.swift @@ -39,7 +39,7 @@ struct LoginScreen: View { Spacer() .frame(maxHeight: 16) - TextField("Username", text: $loginState.username) + TextField(String(localized: "auth.field.username"), text: $loginState.username) .textInputAutocapitalization(.none) .padding() .background(Color.background) @@ -49,7 +49,7 @@ struct LoginScreen: View { .stroke(Color.background.opacity(0.5), lineWidth: 1) ) - SecureField("Password", text: $loginState.password) + SecureField(String(localized: "auth.field.password"), text: $loginState.password) .padding() .background(Color.background) .clipShape(RoundedRectangle(cornerRadius: 12)) @@ -59,16 +59,16 @@ struct LoginScreen: View { ) if loginState.showError { - Text("Invalid username or password") + Text("auth.error.invalidCredentials") .foregroundColor(.red) .font(.ibmPlexMono(.regular, size: 14)) } HStack(spacing: 0) { - Text("By signing in, you agree to the ") + Text("auth.agreement.prefix") .font(.ibmPlexSans(.regular, size: 12)) - Text("Hacker News Guidelines") + Text("auth.agreement.guidelines") .font(.ibmPlexSans(.regular, size: 12)) .foregroundColor(.blue) .underline() @@ -97,7 +97,7 @@ struct LoginScreen: View { } }, label: { - Text("Submit") + Text("auth.button.submit") .font(.ibmPlexMono(.bold, size: 16)) .frame(maxWidth: .infinity) .frame(height: 40) diff --git a/ios/HackerNews/Bookmarks/BookmarksScreen.swift b/ios/HackerNews/Bookmarks/BookmarksScreen.swift index ec420a0f..86ae1884 100644 --- a/ios/HackerNews/Bookmarks/BookmarksScreen.swift +++ b/ios/HackerNews/Bookmarks/BookmarksScreen.swift @@ -16,7 +16,7 @@ struct BookmarksScreen: View { Group { if model.bookmarks.isEmpty { ZStack { - Text("Long-press a story to bookmark it.") + Text("bookmarks.emptyState") .font(.ibmPlexSans(.medium, size: 18)) } } else { @@ -47,7 +47,7 @@ struct BookmarksScreen: View { .background(.ultraThinMaterial) .containerShape(.rect(cornerRadius: 24, style: .continuous)) - Text("Bookmarks") + Text("bookmarks.title") .font(.ibmPlexMono(.bold, size: 24)) .padding(.horizontal, 16) } diff --git a/ios/HackerNews/Comments/CommentComposer.swift b/ios/HackerNews/Comments/CommentComposer.swift index 88ecfca0..b7ee569e 100644 --- a/ios/HackerNews/Comments/CommentComposer.swift +++ b/ios/HackerNews/Comments/CommentComposer.swift @@ -16,11 +16,11 @@ struct CommentComposer: View { HStack(alignment: .center) { Image(systemName: "message.fill") .font(.system(size: 12)) - Text("Add a comment") + Text("comments.composer.title") .font(.ibmPlexSans(.medium, size: 12)) } TextField( - "Words of wisdom", + String(localized: "comments.composer.placeholder"), text: $state.text ) .textFieldStyle(.roundedBorder) diff --git a/ios/HackerNews/Comments/CommentRow.swift b/ios/HackerNews/Comments/CommentRow.swift index 50c04f96..5af47a9d 100644 --- a/ios/HackerNews/Comments/CommentRow.swift +++ b/ios/HackerNews/Comments/CommentRow.swift @@ -57,10 +57,10 @@ struct CommentRow: View { .clipShape(Capsule()) Menu { - Button("Report Comment") { + Button(String(localized: "comments.action.report")) { flagComment(state) } - Button(state.hidden ? "Show" : "Collapse") { + Button(state.hidden ? String(localized: "comments.action.show") : String(localized: "comments.action.collapse")) { toggleComment() } } label: { diff --git a/ios/HackerNews/Comments/CommentsHeader.swift b/ios/HackerNews/Comments/CommentsHeader.swift index 683e0b4d..c0909164 100644 --- a/ios/HackerNews/Comments/CommentsHeader.swift +++ b/ios/HackerNews/Comments/CommentsHeader.swift @@ -64,7 +64,7 @@ struct CommentsHeader: View { .clipShape(Capsule()) Menu { - Button("Report Post", action: flagPost) + Button(String(localized: "post.action.report"), action: flagPost) } label: { Image(systemName: "ellipsis") .font(.system(size: 12)) diff --git a/ios/HackerNews/Feed/FeedScreen.swift b/ios/HackerNews/Feed/FeedScreen.swift index e246ab75..ba445a73 100644 --- a/ios/HackerNews/Feed/FeedScreen.swift +++ b/ios/HackerNews/Feed/FeedScreen.swift @@ -93,7 +93,7 @@ private struct FeedListView: View { model.toggleBookmark(content) } label: { Label( - content.bookmarked ? "Remove Bookmark" : "Bookmark", + content.bookmarked ? String(localized: "bookmarks.action.remove") : String(localized: "bookmarks.action.bookmark"), systemImage: content.bookmarked ? "book.fill" : "book" ) } diff --git a/ios/HackerNews/Localizable.xcstrings b/ios/HackerNews/Localizable.xcstrings new file mode 100644 index 00000000..8b137df1 --- /dev/null +++ b/ios/HackerNews/Localizable.xcstrings @@ -0,0 +1,569 @@ +{ + "sourceLanguage" : "en", + "strings" : { + "" : { + + }, + "@%@" : { + + }, + "@humdinger" : { + + }, + "%lld" : { + + }, + "2h ago" : { + + }, + "45" : { + + }, + "99" : { + + }, + "auth.agreement.guidelines" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hacker News Guidelines" + } + } + } + }, + "auth.agreement.prefix" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "By signing in, you agree to the " + } + } + } + }, + "auth.button.login" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Login" + } + } + } + }, + "auth.button.logout" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Logout" + } + } + } + }, + "auth.button.submit" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Submit" + } + } + } + }, + "auth.error.invalidCredentials" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Invalid username or password" + } + } + } + }, + "auth.field.password" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Password" + } + } + } + }, + "auth.field.username" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Username" + } + } + } + }, + "bookmarks.action.bookmark" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bookmark" + } + } + } + }, + "bookmarks.action.remove" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Remove Bookmark" + } + } + } + }, + "bookmarks.emptyState" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Long-press a story to bookmark it." + } + } + } + }, + "bookmarks.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bookmarks" + } + } + } + }, + "comments.action.collapse" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Collapse" + } + } + } + }, + "comments.action.report" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Report Comment" + } + } + } + }, + "comments.action.show" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Show" + } + } + } + }, + "comments.composer.placeholder" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Words of wisdom" + } + } + } + }, + "comments.composer.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add a comment" + } + } + } + }, + "feed.type.ask" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ask" + } + } + } + }, + "feed.type.best" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Best" + } + } + } + }, + "feed.type.new" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "New" + } + } + } + }, + "feed.type.show" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Show" + } + } + } + }, + "feed.type.top" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Top" + } + } + } + }, + "feedback.button.submit" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Submit" + } + } + } + }, + "feedback.field.email" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email" + } + } + } + }, + "feedback.field.name" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Name" + } + } + } + }, + "feedback.section.yourFeedback" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Your Feedback" + } + } + } + }, + "feedback.section.yourInfo" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Your Info (optional)" + } + } + } + }, + "feedback.success" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Thank you for your feedback!" + } + } + } + }, + "feedback.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Send Feedback" + } + } + } + }, + "post.action.report" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Report Post" + } + } + } + }, + "settings.commentFontSize" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Comment Font Size (%@pt)" + } + } + } + }, + "settings.row.checkForUpdates" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Check for Updates" + } + } + } + }, + "settings.row.followEmerge" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Follow Emerge" + } + } + } + }, + "settings.row.followSupergooey" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Follow Supergooey" + } + } + } + }, + "settings.row.fontFamily" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Font Family" + } + } + } + }, + "settings.row.fontStyle" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Font Style" + } + } + } + }, + "settings.row.privacyPolicy" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Privacy Policy" + } + } + } + }, + "settings.row.sendFeedback" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Send Feedback" + } + } + } + }, + "settings.section.about" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "About" + } + } + } + }, + "settings.section.appearance" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Appearance" + } + } + } + }, + "settings.section.profile" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Profile" + } + } + } + }, + "settings.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Settings" + } + } + } + }, + "settings.titleFontSize" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Title Font Size (%@pt)" + } + } + } + }, + "Some Short Title" : { + + }, + "theme.fontFamily.ibmPlex" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "IBM Plex" + } + } + } + }, + "theme.fontFamily.system" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "System" + } + } + } + }, + "theme.fontStyle.sans" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sans" + } + } + } + }, + "theme.fontStyle.sansMono" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sans + Mono" + } + } + } + }, + "web.action.openInBrowser" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open in browser" + } + } + } + }, + "web.action.share" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Share" + } + } + } + } + }, + "version" : "1.1" +} \ No newline at end of file diff --git a/ios/HackerNews/Settings/SendFeedbackScreen.swift b/ios/HackerNews/Settings/SendFeedbackScreen.swift index f67f6acc..ac25eac8 100644 --- a/ios/HackerNews/Settings/SendFeedbackScreen.swift +++ b/ios/HackerNews/Settings/SendFeedbackScreen.swift @@ -19,15 +19,15 @@ struct SendFeedbackScreen: View { var body: some View { NavigationStack { Form { - Section("Your Info (optional)") { - TextField("Name", text: $name) - TextField("Email", text: $email) + Section(String(localized: "feedback.section.yourInfo")) { + TextField(String(localized: "feedback.field.name"), text: $name) + TextField(String(localized: "feedback.field.email"), text: $email) .keyboardType(.emailAddress) .textContentType(.emailAddress) .autocapitalization(.none) } - Section("Your Feedback") { + Section(String(localized: "feedback.section.yourFeedback")) { TextEditor(text: $message) .frame(minHeight: 150) } @@ -35,7 +35,7 @@ struct SendFeedbackScreen: View { if isSubmitted { Section { Label( - "Thank you for your feedback!", + String(localized: "feedback.success"), systemImage: "checkmark.seal.fill" ) .foregroundColor(.green) @@ -44,7 +44,7 @@ struct SendFeedbackScreen: View { } } } - .navigationTitle("Send Feedback") + .navigationTitle(String(localized: "feedback.title")) .navigationBarTitleDisplayMode(.inline) .animation(.spring(), value: isSubmitted) .toolbar { @@ -62,7 +62,7 @@ struct SendFeedbackScreen: View { } .safeAreaInset(edge: .bottom) { Button(action: { sendFeedback() }) { - Text("Submit") + Text("feedback.button.submit") .font(.ibmPlexMono(.bold, size: 16)) .frame(maxWidth: .infinity) .frame(height: 40) diff --git a/ios/HackerNews/Settings/SettingsScreen.swift b/ios/HackerNews/Settings/SettingsScreen.swift index 4d8e166c..ed053887 100644 --- a/ios/HackerNews/Settings/SettingsScreen.swift +++ b/ios/HackerNews/Settings/SettingsScreen.swift @@ -19,7 +19,7 @@ struct SettingsScreen: View { ScrollView { LazyVStack(spacing: 8) { VStack(alignment: .leading, spacing: 4) { - Text("Profile") + Text("settings.section.profile") .font(theme.themedFont(size: 12, style: .sans, weight: .medium)) LoginRow(loggedIn: model.authState == AuthState.loggedIn) { model.gotoLogin() @@ -27,10 +27,10 @@ struct SettingsScreen: View { } VStack(alignment: .leading, spacing: 4) { - Text("About") + Text("settings.section.about") .font(theme.themedFont(size: 12, style: .sans, weight: .medium)) SettingsRow( - text: "Follow Emerge", + text: String(localized: "settings.row.followEmerge"), leadingIcon: { Image(systemName: "bird.fill") .font(.system(size: 12)) @@ -50,7 +50,7 @@ struct SettingsScreen: View { ) SettingsRow( - text: "Follow Supergooey", + text: String(localized: "settings.row.followSupergooey"), leadingIcon: { Image(systemName: "bird.fill") .font(.system(size: 12)) @@ -70,7 +70,7 @@ struct SettingsScreen: View { #if ADHOC SettingsRow( - text: "Check for Updates", + text: String(localized: "settings.row.checkForUpdates"), leadingIcon: { Image(systemName: "icloud.and.arrow.down") .font(.system(size: 12)) @@ -89,7 +89,7 @@ struct SettingsScreen: View { #endif SettingsRow( - text: "Send Feedback", + text: String(localized: "settings.row.sendFeedback"), leadingIcon: { Image(systemName: "exclamationmark.triangle.fill") .font(.system(size: 12)) @@ -107,7 +107,7 @@ struct SettingsScreen: View { ) SettingsRow( - text: "Privacy Policy", + text: String(localized: "settings.row.privacyPolicy"), leadingIcon: { Image(systemName: "lock.fill") .font(.system(size: 12)) @@ -131,11 +131,11 @@ struct SettingsScreen: View { VStack(alignment: .leading, spacing: 4) { @Bindable var theme = theme - Text("Appearance") + Text("settings.section.appearance") .font(.ibmPlexSans(.medium, size: 12)) SettingsRow( - text: "Font Family", + text: String(localized: "settings.row.fontFamily"), leadingIcon: { Image(systemName: "textformat") .font(.system(size: 12)) @@ -143,10 +143,10 @@ struct SettingsScreen: View { }, trailingIcon: { Menu { - Button("System") { + Button(String(localized: "theme.fontFamily.system")) { theme.fontFamilyPreference = .system } - Button("IBM Plex") { + Button(String(localized: "theme.fontFamily.ibmPlex")) { theme.fontFamilyPreference = .ibmPlex } } label: { @@ -165,7 +165,7 @@ struct SettingsScreen: View { ) SettingsRow( - text: "Font Style", + text: String(localized: "settings.row.fontStyle"), leadingIcon: { Image(systemName: "textformat") .font(.system(size: 12)) @@ -173,10 +173,10 @@ struct SettingsScreen: View { }, trailingIcon: { Menu { - Button("Sans") { + Button(String(localized: "theme.fontStyle.sans")) { theme.fontStylePreference = .sans } - Button("Sans + Mono") { + Button(String(localized: "theme.fontStyle.sansMono")) { theme.fontStylePreference = .sansAndMono } } label: { @@ -195,8 +195,7 @@ struct SettingsScreen: View { ) SettingsRow( - text: - "Comment Font Size (\(String(format: "%.1f", theme.commentFontSize))pt)", + text: String(localized: "settings.commentFontSize", defaultValue: "Comment Font Size (\(String(format: "%.1f", theme.commentFontSize))pt)"), leadingIcon: { Image(systemName: "text.bubble") .font(.system(size: 12)) @@ -216,8 +215,7 @@ struct SettingsScreen: View { .animation(.smooth, value: theme.commentFontSize) SettingsRow( - text: - "Title Font Size (\(String(format: "%.1f", theme.titleFontSize))pt)", + text: String(localized: "settings.titleFontSize", defaultValue: "Title Font Size (\(String(format: "%.1f", theme.titleFontSize))pt)"), leadingIcon: { Image(systemName: "text.alignleft") .font(.system(size: 12)) @@ -245,7 +243,7 @@ struct SettingsScreen: View { .background(.ultraThinMaterial) .containerShape(.rect(cornerRadius: 24, style: .continuous)) - Text("Settings") + Text("settings.title") .font(.ibmPlexMono(.bold, size: 24)) .padding(.horizontal, 16) } diff --git a/ios/HackerNews/Web/WebView.swift b/ios/HackerNews/Web/WebView.swift index f58cdeab..1527c7d4 100644 --- a/ios/HackerNews/Web/WebView.swift +++ b/ios/HackerNews/Web/WebView.swift @@ -59,10 +59,10 @@ struct WebViewContainer: View { Button { openURL(self.model.url) } label: { - Label("Open in browser", systemImage: "safari") + Label(String(localized: "web.action.openInBrowser"), systemImage: "safari") } ShareLink(item: self.model.url) { - Label("Share", systemImage: "square.and.arrow.up") + Label(String(localized: "web.action.share"), systemImage: "square.and.arrow.up") } } label: { Image(systemName: "ellipsis") diff --git a/ios/Packages/Common/Sources/Common/Feed/FeedType.swift b/ios/Packages/Common/Sources/Common/Feed/FeedType.swift index 79ae3bc9..81869389 100644 --- a/ios/Packages/Common/Sources/Common/Feed/FeedType.swift +++ b/ios/Packages/Common/Sources/Common/Feed/FeedType.swift @@ -15,15 +15,15 @@ public enum FeedType: CaseIterable { public var title: String { switch self { case .top: - return "Top" + return String(localized: "feed.type.top", bundle: .main) case .new: - return "New" + return String(localized: "feed.type.new", bundle: .main) case .best: - return "Best" + return String(localized: "feed.type.best", bundle: .main) case .ask: - return "Ask" + return String(localized: "feed.type.ask", bundle: .main) case .show: - return "Show" + return String(localized: "feed.type.show", bundle: .main) } } } diff --git a/ios/Packages/Common/Sources/Common/Utils/Theme.swift b/ios/Packages/Common/Sources/Common/Utils/Theme.swift index 7cbe0dcf..4352516a 100644 --- a/ios/Packages/Common/Sources/Common/Utils/Theme.swift +++ b/ios/Packages/Common/Sources/Common/Utils/Theme.swift @@ -18,9 +18,9 @@ public enum FontStylePreference: String { public var displayName: String { switch self { case .sans: - "Sans" + String(localized: "theme.fontStyle.sans", bundle: .main) case .sansAndMono: - "Sans + Mono" + String(localized: "theme.fontStyle.sansMono", bundle: .main) } } } @@ -32,9 +32,9 @@ public enum FontFamilyPreference: String { public var displayName: String { switch self { case .system: - "System" + String(localized: "theme.fontFamily.system", bundle: .main) case .ibmPlex: - "IBM Plex" + String(localized: "theme.fontFamily.ibmPlex", bundle: .main) } }