import Foundation extension WikimediaProject { private static var commonsIdentifier: String { return "commonswiki" } private static var wikidataIdentifier: String { return "wikidatawiki" } private static var mediawikiIdentifier: String { return "mediawikiwiki" } private static var wikispeciesIdentifier: String { return "specieswiki" } private static var wikipediaLanguageSuffix: String { return "wiki" } private static var wikibooksLanguageSuffix: String { return "wikibooks" } private static var wiktionaryLanguageSuffix: String { return "wiktionary" } private static var wikiquoteLanguageSuffix: String { return "wikiquote" } private static var wikimediaLanguageSuffix: String { return "wikimedia" } private static var wikisourceLanguageSuffix: String { return "wikisource" } private static var wikinewsLanguageSuffix: String { return "wikinews" } private static var wikiversityLanguageSuffix: String { return "wikiversity" } private static var wikivoyageLanguageSuffix: String { return "wikivoyage" } public var notificationsApiWikiIdentifier: String { switch self { case .wikipedia(let languageCode, _, _): return languageCode + Self.wikipediaLanguageSuffix case .commons: return Self.commonsIdentifier case .wikidata: return Self.wikidataIdentifier case .wikibooks(let languageCode, _): return languageCode + Self.wikibooksLanguageSuffix case .wiktionary(let languageCode, _): return languageCode + Self.wiktionaryLanguageSuffix case .wikiquote(let languageCode, _): return languageCode + Self.wikiquoteLanguageSuffix case .wikisource(let languageCode, _): return languageCode + Self.wikisourceLanguageSuffix case .wikinews(let languageCode, _): return languageCode + Self.wikinewsLanguageSuffix case .wikiversity(let languageCode, _): return languageCode + Self.wikiversityLanguageSuffix case .wikivoyage(let languageCode, _): return languageCode + Self.wikivoyageLanguageSuffix case .mediawiki: return Self.mediawikiIdentifier case .wikispecies: return Self.wikispeciesIdentifier } } private var projectName: String { // TODO: This would be better as a generated mapping file from translatewiki's project translations (for example: https://translatewiki.net/wiki/Special:ExportTranslations?group=ext-wikimediaprojectnames&language=he&format=export-to-file) // See https://phabricator.wikimedia.org/T297620 switch self { case .wikipedia: return CommonStrings.plainWikipediaName case .wikibooks: return WMFLocalizedString("project-name-wikibooks", value:"Wikibooks", comment: "Project name for Wikibooks.") case .wiktionary: return WMFLocalizedString("project-name-wiktionary", value:"Wiktionary", comment: "Project name for Wiktionary.") case .wikiquote: return WMFLocalizedString("project-name-wikiquote", value:"Wikiquote", comment: "Project name for Wikiquote.") case .wikisource: return WMFLocalizedString("project-name-wikisource", value:"Wikisource", comment: "Project name for Wikisource.") case .wikinews: return WMFLocalizedString("project-name-wikinews", value:"Wikinews", comment: "Project name for Wikinews.") case .wikiversity: return WMFLocalizedString("project-name-wikiversity", value:"Wikiversity", comment: "Project name for Wikiversity.") case .wikivoyage: return WMFLocalizedString("project-name-wikivoyage", value:"Wikivoyage", comment: "Project name for Wikivoyage.") case .commons: return WMFLocalizedString("project-name-wikimedia-commons", value:"Wikimedia Commons", comment: "Project name for Wikimedia Commons.") case .wikidata: return WMFLocalizedString("project-name-wikidata", value:"Wikidata", comment: "Project name for Wikidata.") case .mediawiki: return WMFLocalizedString("project-name-mediawiki", value:"MediaWiki", comment: "Project name for MediaWiki.") case .wikispecies: return WMFLocalizedString("project-name-wikispecies", value:"Wikispecies", comment: "Project name for Wikispecies.") } } /// Returns formatted descriptive project name /// - Parameters: /// - shouldReturnCodedFormat: Boolean for if you want description in coded format for langauge projects ("EN-Wikipedia" vs "English Wikipedia"). This is ignored for commons and wikidata projects. /// - Returns: Formatted descriptive project name public func projectName(shouldReturnCodedFormat: Bool) -> String { let createLanguageProjectNameBlock: (String, String, String, Bool) -> String = { (languageCode, localizedLanguageName, projectName, shouldReturnCodedFormat) in let format = WMFLocalizedString("notifications-center-language-project-name-format", value: "%1$@ %2$@", comment: "Format used for the ordering of language project name descriptions. This description is inserted into the header text of notifications in Notifications Center. For example, \"English Wikipedia\". Use this format to reorder these words if necessary or insert additional connecting words. Parameters: %1$@ = localized language name (\"English\"), %2$@ = localized name for Wikipedia (\"Wikipedia\")") if !shouldReturnCodedFormat { return String.localizedStringWithFormat(format, localizedLanguageName, projectName) } else { let codedProjectName = "\(languageCode.localizedUppercase)-\(projectName)" return codedProjectName } } switch self { case .wikipedia(let languageCode, let localizedLanguageName, _): return createLanguageProjectNameBlock(languageCode, localizedLanguageName, projectName, shouldReturnCodedFormat) case .commons: return projectName case .wikidata: return projectName case .wikibooks(let languageCode, let localizedLanguageName): return createLanguageProjectNameBlock(languageCode, localizedLanguageName, projectName, shouldReturnCodedFormat) case .wiktionary(let languageCode, let localizedLanguageName): return createLanguageProjectNameBlock(languageCode, localizedLanguageName, projectName, shouldReturnCodedFormat) case .wikiquote(let languageCode, let localizedLanguageName): return createLanguageProjectNameBlock(languageCode, localizedLanguageName, projectName, shouldReturnCodedFormat) case .wikisource(let languageCode, let localizedLanguageName): return createLanguageProjectNameBlock(languageCode, localizedLanguageName, projectName, shouldReturnCodedFormat) case .wikinews(let languageCode, let localizedLanguageName): return createLanguageProjectNameBlock(languageCode, localizedLanguageName, projectName, shouldReturnCodedFormat) case .wikiversity(let languageCode, let localizedLanguageName): return createLanguageProjectNameBlock(languageCode, localizedLanguageName, projectName, shouldReturnCodedFormat) case .wikivoyage(let languageCode, let localizedLanguageName): return createLanguageProjectNameBlock(languageCode, localizedLanguageName, projectName, shouldReturnCodedFormat) case .mediawiki: return projectName case .wikispecies: return projectName } } public var languageVariantCode: String? { switch self { case .wikipedia(_, _, let languageVariantCode): return languageVariantCode default: return nil } } func mediaWikiAPIURL(configuration: Configuration, queryParameters: RemoteNotificationsAPIController.Query.Parameters?) -> URL? { switch self { case .commons: return configuration.commonsAPIURLComponents(with: queryParameters).url case .wikidata: return configuration.wikidataAPIURLComponents(with: queryParameters).url case .wikipedia(let languageCode, _, _): return configuration.mediaWikiAPIURLForLanguageCode(languageCode, queryParameters: queryParameters).url case .wikibooks(let languageCode, _): return configuration.mediaWikiAPIURLForLanguageCode(languageCode, siteDomain: Configuration.Domain.wikibooks, queryParameters: queryParameters).url case .wiktionary(let languageCode, _): return configuration.mediaWikiAPIURLForLanguageCode(languageCode, siteDomain: Configuration.Domain.wiktionary, queryParameters: queryParameters).url case .wikiquote(let languageCode, _): return configuration.mediaWikiAPIURLForLanguageCode(languageCode, siteDomain: Configuration.Domain.wikiquote, queryParameters: queryParameters).url case .wikisource(let languageCode, _): return configuration.mediaWikiAPIURLForLanguageCode(languageCode, siteDomain: Configuration.Domain.wikisource, queryParameters: queryParameters).url case .wikinews(let languageCode, _): return configuration.mediaWikiAPIURLForLanguageCode(languageCode, siteDomain: Configuration.Domain.wikinews, queryParameters: queryParameters).url case .wikiversity(let languageCode, _): return configuration.mediaWikiAPIURLForLanguageCode(languageCode, siteDomain: Configuration.Domain.wikiversity, queryParameters: queryParameters).url case .wikivoyage(let languageCode, _): return configuration.mediaWikiAPIURLForLanguageCode(languageCode, siteDomain: Configuration.Domain.wikivoyage, queryParameters: queryParameters).url case .mediawiki: return configuration.mediaWikiAPIURLForHost(Configuration.Domain.mediaWiki, with: queryParameters).url case .wikispecies: return configuration.mediaWikiAPIURLForHost(Configuration.Domain.wikispecies, with: queryParameters).url } } private static func projectForLanguageSuffix(suffix: String, language: MWKLanguageLink?) -> WikimediaProject? { guard let language = language else { return nil } switch suffix { case Self.wikipediaLanguageSuffix: return .wikipedia(language.languageCode, language.localizedName, language.languageVariantCode) case Self.wikibooksLanguageSuffix: return .wikibooks(language.languageCode, language.localizedName) case Self.wiktionaryLanguageSuffix: return .wiktionary(language.languageCode, language.localizedName) case Self.wikiquoteLanguageSuffix: return .wikiquote(language.languageCode, language.localizedName) case Self.wikisourceLanguageSuffix: return .wikisource(language.languageCode, language.localizedName) case Self.wikinewsLanguageSuffix: return .wikinews(language.languageCode, language.localizedName) case Self.wikiversityLanguageSuffix: return .wikiversity(language.languageCode, language.localizedName) case Self.wikivoyageLanguageSuffix: return .wikivoyage(language.languageCode, language.localizedName) default: return nil } } /// Initializes WikimediaProject with wiki identifier recognize by the MediaWiki Notifications API /// - Parameters: /// - notificationsApiIdentifier: The API identifier used by the MediaWiki Notifications API. (e.g. "enwiki", "commonswiki", "wikidatawiki", etc.) /// - languageLinkController: Included to validate project against a list of languages that the app recognizes. This also associates extra metadata to language enum associated value, like localizedName and languageVariantCode. public init?(notificationsApiIdentifier: String, languageLinkController: MWKLanguageLinkController) { switch notificationsApiIdentifier { case Self.commonsIdentifier: self = .commons case Self.wikidataIdentifier: self = .wikidata case Self.wikispeciesIdentifier: self = .wikispecies case Self.mediawikiIdentifier: self = .mediawiki default: let suffixes = [Self.wikipediaLanguageSuffix, Self.wikibooksLanguageSuffix, Self.wiktionaryLanguageSuffix, Self.wikiquoteLanguageSuffix, Self.wikimediaLanguageSuffix, Self.wikisourceLanguageSuffix, Self.wikinewsLanguageSuffix, Self.wikiversityLanguageSuffix, Self.wikivoyageLanguageSuffix] var project: WikimediaProject? for suffix in suffixes { let strippedIdentifier = notificationsApiIdentifier.hasSuffix(suffix) ? String(notificationsApiIdentifier.dropLast(suffix.count)) : notificationsApiIdentifier // confirm it is a recognized language let recognizedLanguage = languageLinkController.allLanguages.first { languageLink in languageLink.languageCode == strippedIdentifier } project = Self.projectForLanguageSuffix(suffix: suffix, language: recognizedLanguage) if project != nil { break } } guard let project = project else { return nil } self = project } } }