diff --git a/Osushi.xcodeproj/project.pbxproj b/Osushi.xcodeproj/project.pbxproj index 9b63195..1ab1e31 100644 --- a/Osushi.xcodeproj/project.pbxproj +++ b/Osushi.xcodeproj/project.pbxproj @@ -36,6 +36,8 @@ 3F91F1682BBA88E1008EC967 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3F91F1672BBA88E1008EC967 /* Preview Assets.xcassets */; }; 3F91F17C2BBA88E1008EC967 /* OsushiUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F91F17B2BBA88E1008EC967 /* OsushiUITests.swift */; }; 3F91F17E2BBA88E1008EC967 /* OsushiUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F91F17D2BBA88E1008EC967 /* OsushiUITestsLaunchTests.swift */; }; + 3FC7CE6F2CA80AF90058BFB0 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 3FC7CE6E2CA80AF90058BFB0 /* Localizable.xcstrings */; }; + 3FC7CE722CA80B590058BFB0 /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FC7CE712CA80B590058BFB0 /* Strings.swift */; }; 3FF9231D2BBA8AF000092F07 /* MarkdownUI in Frameworks */ = {isa = PBXBuildFile; productRef = 3FF9231C2BBA8AF000092F07 /* MarkdownUI */; }; /* End PBXBuildFile section */ @@ -89,6 +91,8 @@ 3F91F1772BBA88E1008EC967 /* OsushiUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OsushiUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3F91F17B2BBA88E1008EC967 /* OsushiUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OsushiUITests.swift; sourceTree = ""; }; 3F91F17D2BBA88E1008EC967 /* OsushiUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OsushiUITestsLaunchTests.swift; sourceTree = ""; }; + 3FC7CE6E2CA80AF90058BFB0 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = ""; }; + 3FC7CE712CA80B590058BFB0 /* Strings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -211,6 +215,7 @@ 3F6891292BBAF473003E7982 /* Model */, 3F91F1642BBA88E1008EC967 /* Assets.xcassets */, 3F91F1662BBA88E1008EC967 /* Preview Content */, + 3FC7CE702CA80B480058BFB0 /* Resources */, ); path = Osushi; sourceTree = ""; @@ -241,6 +246,15 @@ path = OsushiUITests; sourceTree = ""; }; + 3FC7CE702CA80B480058BFB0 /* Resources */ = { + isa = PBXGroup; + children = ( + 3FC7CE712CA80B590058BFB0 /* Strings.swift */, + 3FC7CE6E2CA80AF90058BFB0 /* Localizable.xcstrings */, + ); + path = Resources; + sourceTree = ""; + }; 3FF9231B2BBA8AF000092F07 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -373,6 +387,7 @@ files = ( 3F91F1682BBA88E1008EC967 /* Preview Assets.xcassets in Resources */, 3F91F1652BBA88E1008EC967 /* Assets.xcassets in Resources */, + 3FC7CE6F2CA80AF90058BFB0 /* Localizable.xcstrings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -429,6 +444,7 @@ 3F68911D2BBAF45A003E7982 /* ProfileDetailView.swift in Sources */, 3F6891392BBAF516003E7982 /* PostRowView.swift in Sources */, 3F91F1632BBA88DE008EC967 /* ContentView.swift in Sources */, + 3FC7CE722CA80B590058BFB0 /* Strings.swift in Sources */, 3F91F1612BBA88DE008EC967 /* OsushiApp.swift in Sources */, 3F68912D2BBAF473003E7982 /* Profile.swift in Sources */, 3F68911F2BBAF45A003E7982 /* StaffListView.swift in Sources */, @@ -539,6 +555,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; @@ -596,6 +613,7 @@ MTL_FAST_MATH = YES; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_EMIT_LOC_STRINGS = YES; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/Osushi/Model/APIModelData.swift b/Osushi/Model/APIModelData.swift index 523ea52..d7f8348 100644 --- a/Osushi/Model/APIModelData.swift +++ b/Osushi/Model/APIModelData.swift @@ -2,7 +2,7 @@ import Foundation final class APIModelData: ObservableObject { @Published var markdownContent: [String] = [] - @Published var errorMessage: String = "不明なエラー" + @Published var errorMessage: String = Strings.Other.unknown private var lastFetchDate: Date? private let fetchThresholdSeconds: TimeInterval = 3600 // 1hour diff --git a/Osushi/Resources/Localizable.xcstrings b/Osushi/Resources/Localizable.xcstrings new file mode 100644 index 0000000..078198a --- /dev/null +++ b/Osushi/Resources/Localizable.xcstrings @@ -0,0 +1,85 @@ +{ + "sourceLanguage" : "ja", + "strings" : { + "GitHub" : { + + }, + "iOS Osushi" : { + + }, + "iOS Osushi🍣" : { + + }, + "MarkdownUI" : { + + }, + "X" : { + + }, + "お気に入り" : { + + }, + "お気に入りボタン" : { + + }, + "お気に入りボタンの説明" : { + "extractionState" : "manual", + "localizations" : { + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "この記事をお気に入りすることができます🍣\nお気に入りした記事は下のタブから確認することができます!" + } + } + } + }, + "お気に入りリストが空の場合のメッセージ" : { + "localizations" : { + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "お気に入りボタンをタップして追加してみよう🍣" + } + } + } + }, + "お気に入り一覧" : { + + }, + "コミュニティの説明" : { + "localizations" : { + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "iOS Osushi は、iOS 関連のニュースを定期的に配信するサイトです。" + } + } + } + }, + "バージョン" : { + + }, + "ホーム" : { + + }, + "ライセンス" : { + + }, + "不明" : { + + }, + "投稿一覧" : { + + }, + "詳細情報" : { + + }, + "運営" : { + + }, + "運営メンバー" : { + + } + }, + "version" : "1.0" +} \ No newline at end of file diff --git a/Osushi/Resources/Strings.swift b/Osushi/Resources/Strings.swift new file mode 100644 index 0000000..b976a50 --- /dev/null +++ b/Osushi/Resources/Strings.swift @@ -0,0 +1,36 @@ +struct Strings { + struct Home { + static let home = String(localized: "ホーム") + static let favorite = String(localized: "お気に入り") + static let iosOsushi = String(localized: "iOS Osushi") + } + + struct PostList { + static let title = String(localized: "投稿一覧") + static let tipsTitle = String(localized: "お気に入りボタン") + static let tipsMessage = String(localized: "お気に入りボタンの説明") + static let errorMessage = String(localized: "詳細情報") + } + + + struct FavoriteList { + static let title = String(localized: "お気に入り一覧") + static let emptyListTitle = String(localized: "お気に入り一覧") + static let emptyListMessage = String(localized: "お気に入りリストが空の場合のメッセージ") + } + + struct Infomation { + static let title = String(localized: "iOS Osushi🍣") + static let management = String(localized: "運営") + static let license = String(localized: "ライセンス") + static let version = String(localized: "バージョン") + static let description = String(localized: "コミュニティの説明") + static let staffListTitle = String(localized: "運営メンバー") + static let x = String(localized: "X") + static let gitHub = String(localized: "GitHub") + } + + struct Other { + static let unknown = String(localized: "不明") + } +} diff --git a/Osushi/View/ContentView.swift b/Osushi/View/ContentView.swift index f09f1b3..e3981d0 100644 --- a/Osushi/View/ContentView.swift +++ b/Osushi/View/ContentView.swift @@ -13,20 +13,20 @@ struct ContentView: View { TabView(selection: $selection) { PostListView() .tabItem { - Label("ホーム", systemImage: "house") + Label(Strings.Home.home, systemImage: "house") } .tag(Tab.top) FavoriteListView() .modelContainer(for: Favorite.self) .tabItem { - Label("お気に入り", systemImage: "star") + Label(Strings.Home.favorite, image: "star") } .tag(Tab.favorite) InfoListView() .tabItem { - Label("iOS Osushi", image: .tabOsushi) + Label(Strings.Home.iosOsushi, image: .tabOsushi) }.tag(Tab.setting) } } diff --git a/Osushi/View/FavoriteList/FavoriteListView.swift b/Osushi/View/FavoriteList/FavoriteListView.swift index 895f76c..f4c3ff2 100644 --- a/Osushi/View/FavoriteList/FavoriteListView.swift +++ b/Osushi/View/FavoriteList/FavoriteListView.swift @@ -22,13 +22,13 @@ struct FavoriteListView: View { } } } - .navigationTitle("お気に入り一覧") + .navigationTitle(Strings.FavoriteList.title) .overlay { if favoritePosts.isEmpty { ContentUnavailableView { - Label("お気に入りがありません", systemImage: "tray.fill") + Label(Strings.FavoriteList.emptyListTitle, systemImage: "tray.fill") } description: { - Text("お気に入りボタンをタップして追加してみよう🍣") + Text(Strings.FavoriteList.emptyListMessage) } } } diff --git a/Osushi/View/InfomationList/CommunityView.swift b/Osushi/View/InfomationList/CommunityView.swift index b9d9582..38dd6cb 100644 --- a/Osushi/View/InfomationList/CommunityView.swift +++ b/Osushi/View/InfomationList/CommunityView.swift @@ -22,7 +22,7 @@ struct CommunityView: View { Spacer() } - Text("iOS Osushiは、iOS関連のニュースを定期的に配信するサイトです。") + Text(Strings.Infomation.description) } } diff --git a/Osushi/View/InfomationList/InfoListView.swift b/Osushi/View/InfomationList/InfoListView.swift index c42cfa8..3c5eeb5 100644 --- a/Osushi/View/InfomationList/InfoListView.swift +++ b/Osushi/View/InfomationList/InfoListView.swift @@ -18,19 +18,19 @@ struct InfoListView: View { } Section { - NavigationLink("運営") { + NavigationLink(Strings.Infomation.management) { StaffListView(profiles: InformationListViewModel.profiles) } - NavigationLink("ライセンス") { + NavigationLink(Strings.Infomation.license) { LisenceListView() } } Section { - LabeledContent("バージョン", value: viewModel.versionString) + LabeledContent(Strings.Infomation.version, value: viewModel.versionString) } } - .navigationTitle("iOS Osushi🍣") + .navigationTitle(Strings.Infomation.title) } } } diff --git a/Osushi/View/InfomationList/InformationListViewModel.swift b/Osushi/View/InfomationList/InformationListViewModel.swift index a47602f..ad19dba 100644 --- a/Osushi/View/InfomationList/InformationListViewModel.swift +++ b/Osushi/View/InfomationList/InformationListViewModel.swift @@ -20,6 +20,6 @@ final class InformationListViewModel { } private func makeVersionString(forInfoDictionaryKey key: String) -> String { - Bundle.main.object(forInfoDictionaryKey: key) as? String ?? "不明" + Bundle.main.object(forInfoDictionaryKey: key) as? String ?? Strings.Other.unknown } } diff --git a/Osushi/View/InfomationList/Lisence/LisenceListView.swift b/Osushi/View/InfomationList/Lisence/LisenceListView.swift index da899a2..1b5d043 100644 --- a/Osushi/View/InfomationList/Lisence/LisenceListView.swift +++ b/Osushi/View/InfomationList/Lisence/LisenceListView.swift @@ -36,7 +36,7 @@ SOFTWARE. ) ) } - .navigationTitle("ライセンス") + .navigationTitle(Strings.Infomation.license) } } } diff --git a/Osushi/View/InfomationList/SNSView.swift b/Osushi/View/InfomationList/SNSView.swift index a5bf08a..d396a15 100644 --- a/Osushi/View/InfomationList/SNSView.swift +++ b/Osushi/View/InfomationList/SNSView.swift @@ -5,7 +5,7 @@ struct SNSView: View { let gitHubUrlString: String var body: some View { - Link("X", destination: URL(string: xUrlString)!) - Link("GitHub", destination: URL(string: gitHubUrlString)!) + Link(Strings.Infomation.x, destination: URL(string: xUrlString)!) + Link(Strings.Infomation.gitHub, destination: URL(string: gitHubUrlString)!) } } diff --git a/Osushi/View/InfomationList/Staff/ProfileDetailView.swift b/Osushi/View/InfomationList/Staff/ProfileDetailView.swift index 73dd02d..ba650ff 100644 --- a/Osushi/View/InfomationList/Staff/ProfileDetailView.swift +++ b/Osushi/View/InfomationList/Staff/ProfileDetailView.swift @@ -15,14 +15,14 @@ struct ProfileDetailView: View { HStack { Link( - "X", + Strings.Infomation.x, destination: URL( string: "https://twitter.com/\(profile.x)" )! ) Link( - "GitHub", + Strings.Infomation.gitHub, destination: URL( string: "https://github.com/\(profile.gitHub)" )! diff --git a/Osushi/View/InfomationList/Staff/StaffListView.swift b/Osushi/View/InfomationList/Staff/StaffListView.swift index 68588cf..0bff38c 100644 --- a/Osushi/View/InfomationList/Staff/StaffListView.swift +++ b/Osushi/View/InfomationList/Staff/StaffListView.swift @@ -14,7 +14,7 @@ struct StaffListView: View { } } } - .navigationTitle("運営メンバー") + .navigationTitle(Strings.Infomation.staffListTitle) } } } diff --git a/Osushi/View/PostList/DetailPostView.swift b/Osushi/View/PostList/DetailPostView.swift index 8601b61..c30b8df 100644 --- a/Osushi/View/PostList/DetailPostView.swift +++ b/Osushi/View/PostList/DetailPostView.swift @@ -5,10 +5,10 @@ import TipKit struct FavoriteButtonTip: Tip { var title: Text { - Text("お気に入りボタン") + Text(Strings.PostList.tipsTitle) } var message: Text? { - Text("この記事をお気に入りすることができます🍣\nお気に入りした記事は下のタブから確認することができます!") + Text(Strings.PostList.tipsMessage) } } diff --git a/Osushi/View/PostList/PostListView.swift b/Osushi/View/PostList/PostListView.swift index 646988e..879de97 100644 --- a/Osushi/View/PostList/PostListView.swift +++ b/Osushi/View/PostList/PostListView.swift @@ -16,7 +16,7 @@ struct PostListView: View { } } } - .navigationTitle("投稿一覧") + .navigationTitle(Strings.PostList.title) .refreshable { viewModel.fetchPosts() } diff --git a/Osushi/View/PostList/PostListViewModel.swift b/Osushi/View/PostList/PostListViewModel.swift index d777659..7c3b58a 100644 --- a/Osushi/View/PostList/PostListViewModel.swift +++ b/Osushi/View/PostList/PostListViewModel.swift @@ -29,6 +29,6 @@ final class PostListViewModel: ObservableObject { .trimmingCharacters(in: .whitespaces) } } - return "詳細情報が見つかりません。" + return Strings.PostList.errorMessage } }