Skip to content
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

[iOS] Add metric for primary language #23602

Merged
merged 1 commit into from
May 14, 2024
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
2 changes: 2 additions & 0 deletions ios/brave-ios/App/iOS/Delegates/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
)
}

LanguageMetrics.recordPrimaryLanguageP3A()

Task(priority: .low) {
await self.cleanUpLargeTemporaryDirectory()
}
Expand Down
1 change: 1 addition & 0 deletions ios/brave-ios/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ var package = Package(
name: "Growth",
dependencies: [
"BraveVPN", "Shared", "BraveShared", "Strings", "SnapKit", "CertificateUtilities",
.product(name: "OrderedCollections", package: "swift-collections"),
],
plugins: ["LoggerPlugin"]
),
Expand Down
225 changes: 225 additions & 0 deletions ios/brave-ios/Sources/Growth/LanguageMetrics.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
// Copyright (c) 2024 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

import BraveCore
import Foundation
import OrderedCollections

public class LanguageMetrics {

// This list is copied from //brave/components/misc_metrics/language_metrics.cc
static let acceptedLanguages: OrderedSet<String> = [
"aa", // Afar
"ab", // Abkhazian
"ae", // Avestan
"af", // Afrikaans
"ak", // Akan
"am", // Amharic
"an", // Aragonese
"ar", // Arabic
"as", // Assamese
"av", // Avaric
"ay", // Aymara
"az", // Azerbaijani
"ba", // Bashkir
"be", // Belarusian
"bg", // Bulgarian
"bh", // Bihari languages
"bi", // Bislama
"bm", // Bambara
"bn", // Bengali
"bo", // Tibetan
"br", // Breton
"bs", // Bosnian
"ca", // Catalan; Valencian
"ce", // Chechen
"ch", // Chamorro
"co", // Corsican
"cr", // Cree
"cs", // Czech
"cu", // Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; // Old Church Slavonic
"cv", // Chuvash
"cy", // Welsh
"da", // Danish
"de", // German
"dv", // Divehi; Dhivehi; Maldivian
"dz", // Dzongkha
"ee", // Ewe
"el", // "Greek, Modern (1453-)"
"en", // English
"eo", // Esperanto
"es", // Spanish; Castilian
"et", // Estonian
"eu", // Basque
"fa", // Persian
"ff", // Fulah
"fi", // Finnish
"fj", // Fijian
"fo", // Faroese
"fr", // French
"fy", // Western Frisian
"ga", // Irish
"gd", // Gaelic; Scottish Gaelic
"gl", // Galician
"gn", // Guarani
"gu", // Gujarati
"gv", // Manx
"ha", // Hausa
"he", // Hebrew
"hi", // Hindi
"ho", // Hiri Motu
"hr", // Croatian
"ht", // Haitian; Haitian Creole
"hu", // Hungarian
"hy", // Armenian
"hz", // Herero
"ia", // Interlingua (International Auxiliary Language Association)
"id", // Indonesian
"ie", // Interlingue; Occidental
"ig", // Igbo
"ii", // Sichuan Yi; Nuosu
"ik", // Inupiaq
"io", // Ido
"is", // Icelandic
"it", // Italian
"iu", // Inuktitut
"ja", // Japanese
"jv", // Javanese
"ka", // Georgian
"kg", // Kongo
"ki", // Kikuyu; Gikuyu
"kj", // Kuanyama; Kwanyama
"kk", // Kazakh
"kl", // Kalaallisut; Greenlandic
"km", // Central Khmer
"kn", // Kannada
"ko", // Korean
"kr", // Kanuri
"ks", // Kashmiri
"ku", // Kurdish
"kv", // Komi
"kw", // Cornish
"ky", // Kirghiz; Kyrgyz
"la", // Latin
"lb", // Luxembourgish; Letzeburgesch
"lg", // Ganda
"li", // Limburgan; Limburger; Limburgish
"ln", // Lingala
"lo", // Lao
"lt", // Lithuanian
"lu", // Luba-Katanga
"lv", // Latvian
"mg", // Malagasy
"mh", // Marshallese
"mi", // Maori
"mk", // Macedonian
"ml", // Malayalam
"mn", // Mongolian
"mr", // Marathi
"ms", // Malay
"mt", // Maltese
"my", // Burmese
"na", // Nauru
"nb", // "Bokmål, Norwegian; Norwegian Bokmål"
"nd", // "Ndebele, North; North Ndebele"
"ne", // Nepali
"ng", // Ndonga
"nl", // Dutch; Flemish
"nn", // "Norwegian Nynorsk; Nynorsk, Norwegian"
"no", // Norwegian
"nr", // "Ndebele, South; South Ndebele"
"nv", // Navajo; Navaho
"ny", // Chichewa; Chewa; Nyanja
"oc", // Occitan (post 1500)
"oj", // Ojibwa
"om", // Oromo
"or", // Oriya
"os", // Ossetian; Ossetic
"pa", // Panjabi; Punjabi
"pi", // Pali
"pl", // Polish
"ps", // Pushto; Pashto
"pt", // Portuguese
"qu", // Quechua
"rm", // Romansh
"rn", // Rundi
"ro", // Romanian; Moldavian; Moldovan
"ru", // Russian
"rw", // Kinyarwanda
"sa", // Sanskrit
"sc", // Sardinian
"sd", // Sindhi
"se", // Northern Sami
"sg", // Sango
"si", // Sinhala; Sinhalese
"sk", // Slovak
"sl", // Slovenian
"sm", // Samoan
"sn", // Shona
"so", // Somali
"sq", // Albanian
"sr", // Serbian
"ss", // Swati
"st", // "Sotho, Southern"
"su", // Sundanese
"sv", // Swedish
"sw", // Swahili
"ta", // Tamil
"te", // Telugu
"tg", // Tajik
"th", // Thai
"ti", // Tigrinya
"tk", // Turkmen
"tl", // Tagalog
"tn", // Tswana
"to", // Tonga (Tonga Islands)
"tr", // Turkish
"ts", // Tsonga
"tt", // Tatar
"tw", // Twi
"ty", // Tahitian
"ug", // Uighur; Uyghur
"uk", // Ukrainian
"ur", // Urdu
"uz", // Uzbek
"ve", // Venda
"vi", // Vietnamese
"vo", // Volapük
"wa", // Walloon
"wo", // Wolof
"xh", // Xhosa
"yi", // Yiddish
"yo", // Yoruba
"za", // Zhuang; Chuang
"zh", // Chinese
"zu", // Zulu
]

static let languageSynonyms: [String: String] = [
"in": "id",
"iw": "he",
"ji": "yi",
"jw": "jv",
"mo": "ro",
]

static func answerForLangaugeCode(_ languageCode: String?) -> Int {
let suspendedMetricValue = Int.max - 1
guard let languageCode = languageCode,
case let primaryLanguage = languageSynonyms[languageCode, default: languageCode],
let answer = acceptedLanguages.firstIndex(of: primaryLanguage)
else {
// Suspend metric if primary language not detected or language isn't accepted
return suspendedMetricValue
}
return answer
}

public static func recordPrimaryLanguageP3A() {
let primaryLanguageHistogramName = "Brave.Core.PrimaryLang"
let answer = answerForLangaugeCode(Locale.current.languageCode)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it work correctly for longer language codes like pt_BR pt_PT?
Is it a gap we should discuss?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The language code for those would both be pt, the extras (BR/PT) are the region code

UmaHistogramExactLinear(primaryLanguageHistogramName, answer, acceptedLanguages.count)
}
}
29 changes: 29 additions & 0 deletions ios/brave-ios/Tests/GrowthTests/LangaugeMetricsTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) 2024 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

import Foundation
import XCTest

@testable import Growth

class LanguageMetricsTests: XCTestCase {
func testInvalidLanguageCodes() {
let expectedValue = Int.max - 1
XCTAssertEqual(LanguageMetrics.answerForLangaugeCode(nil), expectedValue)
XCTAssertEqual(LanguageMetrics.answerForLangaugeCode("notalangugage"), expectedValue)
}

func testValidLanguageCodes() {
for (index, languageCode) in LanguageMetrics.acceptedLanguages.enumerated() {
XCTAssertEqual(LanguageMetrics.answerForLangaugeCode(languageCode), index)
}
}

func testLanguageSynonyms() {
let (deprecated, active) = ("in", "id")
let expectedAnswer = LanguageMetrics.answerForLangaugeCode(active)
XCTAssertEqual(LanguageMetrics.answerForLangaugeCode(deprecated), expectedAnswer)
}
}
Loading