diff --git a/codegen/src/collect_large_numbers.rs b/codegen/src/collect_large_numbers.rs new file mode 100644 index 0000000..c340b12 --- /dev/null +++ b/codegen/src/collect_large_numbers.rs @@ -0,0 +1,358 @@ +use std::collections::HashMap; +use std::{collections::BTreeMap, fs::File, io::BufReader, path::Path}; + +use anyhow::{Context, Result}; +use fancy_regex::Regex; +use futures::{stream, StreamExt}; +use once_cell::sync::Lazy; +use reqwest::{header, Client}; +use rustypipe::model::{locale::LANGUAGES, Language}; +use serde::Deserialize; +use serde_with::serde_as; +use serde_with::VecSkipError; + +use crate::util::{self, Text}; + +type CollectedNumbers = BTreeMap>; + +/// Collect video view count texts in every supported language +/// and write them to `testfiles/dict/large_number_samples.json`. +/// +/// YouTube's API outputs the subscriber count of a channel only in a +/// approximated format (e.g *880K subscribers*), which varies +/// by language. +/// +/// To parse these numbers correctly we need to collect textual numbers +/// of different orders of magnitude in every language. This script extracts +/// the view count texts from the most popular videos of different channels. +/// +/// We extract these instead of subscriber counts because the YouTube API +/// outputs view counts both in approximated and exact format, so we can use +/// the exact counts to figure out the tokens. +pub async fn collect_large_numbers(project_root: &Path, concurrency: usize) { + let mut json_path = project_root.to_path_buf(); + json_path.push("testfiles/dict/large_number_samples.json"); + + let channels = [ + "UCq-Fj5jknLsUf-MWSy4_brA", // 10e8 (225M) + "UCcdwLMPsaU2ezNSJU1nFoBQ", // 10e7 (60M) + "UC6mIxFTvXkWQVEHPsEdflzQ", // 10e6 (1.7M) + "UCD0y51PJfvkZNe3y3FR5riw", // 10e5 (125K) + "UCNcN0dW43zE0Om3278fjY8A", // 10e4 (27K) + "UC0QEucPrn0-Ddi3JBTcs5Kw", // 10e3 (5K) + "UCGiJh0NZ52wRhYKYnuZI08Q", // 10e1 (37) + ]; + + let collected_numbers: CollectedNumbers = stream::iter(LANGUAGES) + .map(|lang| async move { + let mut entry = BTreeMap::new(); + + for (n, ch_id) in channels.iter().enumerate() { + let channel = get_channel(ch_id, lang) + .await + .context(format!("{}-{}", lang, n)) + .unwrap(); + + channel.view_counts.iter().for_each(|(num, txt)| { + entry.insert(get_mag(*num), (txt.to_owned(), *num)); + }); + + println!("collected {}-{}", lang, n); + } + + (lang, entry) + }) + .buffer_unordered(concurrency) + .collect() + .await; + + let file = File::create(json_path).unwrap(); + serde_json::to_writer_pretty(file, &collected_numbers).unwrap(); +} + +/// Attempt to parse the numbers collected by `collect-large-numbers` +/// and write the results to `dictionary.json`. +pub fn write_samples_to_dict(project_root: &Path) { + let mut json_path = project_root.to_path_buf(); + json_path.push("testfiles/dict/large_number_samples.json"); + + let json_file = File::open(json_path).unwrap(); + let collected_nums: CollectedNumbers = + serde_json::from_reader(BufReader::new(json_file)).unwrap(); + let mut dict = util::read_dict(project_root); + let langs = dict.keys().map(|k| k.to_owned()).collect::>(); + + static POINT_REGEX: Lazy = Lazy::new(|| Regex::new(r"\d(\.|,)\d{1,3}(?:\D|$)").unwrap()); + + for lang in langs { + let dict_entry = dict.entry(lang).or_default(); + + let mut e_langs = dict_entry.equivalent.clone(); + e_langs.push(lang); + + let comma_decimal = collected_nums + .get(&lang) + .unwrap() + .iter() + .find_map(|(mag, (txt, _))| { + let point = POINT_REGEX + .captures(txt) + .unwrap() + .map(|c| c.get(1).unwrap().as_str()); + + if let Some(point) = point { + let num_all = util::parse_numeric::(txt).unwrap(); + // If the number parsed from all digits has the same order of + // magnitude as the actual number, it must be a separator. + // Otherwise it is a decimal point + return Some((get_mag(num_all) == *mag) ^ (point == ",")); + } + None + }) + .unwrap(); + + let decimal_point = match comma_decimal { + true => ",", + false => ".", + }; + + // Search for tokens + + // This map holds all the tokens we encounter while parsing the language + // If a new token is found, it is stored in this map with the derived order of + // magnitude. + // If the token is found again with a different derived order of magnitude, + // its value in the map is set to None. + let mut found_tokens: HashMap> = HashMap::new(); + + let mut insert_token = |token: String, mag: u8| { + let found_token = found_tokens.entry(token).or_insert(match mag { + 0 => None, + x => Some(x), + }); + + if let Some(f) = found_token { + if *f != mag { + *found_token = None; + } + } + }; + + for lang in e_langs { + let entry = collected_nums.get(&lang).unwrap(); + + entry.iter().for_each(|(mag, (txt, _))| { + let filtered = util::filter_largenumstr(txt); + + let tokens: Vec = match dict_entry.by_char { + true => filtered.chars().map(|c| c.to_string()).collect(), + false => filtered.split_whitespace().map(|c| c.to_string()).collect(), + }; + + let num_before_point = + util::parse_numeric::(txt.split(decimal_point).next().unwrap()).unwrap(); + let mag_before_point = get_mag(num_before_point); + let mut mag_remaining = mag - mag_before_point; + + tokens.iter().for_each(|t| { + // These tokens are correct in all languages + // and are used to parse combined prefixes like `1.1K crore` (en-IN) + let known_tmag: u8 = if t.len() == 1 { + match t.as_str() { + "K" | "k" => 3, + "M" => 6, + // 'm' means 10^3 in Catalan, 'B' means 10^3 in Turkish + _ => 0, + } + } else { + 0 + }; + + // K/M/B + if known_tmag > 0 { + mag_remaining = mag_remaining + .checked_sub(known_tmag) + .expect("known magnitude incorrect"); + } else { + insert_token(t.to_owned(), mag_remaining); + } + }); + }); + } + + // Insert collected data into dictionary + dict_entry.number_tokens = found_tokens + .into_iter() + .filter_map(|(k, v)| v.map(|v| (k, v))) + .collect(); + dict_entry.comma_decimal = comma_decimal; + } + + util::write_dict(project_root, &dict); +} + +fn get_mag(n: u64) -> u8 { + (n as f64).log10().floor() as u8 +} + +/* +YouTube channel videos response +*/ + +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct Channel { + contents: Contents, +} + +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct Contents { + two_column_browse_results_renderer: TabsRenderer, +} + +#[serde_as] +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct TabsRenderer { + #[serde_as(as = "VecSkipError<_>")] + tabs: Vec, +} + +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct TabRendererWrap { + tab_renderer: TabRenderer, +} + +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct TabRenderer { + content: SectionListRendererWrap, +} + +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct SectionListRendererWrap { + section_list_renderer: SectionListRenderer, +} + +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct SectionListRenderer { + contents: Vec, +} + +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct ItemSectionRendererWrap { + item_section_renderer: ItemSectionRenderer, +} + +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct ItemSectionRenderer { + contents: Vec, +} + +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct GridRendererWrap { + grid_renderer: GridRenderer, +} + +#[serde_as] +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct GridRenderer { + #[serde_as(as = "VecSkipError<_>")] + items: Vec, +} + +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct VideoListItem { + grid_video_renderer: GridVideoRenderer, +} + +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct GridVideoRenderer { + /// `24,194 views` + view_count_text: Text, + /// `19K views` + short_view_count_text: Text, +} + +#[derive(Clone, Debug)] +struct ChannelData { + view_counts: Vec<(u64, String)>, +} + +async fn get_channel(channel_id: &str, lang: Language) -> Result { + let client = Client::new(); + + let body = format!( + "{}{}{}{}{}", + r##"{"context":{"client":{"clientName":"WEB","clientVersion":"2.20220914.06.00","platform":"DESKTOP","originalUrl":"https://www.youtube.com/","hl":""##, + lang, + r##"","gl":"US"},"request":{"internalExperimentFlags":[],"useSsl":true},"user":{"lockedSafetyMode":false}},"params":"EgZ2aWRlb3MYASAAMAE%3D","browseId":""##, + channel_id, + "\"}" + ); + + let resp = client + .post("https://www.youtube.com/youtubei/v1/browse?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8&prettyPrint=false") + .header(header::CONTENT_TYPE, "application/json") + .body(body) + .send().await? + .error_for_status()?; + + let channel = resp.json::().await?; + + Ok(ChannelData { + view_counts: channel + .contents + .two_column_browse_results_renderer + .tabs + .get(0) + .map(|tab| { + tab.tab_renderer.content.section_list_renderer.contents[0] + .item_section_renderer + .contents[0] + .grid_renderer + .items + .iter() + .map(|itm| { + ( + util::parse_numeric( + &itm.grid_video_renderer.view_count_text.simple_text, + ) + .unwrap(), + itm.grid_video_renderer + .short_view_count_text + .simple_text + .to_owned(), + ) + }) + .collect() + }) + .unwrap_or_default(), + }) +} + +#[tokio::test] +async fn test() { + let channel = get_channel("UCcdwLMPsaU2ezNSJU1nFoBQ", Language::Az) + .await + .unwrap(); + + dbg!(channel); +} + +#[test] +fn test2() { + write_samples_to_dict(Path::new( + "/home/thetadev/Documents/Programmieren/Rust/rustypipe", + )); +} diff --git a/codegen/src/collect_playlist_dates.rs b/codegen/src/collect_playlist_dates.rs index 714487c..2ab6c0e 100644 --- a/codegen/src/collect_playlist_dates.rs +++ b/codegen/src/collect_playlist_dates.rs @@ -38,7 +38,7 @@ enum DateCase { } /// Collect 'Playlist updated' dates in every supported language -/// and write them to `testfiles/date/playlist_samples.json`. +/// and write them to `testfiles/dict/playlist_samples.json`. /// /// YouTube's API outputs the update date of playlists only in a /// textual format (e.g. *Last updated on Jan 3, 2020*), which varies @@ -55,13 +55,15 @@ enum DateCase { /// - one playlist updated yesterday /// - one playlist updated 2-7 days ago /// - one playlist from every month. Note that there should not -/// be any dates which include the same number twice (e.g. 01.01.2020). +/// be any dates which include the same number twice (e.g. 01.01.2020). +/// +/// **IMPORTANT:** /// /// Because the relative dates change with time, the first three playlists -/// should be checked and eventually changed before running the program. +/// have to checked and eventually changed before running the program. pub async fn collect_dates(project_root: &Path, concurrency: usize) { let mut json_path = project_root.to_path_buf(); - json_path.push("testfiles/date/playlist_samples.json"); + json_path.push("testfiles/dict/playlist_samples.json"); // These are the sample playlists let cases = [ @@ -115,7 +117,7 @@ pub async fn collect_dates(project_root: &Path, concurrency: usize) { /// parsed automatically and require manual work. pub fn write_samples_to_dict(project_root: &Path) { let mut json_path = project_root.to_path_buf(); - json_path.push("testfiles/date/playlist_samples.json"); + json_path.push("testfiles/dict/playlist_samples.json"); let json_file = File::open(json_path).unwrap(); let collected_dates: CollectedDates = diff --git a/codegen/src/download_testfiles.rs b/codegen/src/download_testfiles.rs index ef72537..13b2008 100644 --- a/codegen/src/download_testfiles.rs +++ b/codegen/src/download_testfiles.rs @@ -146,7 +146,7 @@ async fn video_details(testfiles: &Path) { async fn comments_top(testfiles: &Path) { let mut json_path = testfiles.to_path_buf(); json_path.push("video_details"); - json_path.push(format!("comments_top.json")); + json_path.push("comments_top.json"); if json_path.exists() { return; } diff --git a/codegen/src/gen_dictionary.rs b/codegen/src/gen_dictionary.rs index ae86c0f..ec94cac 100644 --- a/codegen/src/gen_dictionary.rs +++ b/codegen/src/gen_dictionary.rs @@ -34,17 +34,47 @@ pub fn generate_dictionary(project_root: &Path) { let dict = util::read_dict(project_root); let code_head = r#"// This file is automatically generated. DO NOT EDIT. +// See codegen/gen_dictionary.rs for the generation code. use crate::{ model::Language, timeago::{DateCmp, TaToken, TimeUnit}, }; +/// The dictionary contains the information required to parse dates and numbers +/// in all supported languages. pub struct Entry { + /// Should the language be parsed by character instead of by word? + /// (e.g. Chinese/Japanese) pub by_char: bool, + /// Tokens for parsing timeago strings. + /// + /// Format: Parsed token -> \[Quantity\] Identifier + /// + /// Identifiers: `Y`(ear), `M`(month), `W`(eek), `D`(ay), + /// `h`(our), `m`(inute), `s`(econd) pub timeago_tokens: phf::Map<&'static str, TaToken>, + /// Order in which to parse numeric date components. Formatted as + /// a string of date identifiers (Y, M, D). + /// + /// Examples: + /// + /// - 03.01.2020 => `"DMY"` + /// - Jan 3, 2020 => `"DY"` pub date_order: &'static [DateCmp], + /// Tokens for parsing month names. + /// + /// Format: Parsed token -> Month number (starting from 1) pub months: phf::Map<&'static str, u8>, + /// Tokens for parsing date strings with no digits (e.g. Today, Tomorrow) + /// + /// Format: Parsed token -> \[Quantity\] Identifier pub timeago_nd_tokens: phf::Map<&'static str, TaToken>, + /// Are commas (instead of points) used as decimal separators? + pub comma_decimal: bool, + /// Tokens for parsing decimal prefixes (K, M, B, ...) + /// + /// Format: Parsed token -> decimal power + pub number_tokens: phf::Map<&'static str, u8>, } "#; @@ -100,12 +130,19 @@ pub fn entry(lang: Language) -> Entry { }); date_order = date_order.trim_end_matches([' ', ',']).to_owned() + "]"; + // Number tokens + let mut number_tokens = phf_codegen::Map::<&str>::new(); + entry.number_tokens.iter().for_each(|(txt, mag)| { + number_tokens.entry(txt, &mag.to_string()); + }); + let code_ta_tokens = &ta_tokens.build().to_string().replace('\n', "\n "); let code_ta_nd_tokens = &ta_nd_tokens.build().to_string().replace('\n', "\n "); let code_months = &months.build().to_string().replace('\n', "\n "); + let code_number_tokens = &number_tokens.build().to_string().replace('\n', "\n "); - let _ = write!(code_timeago_tokens, "{} => Entry {{\n by_char: {:?},\n timeago_tokens: {},\n date_order: {},\n months: {},\n timeago_nd_tokens: {},\n }},\n ", - selector, entry.by_char, code_ta_tokens, date_order, code_months, code_ta_nd_tokens); + let _ = write!(code_timeago_tokens, "{} => Entry {{\n by_char: {:?},\n timeago_tokens: {},\n date_order: {},\n months: {},\n timeago_nd_tokens: {},\n comma_decimal: {:?},\n number_tokens: {},\n }},\n ", + selector, entry.by_char, code_ta_tokens, date_order, code_months, code_ta_nd_tokens, entry.comma_decimal, code_number_tokens); }); code_timeago_tokens = code_timeago_tokens.trim_end().to_owned() + "\n }\n}\n"; diff --git a/codegen/src/gen_locales.rs b/codegen/src/gen_locales.rs index 55094b6..5f0a279 100644 --- a/codegen/src/gen_locales.rs +++ b/codegen/src/gen_locales.rs @@ -8,6 +8,8 @@ use serde::Deserialize; use serde_with::serde_as; use serde_with::VecSkipError; +use crate::util::Text; + #[serde_as] #[derive(Clone, Debug, Deserialize)] #[serde(rename_all = "camelCase")] @@ -135,12 +137,6 @@ struct LanguageCountryCommand { hl: String, } -#[derive(Clone, Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -struct Text { - simple_text: String, -} - pub async fn generate_locales(project_root: &Path) { let (languages, countries) = get_locales().await; @@ -284,7 +280,7 @@ pub enum Country { async fn get_locales() -> (BTreeMap, BTreeMap) { let client = Client::new(); let resp = client - .post("https://www.youtube.com/youtubei/v1/account/account_menu?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8") + .post("https://www.youtube.com/youtubei/v1/account/account_menu?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8&prettyPrint=false") .header(header::CONTENT_TYPE, "application/json") .body( r##"{"context":{"client":{"clientName":"WEB","clientVersion":"2.20220914.06.00","platform":"DESKTOP","originalUrl":"https://www.youtube.com/","hl":"en","gl":"US"},"request":{"internalExperimentFlags":[],"useSsl":true},"user":{"lockedSafetyMode":false}}}"## diff --git a/codegen/src/main.rs b/codegen/src/main.rs index fc1efe0..979315d 100644 --- a/codegen/src/main.rs +++ b/codegen/src/main.rs @@ -1,3 +1,4 @@ +mod collect_large_numbers; mod collect_playlist_dates; mod download_testfiles; mod gen_dictionary; @@ -21,7 +22,9 @@ struct Cli { #[derive(Subcommand)] enum Commands { CollectPlaylistDates, - WritePlaylistDates, + CollectLargeNumbers, + ParsePlaylistDates, + ParseLargeNumbers, GenLocales, GenDict, DownloadTestfiles, @@ -36,8 +39,14 @@ async fn main() { Commands::CollectPlaylistDates => { collect_playlist_dates::collect_dates(&cli.project_root, cli.concurrency).await; } - Commands::WritePlaylistDates => { - collect_playlist_dates::write_samples_to_dict(&cli.project_root); + Commands::CollectLargeNumbers => { + collect_large_numbers::collect_large_numbers(&cli.project_root, cli.concurrency).await; + } + Commands::ParsePlaylistDates => { + collect_playlist_dates::write_samples_to_dict(&cli.project_root) + } + Commands::ParseLargeNumbers => { + collect_large_numbers::write_samples_to_dict(&cli.project_root) } Commands::GenLocales => { gen_locales::generate_locales(&cli.project_root).await; diff --git a/codegen/src/util.rs b/codegen/src/util.rs index 5925322..b41e7dc 100644 --- a/codegen/src/util.rs +++ b/codegen/src/util.rs @@ -3,19 +3,53 @@ use std::{collections::BTreeMap, fs::File, io::BufReader, path::Path, str::FromS use rustypipe::model::Language; use serde::{Deserialize, Serialize}; -const DICT_PATH: &str = "testfiles/date/dictionary.json"; +const DICT_PATH: &str = "testfiles/dict/dictionary.json"; type Dictionary = BTreeMap; #[derive(Debug, Default, Serialize, Deserialize)] #[serde(default)] pub struct DictEntry { + /// List of languages that should be treated equally (e.g. EnUs/EnGb/EnIn) pub equivalent: Vec, + /// Should the language be parsed by character instead of by word? + /// (e.g. Chinese/Japanese) pub by_char: bool, + /// Tokens for parsing timeago strings. + /// + /// Format: Parsed token -> \[Quantity\] Identifier + /// + /// Identifiers: `Y`(ear), `M`(month), `W`(eek), `D`(ay), + /// `h`(our), `m`(inute), `s`(econd) pub timeago_tokens: BTreeMap, + /// Order in which to parse numeric date components. Formatted as + /// a string of date identifiers (Y, M, D). + /// + /// Examples: + /// + /// - 03.01.2020 => `"DMY"` + /// - Jan 3, 2020 => `"DY"` pub date_order: String, + /// Tokens for parsing month names. + /// + /// Format: Parsed token -> Month number (starting from 1) pub months: BTreeMap, + /// Tokens for parsing date strings with no digits (e.g. Today, Tomorrow) + /// + /// Format: Parsed token -> \[Quantity\] Identifier pub timeago_nd_tokens: BTreeMap, + /// Are commas (instead of points) used as decimal separators? + pub comma_decimal: bool, + /// Tokens for parsing decimal prefixes (K, M, B, ...) + /// + /// Format: Parsed token -> decimal power + pub number_tokens: BTreeMap, +} + +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Text { + pub simple_text: String, } pub fn read_dict(project_root: &Path) -> Dictionary { @@ -48,6 +82,27 @@ pub fn filter_datestr(string: &str) -> String { .collect() } +pub fn filter_largenumstr(string: &str) -> String { + string + .chars() + .filter(|c| !matches!(c, '\u{200b}' | '.' | ',') && !c.is_ascii_digit()) + .collect() +} + +/// Parse a string after removing all non-numeric characters +pub fn parse_numeric(string: &str) -> Result +where + F: FromStr, +{ + let mut buf = String::new(); + for c in string.chars() { + if c.is_ascii_digit() { + buf.push(c); + } + } + buf.parse() +} + /// Parse all numbers occurring in a string and reurn them as a vec pub fn parse_numeric_vec(string: &str) -> Vec where diff --git a/notes/video_ids.txt b/notes/video_ids.txt index 926a78d..fd29b57 100644 --- a/notes/video_ids.txt +++ b/notes/video_ids.txt @@ -59,6 +59,6 @@ Dec PL1J-6JOckZtHo91uApeb10Qlf2XhkfM-9 24.12.2021 10e6: 1.7M UC6mIxFTvXkWQVEHPsEdflzQ 10e5: 125K UCD0y51PJfvkZNe3y3FR5riw 10e4: 27K UCNcN0dW43zE0Om3278fjY8A -10e3: 5K UCNcN0dW43zE0Om3278fjY8A +10e3: 5K UC0QEucPrn0-Ddi3JBTcs5Kw 10e2: 388 UCllyEQfcoiPN68zHv6mGHDQ -10e1: 37 UCNcN0dW43zE0Om3278fjY8A +10e1: 37 UCGiJh0NZ52wRhYKYnuZI08Q diff --git a/src/client/channel.rs b/src/client/channel.rs index 7eb5d8b..f7adfa7 100644 --- a/src/client/channel.rs +++ b/src/client/channel.rs @@ -72,7 +72,6 @@ impl MapResponse for response::Channel { c: ChannelVideos { id: header.channel_id, name: header.title, - subscriber_count_txt: header.subscriber_count_text, }, warnings, }) diff --git a/src/client/response/channel.rs b/src/client/response/channel.rs index ccf303e..9e369f9 100644 --- a/src/client/response/channel.rs +++ b/src/client/response/channel.rs @@ -82,12 +82,14 @@ pub struct HeaderRenderer { pub channel_id: String, /// Channel name pub title: String, - /// Approximate subscriber count (e.g. `880K subscribers`), depends on language - #[serde_as(as = "Text")] - pub subscriber_count_text: String, + /// Approximate subscriber count (e.g. `880K subscribers`), depends on language. + /// + /// `None` if the subscriber count is hidden. + #[serde_as(as = "Option")] + pub subscriber_count_text: Option, pub avatar: Thumbnails, - #[serde_as(as = "VecSkipError<_>")] - pub badges: Vec, + #[serde_as(as = "Option>")] + pub badges: Option>, pub banner: Thumbnails, pub mobile_banner: Thumbnails, /// Fullscreen (16:9) channel banner diff --git a/src/client/response/mod.rs b/src/client/response/mod.rs index 5ffb21a..748a3ba 100644 --- a/src/client/response/mod.rs +++ b/src/client/response/mod.rs @@ -93,6 +93,7 @@ pub struct GridVideoRenderer { pub published_time_text: Option, #[serde_as(as = "Option")] pub view_count_text: Option, + /// Contains video length #[serde_as(as = "VecSkipError<_>")] pub thumbnail_overlays: Vec, } @@ -397,6 +398,10 @@ pub trait IsLive { fn is_live(&self) -> bool; } +pub trait IsShort { + fn is_short(&self) -> bool; +} + impl IsLive for Vec { fn is_live(&self) -> bool { self.iter().any(|badge| { @@ -404,3 +409,19 @@ impl IsLive for Vec { }) } } + +impl IsLive for Vec { + fn is_live(&self) -> bool { + self.iter().any(|overlay| { + overlay.thumbnail_overlay_time_status_renderer.style == TimeOverlayStyle::Live + }) + } +} + +impl IsShort for Vec { + fn is_short(&self) -> bool { + self.iter().any(|overlay| { + overlay.thumbnail_overlay_time_status_renderer.style == TimeOverlayStyle::Shorts + }) + } +} diff --git a/src/dictionary.rs b/src/dictionary.rs index 6a6dea7..84d4465 100644 --- a/src/dictionary.rs +++ b/src/dictionary.rs @@ -1,15 +1,45 @@ // This file is automatically generated. DO NOT EDIT. +// See codegen/gen_dictionary.rs for the generation code. use crate::{ model::Language, timeago::{DateCmp, TaToken, TimeUnit}, }; +/// The dictionary contains the information required to parse dates and numbers +/// in all supported languages. pub struct Entry { + /// Should the language be parsed by character instead of by word? + /// (e.g. Chinese/Japanese) pub by_char: bool, + /// Tokens for parsing timeago strings. + /// + /// Format: Parsed token -> \[Quantity\] Identifier + /// + /// Identifiers: `Y`(ear), `M`(month), `W`(eek), `D`(ay), + /// `h`(our), `m`(inute), `s`(econd) pub timeago_tokens: phf::Map<&'static str, TaToken>, + /// Order in which to parse numeric date components. Formatted as + /// a string of date identifiers (Y, M, D). + /// + /// Examples: + /// + /// - 03.01.2020 => `"DMY"` + /// - Jan 3, 2020 => `"DY"` pub date_order: &'static [DateCmp], + /// Tokens for parsing month names. + /// + /// Format: Parsed token -> Month number (starting from 1) pub months: phf::Map<&'static str, u8>, + /// Tokens for parsing date strings with no digits (e.g. Today, Tomorrow) + /// + /// Format: Parsed token -> \[Quantity\] Identifier pub timeago_nd_tokens: phf::Map<&'static str, TaToken>, + /// Are commas (instead of points) used as decimal separators? + pub comma_decimal: bool, + /// Tokens for parsing decimal prefixes (K, M, B, ...) + /// + /// Format: Parsed token -> decimal power + pub number_tokens: phf::Map<&'static str, u8>, } #[rustfmt::skip] @@ -73,6 +103,17 @@ pub fn entry(lang: Language) -> Entry { ("vandag", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("mjd", 9), + ("m", 6), + ], + }, }, Language::Am => Entry { by_char: false, @@ -133,6 +174,18 @@ pub fn entry(lang: Language) -> Entry { ("ዛሬ", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (1, 0), + ], + entries: &[ + ("ሚ", 6), + ("ሺ", 3), + ("ቢ", 9), + ], + }, }, Language::Ar => Entry { by_char: false, @@ -190,6 +243,18 @@ pub fn entry(lang: Language) -> Entry { ("اليوم", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("مليار", 9), + ("مليون", 6), + ("ألف", 3), + ], + }, }, Language::As => Entry { by_char: false, @@ -227,6 +292,22 @@ pub fn entry(lang: Language) -> Entry { ("ক\u{9be}লি", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 15467950696543387533, + disps: &[ + (1, 0), + (4, 5), + ], + entries: &[ + ("নিয\u{9c1}তট\u{9be}", 6), + ("নিঃট\u{9be}", 6), + ("ল\u{9be}খট\u{9be}", 5), + ("শঃ", 9), + ("কোঃট\u{9be}", 9), + ("হ\u{9be}জ\u{9be}ৰট\u{9be}", 3), + ], + }, }, Language::Az => Entry { by_char: false, @@ -279,6 +360,17 @@ pub fn entry(lang: Language) -> Entry { ("bugün", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("mlrd", 9), + ("mln", 6), + ], + }, }, Language::Be => Entry { by_char: false, @@ -351,6 +443,18 @@ pub fn entry(lang: Language) -> Entry { ("ўчора", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (2, 0), + ], + entries: &[ + ("млрд", 9), + ("млн", 6), + ("тыс", 3), + ], + }, }, Language::Bg => Entry { by_char: false, @@ -396,6 +500,18 @@ pub fn entry(lang: Language) -> Entry { ("днес", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 8694567506910003252, + disps: &[ + (1, 0), + ], + entries: &[ + ("млрд", 9), + ("хил", 3), + ("млн", 6), + ], + }, }, Language::Bn => Entry { by_char: false, @@ -448,6 +564,18 @@ pub fn entry(lang: Language) -> Entry { ("আজ", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 15467950696543387533, + disps: &[ + (1, 0), + ], + entries: &[ + ("ল\u{9be}টি", 5), + ("শত", 9), + ("হ\u{9be}টি", 3), + ], + }, }, Language::Bs => Entry { by_char: false, @@ -514,6 +642,18 @@ pub fn entry(lang: Language) -> Entry { ("danas", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (2, 0), + ], + entries: &[ + ("hilj", 3), + ("mlr", 9), + ("mil", 6), + ], + }, }, Language::Ca => Entry { by_char: false, @@ -574,6 +714,17 @@ pub fn entry(lang: Language) -> Entry { ("ahir", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 15467950696543387533, + disps: &[ + (0, 0), + ], + entries: &[ + ("mM", 9), + ("m", 3), + ], + }, }, Language::Cs => Entry { by_char: false, @@ -620,6 +771,18 @@ pub fn entry(lang: Language) -> Entry { ("dnes", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 15467950696543387533, + disps: &[ + (1, 0), + ], + entries: &[ + ("mld", 9), + ("tis", 3), + ("mil", 6), + ], + }, }, Language::Da => Entry { by_char: false, @@ -679,6 +842,17 @@ pub fn entry(lang: Language) -> Entry { ("går", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (1, 0), + ], + entries: &[ + ("mio", 6), + ("mia", 9), + ], + }, }, Language::De => Entry { by_char: false, @@ -724,6 +898,17 @@ pub fn entry(lang: Language) -> Entry { ("heute", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (1, 0), + ], + entries: &[ + ("Mrd", 9), + ("Mio", 6), + ], + }, }, Language::El => Entry { by_char: false, @@ -784,6 +969,18 @@ pub fn entry(lang: Language) -> Entry { ("σήμερα", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (2, 0), + ], + entries: &[ + ("εκ", 6), + ("χιλ", 3), + ("δισ", 9), + ], + }, }, Language::En | Language::EnGb | Language::EnIn => Entry { by_char: false, @@ -845,8 +1042,20 @@ pub fn entry(lang: Language) -> Entry { ("today", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 15467950696543387533, + disps: &[ + (1, 0), + ], + entries: &[ + ("crore", 7), + ("B", 9), + ("lakh", 5), + ], + }, }, - Language::Es | Language::EsUs | Language::Es419 => Entry { + Language::Es => Entry { by_char: false, timeago_tokens: ::phf::Map { key: 10121458955350035957, @@ -905,6 +1114,86 @@ pub fn entry(lang: Language) -> Entry { ("hoy", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("mil", 9), + ], + }, + }, + Language::EsUs | Language::Es419 => Entry { + by_char: false, + timeago_tokens: ::phf::Map { + key: 10121458955350035957, + disps: &[ + (8, 9), + (2, 0), + (7, 5), + ], + entries: &[ + ("segundos", TaToken { n: 1, unit: Some(TimeUnit::Second) }), + ("meses", TaToken { n: 1, unit: Some(TimeUnit::Month) }), + ("minutos", TaToken { n: 1, unit: Some(TimeUnit::Minute) }), + ("semanas", TaToken { n: 1, unit: Some(TimeUnit::Week) }), + ("segundo", TaToken { n: 1, unit: Some(TimeUnit::Second) }), + ("días", TaToken { n: 1, unit: Some(TimeUnit::Day) }), + ("mes", TaToken { n: 1, unit: Some(TimeUnit::Month) }), + ("hora", TaToken { n: 1, unit: Some(TimeUnit::Hour) }), + ("años", TaToken { n: 1, unit: Some(TimeUnit::Year) }), + ("día", TaToken { n: 1, unit: Some(TimeUnit::Day) }), + ("semana", TaToken { n: 1, unit: Some(TimeUnit::Week) }), + ("horas", TaToken { n: 1, unit: Some(TimeUnit::Hour) }), + ("año", TaToken { n: 1, unit: Some(TimeUnit::Year) }), + ("minuto", TaToken { n: 1, unit: Some(TimeUnit::Minute) }), + ], + }, + date_order: &[DateCmp::D, DateCmp::Y], + months: ::phf::Map { + key: 15467950696543387533, + disps: &[ + (1, 0), + (1, 6), + (0, 4), + ], + entries: &[ + ("jul", 7), + ("oct", 10), + ("ene", 1), + ("may", 5), + ("sept", 9), + ("feb", 2), + ("nov", 11), + ("dic", 12), + ("abr", 4), + ("jun", 6), + ("ago", 8), + ("mar", 3), + ], + }, + timeago_nd_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("ayer", TaToken { n: 1, unit: Some(TimeUnit::Day) }), + ("hoy", TaToken { n: 0, unit: Some(TimeUnit::Day) }), + ], + }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("mil", 9), + ], + }, }, Language::Et => Entry { by_char: false, @@ -968,6 +1257,18 @@ pub fn entry(lang: Language) -> Entry { ("täna", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (2, 0), + ], + entries: &[ + ("mld", 9), + ("mln", 6), + ("tuh", 3), + ], + }, }, Language::Eu => Entry { by_char: false, @@ -1023,6 +1324,14 @@ pub fn entry(lang: Language) -> Entry { ("gaur", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + ], + entries: &[ + ], + }, }, Language::Fa => Entry { by_char: false, @@ -1075,6 +1384,18 @@ pub fn entry(lang: Language) -> Entry { ("دیروز", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 14108922650502679131, + disps: &[ + (0, 0), + ], + entries: &[ + ("میلیارد", 9), + ("میلیون", 6), + ("هزار", 3), + ], + }, }, Language::Fi => Entry { by_char: false, @@ -1120,6 +1441,18 @@ pub fn entry(lang: Language) -> Entry { ("eilen", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 7485420634051515786, + disps: &[ + (0, 0), + ], + entries: &[ + ("mrd", 9), + ("t", 3), + ("milj", 6), + ], + }, }, Language::Fil => Entry { by_char: false, @@ -1172,6 +1505,16 @@ pub fn entry(lang: Language) -> Entry { ("kahapon", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("B", 9), + ], + }, }, Language::Fr | Language::FrCa => Entry { by_char: false, @@ -1232,6 +1575,17 @@ pub fn entry(lang: Language) -> Entry { ("aujourd'hui", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (1, 0), + ], + entries: &[ + ("G", 9), + ("Md", 9), + ], + }, }, Language::Gl => Entry { by_char: false, @@ -1292,6 +1646,14 @@ pub fn entry(lang: Language) -> Entry { ("onte", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + ], + entries: &[ + ], + }, }, Language::Gu => Entry { by_char: false, @@ -1344,6 +1706,19 @@ pub fn entry(lang: Language) -> Entry { ("ગઈ", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (2, 0), + ], + entries: &[ + ("કરોડ", 7), + ("અબજ", 9), + ("હજાર", 3), + ("લાખ", 5), + ], + }, }, Language::Hi => Entry { by_char: false, @@ -1396,6 +1771,19 @@ pub fn entry(lang: Language) -> Entry { ("आज", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 2980949210194914378, + disps: &[ + (2, 0), + ], + entries: &[ + ("हज\u{93c}ार", 3), + ("लाख", 5), + ("क॰", 7), + ("अ॰", 9), + ], + }, }, Language::Hr => Entry { by_char: false, @@ -1462,6 +1850,18 @@ pub fn entry(lang: Language) -> Entry { ("danas", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("mlr", 9), + ("tis", 3), + ("mil", 6), + ], + }, }, Language::Hu => Entry { by_char: false, @@ -1522,6 +1922,17 @@ pub fn entry(lang: Language) -> Entry { ("ma", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("Mrd", 9), + ("E", 3), + ], + }, }, Language::Hy => Entry { by_char: false, @@ -1574,6 +1985,18 @@ pub fn entry(lang: Language) -> Entry { ("այսօր", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 15467950696543387533, + disps: &[ + (0, 0), + ], + entries: &[ + ("հզր", 3), + ("մլն", 6), + ("մլրդ", 9), + ], + }, }, Language::Id => Entry { by_char: false, @@ -1626,6 +2049,17 @@ pub fn entry(lang: Language) -> Entry { ("kemarin", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("jt", 6), + ("rb", 3), + ], + }, }, Language::Is => Entry { by_char: false, @@ -1686,6 +2120,18 @@ pub fn entry(lang: Language) -> Entry { ("gær", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 10121458955350035957, + disps: &[ + (2, 0), + ], + entries: &[ + ("þ", 3), + ("ma", 9), + ("m", 6), + ], + }, }, Language::It => Entry { by_char: false, @@ -1746,6 +2192,17 @@ pub fn entry(lang: Language) -> Entry { ("oggi", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("Mrd", 9), + ("Mln", 6), + ], + }, }, Language::Iw => Entry { by_char: false, @@ -1813,6 +2270,18 @@ pub fn entry(lang: Language) -> Entry { ("אתמול", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 10121458955350035957, + disps: &[ + (2, 0), + ], + entries: &[ + ("\u{202b}M\u{200f}\u{202c}", 6), + ("\u{202b}B\u{200f}\u{202c}", 9), + ("\u{202b}K\u{200f}\u{202c}", 3), + ], + }, }, Language::Ja => Entry { by_char: true, @@ -1850,6 +2319,17 @@ pub fn entry(lang: Language) -> Entry { ("本", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("万", 4), + ("億", 8), + ], + }, }, Language::Ka => Entry { by_char: false, @@ -1902,6 +2382,18 @@ pub fn entry(lang: Language) -> Entry { ("დღეს", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (1, 0), + ], + entries: &[ + ("მლნ", 6), + ("მლრდ", 9), + ("ათ", 3), + ], + }, }, Language::Kk => Entry { by_char: false, @@ -1954,6 +2446,19 @@ pub fn entry(lang: Language) -> Entry { ("бүгін", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 10121458955350035957, + disps: &[ + (0, 0), + ], + entries: &[ + ("мың", 3), + ("млрд", 9), + ("м", 3), + ("млн", 6), + ], + }, }, Language::Km => Entry { by_char: false, @@ -2006,6 +2511,18 @@ pub fn entry(lang: Language) -> Entry { ("បានធ\u{17d2}វើបច\u{17d2}ច\u{17bb}ប\u{17d2}បន\u{17d2}នភាពម\u{17d2}ស\u{17b7}លម\u{17b7}ញ", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (2, 0), + ], + entries: &[ + ("លាន", 6), + ("ប\u{17ca}\u{17b8}លាន", 9), + ("ពាន\u{17cb}", 3), + ], + }, }, Language::Kn => Entry { by_char: false, @@ -2066,6 +2583,17 @@ pub fn entry(lang: Language) -> Entry { ("ನ\u{cbf}ನ\u{ccd}ನ\u{cc6}", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("ಕೋಟ\u{cbf}", 7), + ("ಲಕ\u{ccd}ಷ", 5), + ], + }, }, Language::Ko => Entry { by_char: false, @@ -2102,6 +2630,18 @@ pub fn entry(lang: Language) -> Entry { ("오늘", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 15467950696543387533, + disps: &[ + (0, 0), + ], + entries: &[ + ("천회", 3), + ("억회", 8), + ("만회", 4), + ], + }, }, Language::Ky => Entry { by_char: false, @@ -2154,6 +2694,18 @@ pub fn entry(lang: Language) -> Entry { ("бүгүн", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 15467950696543387533, + disps: &[ + (1, 0), + ], + entries: &[ + ("млд", 9), + ("млн", 6), + ("миң", 3), + ], + }, }, Language::Lo => Entry { by_char: false, @@ -2206,6 +2758,19 @@ pub fn entry(lang: Language) -> Entry { ("ອ\u{eb1}ບເດດມ\u{eb7}\u{ec9}ວານນ\u{eb5}\u{ec9}", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 15467950696543387533, + disps: &[ + (2, 0), + ], + entries: &[ + ("ກ\u{eb5}ບ", 3), + ("ລ\u{ec9}ານ", 6), + ("ຕ\u{eb7}\u{ec9}", 9), + ("ພ\u{eb1}ນ", 3), + ], + }, }, Language::Lt => Entry { by_char: false, @@ -2260,6 +2825,18 @@ pub fn entry(lang: Language) -> Entry { ("vakar", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 15467950696543387533, + disps: &[ + (0, 0), + ], + entries: &[ + ("mlrd", 9), + ("mln", 6), + ("tūkst", 3), + ], + }, }, Language::Lv => Entry { by_char: false, @@ -2320,6 +2897,18 @@ pub fn entry(lang: Language) -> Entry { ("vakar", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 15467950696543387533, + disps: &[ + (0, 0), + ], + entries: &[ + ("milj", 6), + ("mljrd", 9), + ("tūkst", 3), + ], + }, }, Language::Mk => Entry { by_char: false, @@ -2365,6 +2954,19 @@ pub fn entry(lang: Language) -> Entry { ("денес", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 15467950696543387533, + disps: &[ + (2, 0), + ], + entries: &[ + ("илј", 3), + ("мил", 6), + ("милј", 9), + ("М", 6), + ], + }, }, Language::Ml => Entry { by_char: false, @@ -2417,6 +3019,17 @@ pub fn entry(lang: Language) -> Entry { ("ഇന\u{d4d}നലെ", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("ലക\u{d4d}ഷം", 5), + ("കോടി", 7), + ], + }, }, Language::Mn => Entry { by_char: false, @@ -2454,6 +3067,18 @@ pub fn entry(lang: Language) -> Entry { ("өчигдөр", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (1, 0), + ], + entries: &[ + ("сая", 6), + ("тэрбум", 9), + ("мянга", 3), + ], + }, }, Language::Mr => Entry { by_char: false, @@ -2514,6 +3139,19 @@ pub fn entry(lang: Language) -> Entry { ("आज", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (2, 0), + ], + entries: &[ + ("ह", 3), + ("अब\u{94d}ज", 9), + ("लाख", 5), + ("कोटी", 7), + ], + }, }, Language::Ms => Entry { by_char: false, @@ -2566,6 +3204,17 @@ pub fn entry(lang: Language) -> Entry { ("ini", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (1, 0), + ], + entries: &[ + ("J", 6), + ("B", 9), + ], + }, }, Language::My => Entry { by_char: false, @@ -2619,6 +3268,22 @@ pub fn entry(lang: Language) -> Entry { ("မနေ\u{1037}က", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 10121458955350035957, + disps: &[ + (5, 1), + (2, 0), + ], + entries: &[ + ("ထောင\u{103a}", 3), + ("သန\u{103a}း", 6), + ("က\u{102f}ဋေထ", 10), + ("က\u{102f}ဋေ", 7), + ("သောင\u{103a}း", 4), + ("သ\u{102d}န\u{103a}း", 5), + ], + }, }, Language::Ne => Entry { by_char: false, @@ -2671,6 +3336,19 @@ pub fn entry(lang: Language) -> Entry { ("हिजो", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 10121458955350035957, + disps: &[ + (1, 0), + ], + entries: &[ + ("करोड", 7), + ("अरब", 9), + ("हजार", 3), + ("लाख", 5), + ], + }, }, Language::Nl => Entry { by_char: false, @@ -2729,6 +3407,17 @@ pub fn entry(lang: Language) -> Entry { ("vandaag", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 15467950696543387533, + disps: &[ + (0, 0), + ], + entries: &[ + ("mld", 9), + ("mln", 6), + ], + }, }, Language::No => Entry { by_char: false, @@ -2789,6 +3478,17 @@ pub fn entry(lang: Language) -> Entry { ("går", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("mrd", 9), + ("mill", 6), + ], + }, }, Language::Or => Entry { by_char: false, @@ -2841,6 +3541,18 @@ pub fn entry(lang: Language) -> Entry { ("ଗତକ\u{b3e}ଲ\u{b3f}", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (2, 0), + ], + entries: &[ + ("ବ\u{b3f}ଟ\u{b3f}", 9), + ("ନ\u{b3f}ଟ\u{b3f}", 6), + ("ହଟ\u{b3f}", 3), + ], + }, }, Language::Pa => Entry { by_char: false, @@ -2896,6 +3608,19 @@ pub fn entry(lang: Language) -> Entry { ("ਅ\u{a71}ਜ", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 12213676231523076107, + disps: &[ + (0, 0), + ], + entries: &[ + ("ਕਰ\u{a4b}ੜ", 7), + ("ਲ\u{a71}ਖ", 5), + ("ਹਜ\u{a3c}ਾਰ", 3), + ("ਅਰਬ", 9), + ], + }, }, Language::Pl => Entry { by_char: false, @@ -2962,6 +3687,18 @@ pub fn entry(lang: Language) -> Entry { ("wczoraj", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (1, 0), + ], + entries: &[ + ("mln", 6), + ("mld", 9), + ("tys", 3), + ], + }, }, Language::Pt => Entry { by_char: false, @@ -3022,6 +3759,18 @@ pub fn entry(lang: Language) -> Entry { ("ontem", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (2, 0), + ], + entries: &[ + ("mi", 6), + ("bi", 9), + ("mil", 3), + ], + }, }, Language::PtPt => Entry { by_char: false, @@ -3067,6 +3816,17 @@ pub fn entry(lang: Language) -> Entry { ("ontem", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("mil", 3), + ("mM", 9), + ], + }, }, Language::Ro => Entry { by_char: false, @@ -3127,6 +3887,17 @@ pub fn entry(lang: Language) -> Entry { ("ieri", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("mil", 6), + ("mld", 9), + ], + }, }, Language::Ru => Entry { by_char: false, @@ -3194,6 +3965,18 @@ pub fn entry(lang: Language) -> Entry { ("вчера", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (2, 0), + ], + entries: &[ + ("млрд", 9), + ("млн", 6), + ("тыс", 3), + ], + }, }, Language::Si => Entry { by_char: false, @@ -3247,6 +4030,18 @@ pub fn entry(lang: Language) -> Entry { ("අද", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 15467950696543387533, + disps: &[ + (0, 0), + ], + entries: &[ + ("ම\u{dd2}", 6), + ("බ\u{dd2}", 9), + ("ද", 3), + ], + }, }, Language::Sk => Entry { by_char: false, @@ -3292,6 +4087,18 @@ pub fn entry(lang: Language) -> Entry { ("dnes", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 15467950696543387533, + disps: &[ + (1, 0), + ], + entries: &[ + ("mld", 9), + ("tis", 3), + ("mil", 6), + ], + }, }, Language::Sl => Entry { by_char: false, @@ -3362,6 +4169,18 @@ pub fn entry(lang: Language) -> Entry { ("včeraj", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("mio", 6), + ("tis", 3), + ("mrd", 9), + ], + }, }, Language::Sq => Entry { by_char: false, @@ -3417,6 +4236,18 @@ pub fn entry(lang: Language) -> Entry { ("sot", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (1, 0), + ], + entries: &[ + ("mln", 6), + ("mld", 9), + ("mijë", 3), + ], + }, }, Language::Sr => Entry { by_char: false, @@ -3465,6 +4296,18 @@ pub fn entry(lang: Language) -> Entry { ("данас", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("млрд", 9), + ("мил", 6), + ("хиљ", 3), + ], + }, }, Language::SrLatn => Entry { by_char: false, @@ -3514,6 +4357,18 @@ pub fn entry(lang: Language) -> Entry { ("danas", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (2, 0), + ], + entries: &[ + ("hilj", 3), + ("mlrd", 9), + ("mil", 6), + ], + }, }, Language::Sv => Entry { by_char: false, @@ -3573,6 +4428,17 @@ pub fn entry(lang: Language) -> Entry { ("igår", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (1, 0), + ], + entries: &[ + ("mn", 6), + ("md", 9), + ], + }, }, Language::Sw => Entry { by_char: false, @@ -3627,6 +4493,17 @@ pub fn entry(lang: Language) -> Entry { ("jana", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("elfu", 3), + ("B", 9), + ], + }, }, Language::Ta => Entry { by_char: false, @@ -3686,6 +4563,17 @@ pub fn entry(lang: Language) -> Entry { ("இன\u{bcd}று", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("லட\u{bcd}சம\u{bcd}", 5), + ("கோடி", 7), + ], + }, }, Language::Te => Entry { by_char: false, @@ -3746,6 +4634,18 @@ pub fn entry(lang: Language) -> Entry { ("న\u{c3f}న\u{c4d}న", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 10121458955350035957, + disps: &[ + (1, 0), + ], + entries: &[ + ("క\u{c4b}ట\u{c4d}లు", 7), + ("లక\u{c4d}ష", 5), + ("లక\u{c4d}షలు", 5), + ], + }, }, Language::Th => Entry { by_char: false, @@ -3798,6 +4698,22 @@ pub fn entry(lang: Language) -> Entry { ("อ\u{e31}ปเดตแล\u{e49}วเม\u{e37}\u{e48}อวาน", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 15467950696543387533, + disps: &[ + (0, 1), + (4, 0), + ], + entries: &[ + ("พ\u{e31}น", 3), + ("หม\u{e37}\u{e48}น", 4), + ("พ\u{e31}นล\u{e49}าน", 9), + ("แสน", 5), + ("หม\u{e37}\u{e48}นล\u{e49}าน", 10), + ("ล\u{e49}าน", 6), + ], + }, }, Language::Tr => Entry { by_char: false, @@ -3850,6 +4766,18 @@ pub fn entry(lang: Language) -> Entry { ("bugün", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 7485420634051515786, + disps: &[ + (1, 0), + ], + entries: &[ + ("Mn", 6), + ("Mr", 9), + ("B", 3), + ], + }, }, Language::Uk => Entry { by_char: false, @@ -3917,6 +4845,18 @@ pub fn entry(lang: Language) -> Entry { ("сьогодні", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 10121458955350035957, + disps: &[ + (0, 0), + ], + entries: &[ + ("млрд", 9), + ("тис", 3), + ("млн", 6), + ], + }, }, Language::Ur => Entry { by_char: false, @@ -3976,6 +4916,19 @@ pub fn entry(lang: Language) -> Entry { ("کل", TaToken { n: 1, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 7485420634051515786, + disps: &[ + (0, 0), + ], + entries: &[ + ("ہزار", 3), + ("ارب", 9), + ("کروڑ", 7), + ("لاکھ", 5), + ], + }, }, Language::Uz => Entry { by_char: false, @@ -4028,6 +4981,18 @@ pub fn entry(lang: Language) -> Entry { ("bugun", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (1, 0), + ], + entries: &[ + ("mln", 6), + ("mlrd", 9), + ("ming", 3), + ], + }, }, Language::Vi => Entry { by_char: false, @@ -4066,6 +5031,18 @@ pub fn entry(lang: Language) -> Entry { ("nay", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: true, + number_tokens: ::phf::Map { + key: 10121458955350035957, + disps: &[ + (0, 0), + ], + entries: &[ + ("T", 9), + ("Tr", 6), + ("N", 3), + ], + }, }, Language::ZhCn => Entry { by_char: true, @@ -4103,6 +5080,17 @@ pub fn entry(lang: Language) -> Entry { ("今", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 15467950696543387533, + disps: &[ + (1, 0), + ], + entries: &[ + ("万", 4), + ("亿", 8), + ], + }, }, Language::ZhHk => Entry { by_char: true, @@ -4141,6 +5129,16 @@ pub fn entry(lang: Language) -> Entry { ("今", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("B", 9), + ], + }, }, Language::ZhTw => Entry { by_char: true, @@ -4178,6 +5176,17 @@ pub fn entry(lang: Language) -> Entry { ("今", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("萬", 4), + ("億", 8), + ], + }, }, Language::Zu => Entry { by_char: false, @@ -4238,6 +5247,16 @@ pub fn entry(lang: Language) -> Entry { ("namuhla", TaToken { n: 0, unit: Some(TimeUnit::Day) }), ], }, + comma_decimal: false, + number_tokens: ::phf::Map { + key: 12913932095322966823, + disps: &[ + (0, 0), + ], + entries: &[ + ("B", 9), + ], + }, }, } } diff --git a/src/model/mod.rs b/src/model/mod.rs index 89cc431..63c4704 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -310,7 +310,7 @@ pub struct RecommendedVideo { pub publish_date_txt: Option, /// View count /// - /// Is `None` if it could not be parsed + /// `None` if it could not be extracted. pub view_count: Option, /// Is the video an active livestream? pub is_live: bool, @@ -400,6 +400,43 @@ pub struct ChannelVideos { pub id: String, /// Channel name pub name: String, - /// Textual subscriber count (e.g. `2.3M subscribers`), depends on language setting - pub subscriber_count_txt: String, + /* + /// Channel subscriber count + /// + /// `None` if the subscriber count was hidden by the owner + /// or could not be parsed. + pub subscriber_count: Option, + pub videos: Paginator, + */ +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[non_exhaustive] +pub struct ChannelVideo { + /// Unique YouTube video ID + pub id: String, + /// Video title + pub title: String, + /// Video length in seconds. + /// + /// Is `None` for livestreams. + pub length: Option, + /// Video thumbnail + pub thumbnail: Vec, + /// Video publishing date. + /// + /// `None` if the date could not be parsed. + pub publish_date: Option>, + /// Textual video publish date (e.g. `11 months ago`, depends on language) + /// + /// Is `None` for livestreams. + pub publish_date_txt: Option, + /// View count + /// + /// `None` if it could not be extracted. + pub view_count: Option, + /// Is the video an active livestream? + pub is_live: bool, + /// Is the video a YouTube Short video (vertical and <60s)? + pub is_short: bool, } diff --git a/src/model/richtext.rs b/src/model/richtext.rs index feac617..726962c 100644 --- a/src/model/richtext.rs +++ b/src/model/richtext.rs @@ -53,7 +53,7 @@ pub trait ToHtml { } impl TextComponent { - pub fn get_text<'a>(&'a self) -> &'a str { + pub fn get_text(&self) -> &str { match self { TextComponent::Text(text) => text, TextComponent::Web { text, .. } => text, diff --git a/src/timeago.rs b/src/timeago.rs index 8f8c32a..f9404f7 100644 --- a/src/timeago.rs +++ b/src/timeago.rs @@ -247,7 +247,7 @@ mod tests { #[test] fn t_testfile() { - let json_path = Path::new("testfiles/date/timeago_samples.json"); + let json_path = Path::new("testfiles/dict/timeago_samples.json"); let expect = [ TimeAgo { @@ -430,7 +430,7 @@ mod tests { cases: BTreeMap, } - let json_path = Path::new("testfiles/date/timeago_table.json"); + let json_path = Path::new("testfiles/dict/timeago_table.json"); let json_file = File::open(json_path).unwrap(); let timeago_table: TimeagoTable = serde_json::from_reader(BufReader::new(json_file)).unwrap(); @@ -477,7 +477,7 @@ mod tests { #[test] fn t_parse_date_samples() { - let json_path = Path::new("testfiles/date/playlist_samples.json"); + let json_path = Path::new("testfiles/dict/playlist_samples.json"); let json_file = File::open(json_path).unwrap(); let date_samples: BTreeMap> = serde_json::from_reader(BufReader::new(json_file)).unwrap(); diff --git a/testfiles/date/cldr_pluralrules_cardinals.json b/testfiles/dict/cldr_pluralrules_cardinals.json similarity index 100% rename from testfiles/date/cldr_pluralrules_cardinals.json rename to testfiles/dict/cldr_pluralrules_cardinals.json diff --git a/testfiles/date/dictionary.json b/testfiles/dict/dictionary.json similarity index 85% rename from testfiles/date/dictionary.json rename to testfiles/dict/dictionary.json index 8b89c86..6ac29e1 100644 --- a/testfiles/date/dictionary.json +++ b/testfiles/dict/dictionary.json @@ -35,6 +35,11 @@ "timeago_nd_tokens": { "gister": "1D", "vandag": "0D" + }, + "comma_decimal": true, + "number_tokens": { + "m": 6, + "mjd": 9 } }, "am": { @@ -74,6 +79,12 @@ "timeago_nd_tokens": { "ትላንት": "1D", "ዛሬ": "0D" + }, + "comma_decimal": false, + "number_tokens": { + "ሚ": 6, + "ሺ": 3, + "ቢ": 9 } }, "ar": { @@ -110,6 +121,12 @@ "timeago_nd_tokens": { "اليوم": "0D", "بالأمس": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "ألف": 3, + "مليار": 9, + "مليون": 6 } }, "as": { @@ -129,6 +146,15 @@ "timeago_nd_tokens": { "আজি": "0D", "কালি": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "কোঃটা": 9, + "নিঃটা": 6, + "নিযুতটা": 6, + "লাখটা": 5, + "শঃ": 9, + "হাজাৰটা": 3 } }, "az": { @@ -161,6 +187,11 @@ "timeago_nd_tokens": { "bugün": "0D", "dünən": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "mln": 6, + "mlrd": 9 } }, "be": { @@ -210,6 +241,12 @@ "timeago_nd_tokens": { "сёння": "0D", "ўчора": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "млн": 6, + "млрд": 9, + "тыс": 3 } }, "bg": { @@ -236,6 +273,12 @@ "timeago_nd_tokens": { "вчера": "1D", "днес": "0D" + }, + "comma_decimal": true, + "number_tokens": { + "млн": 6, + "млрд": 9, + "хил": 3 } }, "bn": { @@ -268,6 +311,12 @@ "timeago_nd_tokens": { "আজ": "0D", "গতকাল": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "লাটি": 5, + "শত": 9, + "হাটি": 3 } }, "bs": { @@ -312,6 +361,12 @@ "timeago_nd_tokens": { "danas": "0D", "jučer": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "hilj": 3, + "mil": 6, + "mlr": 9 } }, "ca": { @@ -351,6 +406,11 @@ "timeago_nd_tokens": { "ahir": "1D", "avui": "0D" + }, + "comma_decimal": true, + "number_tokens": { + "m": 3, + "mM": 9 } }, "cs": { @@ -378,6 +438,12 @@ "timeago_nd_tokens": { "dnes": "0D", "včera": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "mil": 6, + "mld": 9, + "tis": 3 } }, "da": { @@ -416,6 +482,11 @@ "timeago_nd_tokens": { "dag": "0D", "går": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "mia": 9, + "mio": 6 } }, "de": { @@ -442,6 +513,11 @@ "timeago_nd_tokens": { "gestern": "1D", "heute": "0D" + }, + "comma_decimal": true, + "number_tokens": { + "Mio": 6, + "Mrd": 9 } }, "el": { @@ -481,6 +557,12 @@ "timeago_nd_tokens": { "σήμερα": "0D", "χτες": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "δισ": 9, + "εκ": 6, + "χιλ": 3 } }, "en": { @@ -524,11 +606,59 @@ "timeago_nd_tokens": { "today": "0D", "yesterday": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "B": 9, + "crore": 7, + "lakh": 5 } }, "es": { + "equivalent": [], + "by_char": false, + "timeago_tokens": { + "año": "Y", + "años": "Y", + "día": "D", + "días": "D", + "hora": "h", + "horas": "h", + "mes": "M", + "meses": "M", + "minuto": "m", + "minutos": "m", + "segundo": "s", + "segundos": "s", + "semana": "W", + "semanas": "W" + }, + "date_order": "DY", + "months": { + "abr": 4, + "ago": 8, + "dic": 12, + "ene": 1, + "feb": 2, + "jul": 7, + "jun": 6, + "mar": 3, + "may": 5, + "nov": 11, + "oct": 10, + "sept": 9 + }, + "timeago_nd_tokens": { + "ayer": "1D", + "hoy": "0D" + }, + "comma_decimal": true, + "number_tokens": { + "mil": 9 + } + }, + "es-US": { "equivalent": [ - "es-US", "es-419" ], "by_char": false, @@ -566,6 +696,10 @@ "timeago_nd_tokens": { "ayer": "1D", "hoy": "0D" + }, + "comma_decimal": false, + "number_tokens": { + "mil": 9 } }, "et": { @@ -607,6 +741,12 @@ "timeago_nd_tokens": { "eile": "1D", "täna": "0D" + }, + "comma_decimal": true, + "number_tokens": { + "mld": 9, + "mln": 6, + "tuh": 3 } }, "eu": { @@ -642,7 +782,9 @@ "timeago_nd_tokens": { "atzo": "1D", "gaur": "0D" - } + }, + "comma_decimal": true, + "number_tokens": {} }, "fa": { "equivalent": [], @@ -674,6 +816,12 @@ "timeago_nd_tokens": { "امروز": "0D", "دیروز": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "میلیارد": 9, + "میلیون": 6, + "هزار": 3 } }, "fi": { @@ -700,6 +848,12 @@ "timeago_nd_tokens": { "eilen": "1D", "tänään": "0D" + }, + "comma_decimal": true, + "number_tokens": { + "milj": 6, + "mrd": 9, + "t": 3 } }, "fil": { @@ -732,6 +886,10 @@ "timeago_nd_tokens": { "kahapon": "1D", "ngayong": "0D" + }, + "comma_decimal": false, + "number_tokens": { + "B": 9 } }, "fr": { @@ -773,6 +931,11 @@ "timeago_nd_tokens": { "aujourd'hui": "0D", "hier": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "G": 9, + "Md": 9 } }, "gl": { @@ -812,7 +975,9 @@ "timeago_nd_tokens": { "hoxe": "0D", "onte": "1D" - } + }, + "comma_decimal": true, + "number_tokens": {} }, "gu": { "equivalent": [], @@ -844,6 +1009,13 @@ "timeago_nd_tokens": { "આજે": "0D", "ગઈ": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "અબજ": 9, + "કરોડ": 7, + "લાખ": 5, + "હજાર": 3 } }, "hi": { @@ -876,6 +1048,13 @@ "timeago_nd_tokens": { "आज": "0D", "कल": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "अ॰": 9, + "क॰": 7, + "लाख": 5, + "हज़ार": 3 } }, "hr": { @@ -920,6 +1099,12 @@ "timeago_nd_tokens": { "danas": "0D", "jučer": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "mil": 6, + "mlr": 9, + "tis": 3 } }, "hu": { @@ -959,6 +1144,11 @@ "timeago_nd_tokens": { "ma": "0D", "tegnap": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "E": 3, + "Mrd": 9 } }, "hy": { @@ -991,6 +1181,12 @@ "timeago_nd_tokens": { "այսօր": "0D", "երեկ": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "հզր": 3, + "մլն": 6, + "մլրդ": 9 } }, "id": { @@ -1023,6 +1219,11 @@ "timeago_nd_tokens": { "ini": "0D", "kemarin": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "jt": 6, + "rb": 3 } }, "is": { @@ -1062,6 +1263,12 @@ "timeago_nd_tokens": { "dag": "0D", "gær": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "m": 6, + "ma": 9, + "þ": 3 } }, "it": { @@ -1101,6 +1308,11 @@ "timeago_nd_tokens": { "ieri": "1D", "oggi": "0D" + }, + "comma_decimal": true, + "number_tokens": { + "Mln": 6, + "Mrd": 9 } }, "iw": { @@ -1146,6 +1358,12 @@ "timeago_nd_tokens": { "אתמול": "1D", "היום": "0D" + }, + "comma_decimal": false, + "number_tokens": { + "‫B‏‬": 9, + "‫K‏‬": 3, + "‫M‏‬": 6 } }, "ja": { @@ -1165,6 +1383,11 @@ "timeago_nd_tokens": { "日": "1D", "本": "0D" + }, + "comma_decimal": false, + "number_tokens": { + "万": 4, + "億": 8 } }, "ka": { @@ -1197,6 +1420,12 @@ "timeago_nd_tokens": { "გუშინ": "1D", "დღეს": "0D" + }, + "comma_decimal": true, + "number_tokens": { + "ათ": 3, + "მლნ": 6, + "მლრდ": 9 } }, "kk": { @@ -1229,6 +1458,13 @@ "timeago_nd_tokens": { "бүгін": "0D", "кеше": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "м": 3, + "млн": 6, + "млрд": 9, + "мың": 3 } }, "km": { @@ -1261,6 +1497,12 @@ "timeago_nd_tokens": { "បានធ្វើបច្ចុប្បន្នភាពថ្ងៃនេះ": "0D", "បានធ្វើបច្ចុប្បន្នភាពម្សិលមិញ": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "ប៊ីលាន": 9, + "ពាន់": 3, + "លាន": 6 } }, "kn": { @@ -1300,6 +1542,11 @@ "timeago_nd_tokens": { "ಇಂದು": "0D", "ನಿನ್ನೆ": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "ಕೋಟಿ": 7, + "ಲಕ್ಷ": 5 } }, "ko": { @@ -1318,6 +1565,12 @@ "months": {}, "timeago_nd_tokens": { "오늘": "0D" + }, + "comma_decimal": false, + "number_tokens": { + "만회": 4, + "억회": 8, + "천회": 3 } }, "ky": { @@ -1350,6 +1603,12 @@ "timeago_nd_tokens": { "бүгүн": "0D", "кечээ": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "миң": 3, + "млд": 9, + "млн": 6 } }, "lo": { @@ -1382,6 +1641,13 @@ "timeago_nd_tokens": { "ອັບເດດມື້ນີ້": "0D", "ອັບເດດມື້ວານນີ້": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "ກີບ": 3, + "ຕື້": 9, + "ພັນ": 3, + "ລ້ານ": 6 } }, "lt": { @@ -1415,6 +1681,12 @@ "timeago_nd_tokens": { "vakar": "1D", "šiandien": "0D" + }, + "comma_decimal": true, + "number_tokens": { + "mln": 6, + "mlrd": 9, + "tūkst": 3 } }, "lv": { @@ -1454,6 +1726,12 @@ "timeago_nd_tokens": { "vakar": "1D", "šodien": "0D" + }, + "comma_decimal": true, + "number_tokens": { + "milj": 6, + "mljrd": 9, + "tūkst": 3 } }, "mk": { @@ -1480,6 +1758,13 @@ "timeago_nd_tokens": { "вчера": "1D", "денес": "0D" + }, + "comma_decimal": true, + "number_tokens": { + "М": 6, + "илј": 3, + "мил": 6, + "милј": 9 } }, "ml": { @@ -1512,6 +1797,11 @@ "timeago_nd_tokens": { "ഇന്നലെ": "1D", "ഇന്ന്": "0D" + }, + "comma_decimal": false, + "number_tokens": { + "കോടി": 7, + "ലക്ഷം": 5 } }, "mn": { @@ -1531,6 +1821,12 @@ "timeago_nd_tokens": { "өнөөдөр": "0D", "өчигдөр": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "мянга": 3, + "сая": 6, + "тэрбум": 9 } }, "mr": { @@ -1570,6 +1866,13 @@ "timeago_nd_tokens": { "आज": "0D", "काल": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "अब्ज": 9, + "कोटी": 7, + "लाख": 5, + "ह": 3 } }, "ms": { @@ -1602,6 +1905,11 @@ "timeago_nd_tokens": { "ini": "0D", "semalam": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "B": 9, + "J": 6 } }, "my": { @@ -1635,6 +1943,15 @@ "timeago_nd_tokens": { "မနေ့က": "1D", "ယနေ့": "0D" + }, + "comma_decimal": false, + "number_tokens": { + "ကုဋေ": 7, + "ကုဋေထ": 10, + "ထောင်": 3, + "သန်း": 6, + "သိန်း": 5, + "သောင်း": 4 } }, "ne": { @@ -1667,6 +1984,13 @@ "timeago_nd_tokens": { "आज": "0D", "हिजो": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "अरब": 9, + "करोड": 7, + "लाख": 5, + "हजार": 3 } }, "nl": { @@ -1704,6 +2028,11 @@ "timeago_nd_tokens": { "gisteren": "1D", "vandaag": "0D" + }, + "comma_decimal": true, + "number_tokens": { + "mld": 9, + "mln": 6 } }, "no": { @@ -1743,6 +2072,11 @@ "timeago_nd_tokens": { "dag": "0D", "går": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "mill": 6, + "mrd": 9 } }, "or": { @@ -1775,6 +2109,12 @@ "timeago_nd_tokens": { "ଆଜି": "0D", "ଗତକାଲି": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "ନିଟି": 6, + "ବିଟି": 9, + "ହଟି": 3 } }, "pa": { @@ -1810,6 +2150,13 @@ "timeago_nd_tokens": { "ਅੱਜ": "0D", "ਬੀੇਤੇ": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "ਅਰਬ": 9, + "ਕਰੋੜ": 7, + "ਲੱਖ": 5, + "ਹਜ਼ਾਰ": 3 } }, "pl": { @@ -1854,6 +2201,12 @@ "timeago_nd_tokens": { "dzisiaj": "0D", "wczoraj": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "mld": 9, + "mln": 6, + "tys": 3 } }, "pt": { @@ -1893,6 +2246,12 @@ "timeago_nd_tokens": { "hoje": "0D", "ontem": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "bi": 9, + "mi": 6, + "mil": 3 } }, "pt-PT": { @@ -1919,6 +2278,11 @@ "timeago_nd_tokens": { "hoje": "0D", "ontem": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "mM": 9, + "mil": 3 } }, "ro": { @@ -1958,6 +2322,11 @@ "timeago_nd_tokens": { "astăzi": "0D", "ieri": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "mil": 6, + "mld": 9 } }, "ru": { @@ -2003,6 +2372,12 @@ "timeago_nd_tokens": { "вчера": "1D", "сегодня": "0D" + }, + "comma_decimal": true, + "number_tokens": { + "млн": 6, + "млрд": 9, + "тыс": 3 } }, "si": { @@ -2036,6 +2411,12 @@ "අද": "0D", "ඊයෙ": "1D", "ඊයේ": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "ද": 3, + "බි": 9, + "මි": 6 } }, "sk": { @@ -2062,6 +2443,12 @@ "timeago_nd_tokens": { "dnes": "0D", "včera": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "mil": 6, + "mld": 9, + "tis": 3 } }, "sl": { @@ -2109,6 +2496,12 @@ "timeago_nd_tokens": { "danes": "0D", "včeraj": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "mio": 6, + "mrd": 9, + "tis": 3 } }, "sq": { @@ -2144,6 +2537,12 @@ "timeago_nd_tokens": { "dje": "1D", "sot": "0D" + }, + "comma_decimal": true, + "number_tokens": { + "mijë": 3, + "mld": 9, + "mln": 6 } }, "sr": { @@ -2172,6 +2571,12 @@ "timeago_nd_tokens": { "данас": "0D", "јуче": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "мил": 6, + "млрд": 9, + "хиљ": 3 } }, "sr-Latn": { @@ -2201,6 +2606,12 @@ "timeago_nd_tokens": { "danas": "0D", "juče": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "hilj": 3, + "mil": 6, + "mlrd": 9 } }, "sv": { @@ -2239,6 +2650,11 @@ "timeago_nd_tokens": { "idag": "0D", "igår": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "md": 9, + "mn": 6 } }, "sw": { @@ -2273,6 +2689,11 @@ "timeago_nd_tokens": { "jana": "1D", "leo": "0D" + }, + "comma_decimal": false, + "number_tokens": { + "B": 9, + "elfu": 3 } }, "ta": { @@ -2311,6 +2732,11 @@ "timeago_nd_tokens": { "இன்று": "0D", "நேற்று": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "கோடி": 7, + "லட்சம்": 5 } }, "te": { @@ -2350,6 +2776,12 @@ "timeago_nd_tokens": { "ఈ": "0D", "నిన్న": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "కోట్లు": 7, + "లక్ష": 5, + "లక్షలు": 5 } }, "th": { @@ -2382,6 +2814,15 @@ "timeago_nd_tokens": { "อัปเดตแล้ววันนี้": "0D", "อัปเดตแล้วเมื่อวาน": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "พัน": 3, + "พันล้าน": 9, + "ล้าน": 6, + "หมื่น": 4, + "หมื่นล้าน": 10, + "แสน": 5 } }, "tr": { @@ -2414,6 +2855,12 @@ "timeago_nd_tokens": { "bugün": "0D", "dün": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "B": 3, + "Mn": 6, + "Mr": 9 } }, "uk": { @@ -2459,6 +2906,12 @@ "timeago_nd_tokens": { "вчора": "1D", "сьогодні": "0D" + }, + "comma_decimal": true, + "number_tokens": { + "млн": 6, + "млрд": 9, + "тис": 3 } }, "ur": { @@ -2497,6 +2950,13 @@ "timeago_nd_tokens": { "آج": "0D", "کل": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "ارب": 9, + "لاکھ": 5, + "کروڑ": 7, + "ہزار": 3 } }, "uz": { @@ -2529,6 +2989,12 @@ "timeago_nd_tokens": { "bugun": "0D", "kecha": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "ming": 3, + "mln": 6, + "mlrd": 9 } }, "vi": { @@ -2549,6 +3015,12 @@ "timeago_nd_tokens": { "nay": "0D", "qua": "1D" + }, + "comma_decimal": true, + "number_tokens": { + "N": 3, + "T": 9, + "Tr": 6 } }, "zh-CN": { @@ -2568,6 +3040,11 @@ "timeago_nd_tokens": { "今": "0D", "日": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "万": 4, + "亿": 8 } }, "zh-HK": { @@ -2588,6 +3065,10 @@ "timeago_nd_tokens": { "今": "0D", "天": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "B": 9 } }, "zh-TW": { @@ -2607,6 +3088,11 @@ "timeago_nd_tokens": { "今": "0D", "天": "1D" + }, + "comma_decimal": false, + "number_tokens": { + "億": 8, + "萬": 4 } }, "zu": { @@ -2646,6 +3132,10 @@ "timeago_nd_tokens": { "izolo": "1D", "namuhla": "0D" + }, + "comma_decimal": false, + "number_tokens": { + "B": 9 } } } diff --git a/testfiles/dict/large_number_samples.json b/testfiles/dict/large_number_samples.json new file mode 100644 index 0000000..6bd67d5 --- /dev/null +++ b/testfiles/dict/large_number_samples.json @@ -0,0 +1,3156 @@ +{ + "af": { + "1": [ + "23 kyke", + 23 + ], + "2": [ + "447 kyke", + 447 + ], + "3": [ + "2,4 k kyke", + 2423 + ], + "4": [ + "22 k kyke", + 22795 + ], + "5": [ + "103 k kyke", + 103450 + ], + "6": [ + "1,4 m kyke", + 1468050 + ], + "8": [ + "135 m kyke", + 135582351 + ], + "9": [ + "1,1 mjd kyke", + 1109851129 + ], + "10": [ + "11 mjd kyke", + 11358400300 + ] + }, + "am": { + "1": [ + "23 ዕይታዎች", + 23 + ], + "2": [ + "447 ዕይታዎች", + 447 + ], + "3": [ + "2.4 ሺ ዕይታዎች", + 2423 + ], + "4": [ + "22 ሺ ዕይታዎች", + 22795 + ], + "5": [ + "103 ሺ ዕይታዎች", + 103450 + ], + "6": [ + "1.4 ሚ ዕይታዎች", + 1468050 + ], + "8": [ + "135 ሚ ዕይታዎች", + 135582351 + ], + "9": [ + "1.1 ቢ ዕይታዎች", + 1109851129 + ], + "10": [ + "11 ቢ ዕይታዎች", + 11358400300 + ] + }, + "ar": { + "1": [ + "23 مشاهدة", + 23 + ], + "2": [ + "447 مشاهدة", + 447 + ], + "3": [ + "2.4 ألف مشاهدة", + 2423 + ], + "4": [ + "22 ألف مشاهدة", + 22795 + ], + "5": [ + "103 ألف مشاهدة", + 103450 + ], + "6": [ + "1.4 مليون مشاهدة", + 1468050 + ], + "8": [ + "135 مليون مشاهدة", + 135582351 + ], + "9": [ + "1.1 مليار مشاهدة", + 1109851129 + ], + "10": [ + "11 مليار مشاهدة", + 11358400300 + ] + }, + "as": { + "1": [ + "23টা ভিউ", + 23 + ], + "2": [ + "447টা ভিউ", + 447 + ], + "3": [ + "2.4 হাজাৰটা ভিউ", + 2423 + ], + "4": [ + "22 হাজাৰটা ভিউ", + 22795 + ], + "5": [ + "1 লাখটা ভিউ", + 103450 + ], + "6": [ + "1.4 নিযুতটা ভিউ", + 1468050 + ], + "8": [ + "135 নিঃটা ভিউ", + 135582351 + ], + "9": [ + "1.1 শঃ কোঃটা ভিউ", + 1109851129 + ], + "10": [ + "11 শঃ কোঃটা ভিউ", + 11358400300 + ] + }, + "az": { + "1": [ + "23 baxış", + 23 + ], + "2": [ + "447 baxış", + 447 + ], + "3": [ + "2,4K baxış", + 2423 + ], + "4": [ + "22K baxış", + 22795 + ], + "5": [ + "103K baxış", + 103450 + ], + "6": [ + "1,4 mln baxış", + 1468050 + ], + "8": [ + "135 mln baxış", + 135582351 + ], + "9": [ + "1,1 mlrd baxış", + 1109851129 + ], + "10": [ + "11 mlrd baxış", + 11358400300 + ] + }, + "be": { + "1": [ + "23 прагляды", + 23 + ], + "2": [ + "447 праглядаў", + 447 + ], + "3": [ + "2,4 тыс. праглядаў", + 2423 + ], + "4": [ + "22 тыс. праглядаў", + 22795 + ], + "5": [ + "103 тыс. праглядаў", + 103450 + ], + "6": [ + "1,4 млн праглядаў", + 1468050 + ], + "8": [ + "135 млн праглядаў", + 135582351 + ], + "9": [ + "1,1 млрд праглядаў", + 1109851129 + ], + "10": [ + "11 млрд праглядаў", + 11358400300 + ] + }, + "bg": { + "1": [ + "23 показвания", + 23 + ], + "2": [ + "447 показвания", + 447 + ], + "3": [ + "2,4 хил. показвания", + 2423 + ], + "4": [ + "22 хил. показвания", + 22795 + ], + "5": [ + "103 хил. показвания", + 103450 + ], + "6": [ + "1,4 млн. показвания", + 1468050 + ], + "8": [ + "135 млн. показвания", + 135582351 + ], + "9": [ + "1,1 млрд. показвания", + 1109851129 + ], + "10": [ + "11 млрд. показвания", + 11358400300 + ] + }, + "bn": { + "1": [ + "23টি ভিউ", + 23 + ], + "2": [ + "447টি ভিউ", + 447 + ], + "3": [ + "2.4 হাটি ভিউ", + 2423 + ], + "4": [ + "22 হাটি ভিউ", + 22795 + ], + "5": [ + "1 লাটি ভিউ", + 103450 + ], + "6": [ + "14 লাটি ভিউ", + 1468050 + ], + "8": [ + "13 কোটি ভিউ", + 135582351 + ], + "9": [ + "110 কোটি ভিউ", + 1109851129 + ], + "10": [ + "11শত কোটি ভিউ", + 11358400300 + ] + }, + "bs": { + "1": [ + "23 pregleda", + 23 + ], + "2": [ + "447 pregleda", + 447 + ], + "3": [ + "2,4 hilj. pregleda", + 2423 + ], + "4": [ + "22 hilj. pregleda", + 22795 + ], + "5": [ + "103 hilj. pregleda", + 103450 + ], + "6": [ + "1,4 mil. pregleda", + 1468050 + ], + "8": [ + "135 mil. pregleda", + 135582351 + ], + "9": [ + "1,1 mlr. pregleda", + 1109852895 + ], + "10": [ + "11 mlr. pregleda", + 11358400300 + ] + }, + "ca": { + "1": [ + "23 visualitzacions", + 23 + ], + "2": [ + "447 visualitzacions", + 447 + ], + "3": [ + "2,4m visualitzacions", + 2423 + ], + "4": [ + "22m visualitzacions", + 22795 + ], + "5": [ + "103m visualitzacions", + 103450 + ], + "6": [ + "1,4 M de visualitzacions", + 1468050 + ], + "8": [ + "135 M de visualitzacions", + 135582351 + ], + "9": [ + "1109 M de visualitzacions", + 1109852895 + ], + "10": [ + "11mM de visualitzacions", + 11358400300 + ] + }, + "cs": { + "1": [ + "23 zhlédnutí", + 23 + ], + "2": [ + "447 zhlédnutí", + 447 + ], + "3": [ + "2,4 tis. zhlédnutí", + 2423 + ], + "4": [ + "22 tis. zhlédnutí", + 22795 + ], + "5": [ + "103 tis. zhlédnutí", + 103450 + ], + "6": [ + "1,4 mil. zhlédnutí", + 1468050 + ], + "8": [ + "135 mil. zhlédnutí", + 135582351 + ], + "9": [ + "1,1 mld. zhlédnutí", + 1109852895 + ], + "10": [ + "11 mld. zhlédnutí", + 11358400300 + ] + }, + "da": { + "1": [ + "23 visninger", + 23 + ], + "2": [ + "447 visninger", + 447 + ], + "3": [ + "2.423 visninger", + 2423 + ], + "4": [ + "22.795 visninger", + 22795 + ], + "5": [ + "103.450 visninger", + 103450 + ], + "6": [ + "1,4 mio. visninger", + 1468050 + ], + "8": [ + "135 mio. visninger", + 135582351 + ], + "9": [ + "1,1 mia. visninger", + 1109852895 + ], + "10": [ + "11 mia. visninger", + 11358400300 + ] + }, + "de": { + "1": [ + "23 Aufrufe", + 23 + ], + "2": [ + "447 Aufrufe", + 447 + ], + "3": [ + "2423 Aufrufe", + 2423 + ], + "4": [ + "22.795 Aufrufe", + 22795 + ], + "5": [ + "103.450 Aufrufe", + 103450 + ], + "6": [ + "1,4 Mio. Aufrufe", + 1468050 + ], + "8": [ + "135 Mio. Aufrufe", + 135582351 + ], + "9": [ + "1,1 Mrd. Aufrufe", + 1109852895 + ], + "10": [ + "11 Mrd. Aufrufe", + 11358400300 + ] + }, + "el": { + "1": [ + "23 προβολές", + 23 + ], + "2": [ + "447 προβολές", + 447 + ], + "3": [ + "2,4 χιλ. προβολές", + 2423 + ], + "4": [ + "22 χιλ. προβολές", + 22795 + ], + "5": [ + "103 χιλ. προβολές", + 103450 + ], + "6": [ + "1,4 εκ. προβολές", + 1468050 + ], + "8": [ + "135 εκ. προβολές", + 135582351 + ], + "9": [ + "1,1 δισ. προβολές", + 1109852895 + ], + "10": [ + "11 δισ. προβολές", + 11358400300 + ] + }, + "en": { + "1": [ + "23 views", + 23 + ], + "2": [ + "447 views", + 447 + ], + "3": [ + "2.4K views", + 2423 + ], + "4": [ + "22K views", + 22795 + ], + "5": [ + "103K views", + 103450 + ], + "6": [ + "1.4M views", + 1468050 + ], + "8": [ + "135M views", + 135582351 + ], + "9": [ + "1.1B views", + 1109852895 + ], + "10": [ + "11B views", + 11358400300 + ] + }, + "en-GB": { + "1": [ + "23 views", + 23 + ], + "2": [ + "447 views", + 447 + ], + "3": [ + "2.4K views", + 2423 + ], + "4": [ + "22K views", + 22795 + ], + "5": [ + "103K views", + 103450 + ], + "6": [ + "1.4M views", + 1468050 + ], + "8": [ + "135M views", + 135582351 + ], + "9": [ + "1.1B views", + 1109852895 + ], + "10": [ + "11B views", + 11358400300 + ] + }, + "en-IN": { + "1": [ + "23 views", + 23 + ], + "2": [ + "447 views", + 447 + ], + "3": [ + "2.4K views", + 2423 + ], + "4": [ + "22K views", + 22795 + ], + "5": [ + "1 lakh views", + 103450 + ], + "6": [ + "14 lakh views", + 1468050 + ], + "8": [ + "13 crore views", + 135582351 + ], + "9": [ + "110 crore views", + 1109852895 + ], + "10": [ + "1.1K crore views", + 11358400300 + ] + }, + "es": { + "1": [ + "23 visualizaciones", + 23 + ], + "2": [ + "447 visualizaciones", + 447 + ], + "3": [ + "2423 visualizaciones", + 2423 + ], + "4": [ + "22.795 visualizaciones", + 22795 + ], + "5": [ + "103.450 visualizaciones", + 103450 + ], + "6": [ + "1,4 M de visualizaciones", + 1468050 + ], + "8": [ + "135 M de visualizaciones", + 135582351 + ], + "9": [ + "1109 M de visualizaciones", + 1109852895 + ], + "10": [ + "11 mil M de visualizaciones", + 11358400300 + ] + }, + "es-419": { + "1": [ + "23 vistas", + 23 + ], + "2": [ + "447 vistas", + 447 + ], + "3": [ + "2,423 vistas", + 2423 + ], + "4": [ + "22,795 vistas", + 22795 + ], + "5": [ + "103,450 vistas", + 103450 + ], + "6": [ + "1.4 M de vistas", + 1468050 + ], + "8": [ + "135 M de vistas", + 135582351 + ], + "9": [ + "1109 M de vistas", + 1109852895 + ], + "10": [ + "11 mil M de vistas", + 11358400300 + ] + }, + "es-US": { + "1": [ + "23 vistas", + 23 + ], + "2": [ + "447 vistas", + 447 + ], + "3": [ + "2.4 K vistas", + 2423 + ], + "4": [ + "22 K vistas", + 22795 + ], + "5": [ + "103 K vistas", + 103450 + ], + "6": [ + "1.4 M de vistas", + 1468050 + ], + "8": [ + "135 M de vistas", + 135582351 + ], + "9": [ + "1109 M de vistas", + 1109852895 + ], + "10": [ + "11 mil M de vistas", + 11358400300 + ] + }, + "et": { + "1": [ + "23 vaatamist", + 23 + ], + "2": [ + "447 vaatamist", + 447 + ], + "3": [ + "2,4 tuh vaatamist", + 2423 + ], + "4": [ + "22 tuh vaatamist", + 22795 + ], + "5": [ + "103 tuh vaatamist", + 103450 + ], + "6": [ + "1,4 mln vaatamist", + 1468050 + ], + "8": [ + "135 mln vaatamist", + 135582351 + ], + "9": [ + "1,1 mld vaatamist", + 1109852895 + ], + "10": [ + "11 mld vaatamist", + 11358400300 + ] + }, + "eu": { + "1": [ + "23 ikustaldi", + 23 + ], + "2": [ + "447 ikustaldi", + 447 + ], + "3": [ + "2423 ikustaldi", + 2423 + ], + "4": [ + "22.795 ikustaldi", + 22795 + ], + "5": [ + "103.450 ikustaldi", + 103450 + ], + "6": [ + "1,4 M ikustaldi", + 1468050 + ], + "8": [ + "135 M ikustaldi", + 135582351 + ], + "9": [ + "1109 M ikustaldi", + 1109852895 + ], + "10": [ + "11.358 M ikustaldi", + 11358400300 + ] + }, + "fa": { + "1": [ + "‏23 بازدید", + 23 + ], + "2": [ + "‏447 بازدید", + 447 + ], + "3": [ + "‏2.4 هزار بازدید", + 2423 + ], + "4": [ + "‏22 هزار بازدید", + 22795 + ], + "5": [ + "‏103 هزار بازدید", + 103450 + ], + "6": [ + "‏1.4 میلیون بازدید", + 1468050 + ], + "8": [ + "‏135 میلیون بازدید", + 135582351 + ], + "9": [ + "‏1.1 میلیارد بازدید", + 1109852895 + ], + "10": [ + "‏11 میلیارد بازدید", + 11358400300 + ] + }, + "fi": { + "1": [ + "23 katselukertaa", + 23 + ], + "2": [ + "447 katselukertaa", + 447 + ], + "3": [ + "2,4 t. katselukertaa", + 2423 + ], + "4": [ + "22 t. katselukertaa", + 22795 + ], + "5": [ + "103 t. katselukertaa", + 103450 + ], + "6": [ + "1,4 milj. katselukertaa", + 1468050 + ], + "8": [ + "135 milj. katselukertaa", + 135582351 + ], + "9": [ + "1,1 mrd. katselukertaa", + 1109852895 + ], + "10": [ + "11 mrd. katselukertaa", + 11358400300 + ] + }, + "fil": { + "1": [ + "23 panonood", + 23 + ], + "2": [ + "447 panonood", + 447 + ], + "3": [ + "2.4K panonood", + 2423 + ], + "4": [ + "22K panonood", + 22795 + ], + "5": [ + "103K panonood", + 103450 + ], + "6": [ + "1.4M panonood", + 1468050 + ], + "8": [ + "135M panonood", + 135582351 + ], + "9": [ + "1.1B panonood", + 1109852895 + ], + "10": [ + "11B panonood", + 11358400300 + ] + }, + "fr": { + "1": [ + "23 vues", + 23 + ], + "2": [ + "447 vues", + 447 + ], + "3": [ + "2,4 k vues", + 2423 + ], + "4": [ + "22 k vues", + 22795 + ], + "5": [ + "103 k vues", + 103450 + ], + "6": [ + "1,4 M de vues", + 1468050 + ], + "8": [ + "135 M de vues", + 135582351 + ], + "9": [ + "1,1 Md de vues", + 1109852895 + ], + "10": [ + "11 Md de vues", + 11358400300 + ] + }, + "fr-CA": { + "1": [ + "23 visionnements", + 23 + ], + "2": [ + "447 visionnements", + 447 + ], + "3": [ + "2,4 k visionnements", + 2423 + ], + "4": [ + "22 k visionnements", + 22795 + ], + "5": [ + "103 k visionnements", + 103450 + ], + "6": [ + "1,4 M de visionnements", + 1468050 + ], + "8": [ + "135 M de visionnements", + 135582351 + ], + "9": [ + "1,1 G de visionnements", + 1109852895 + ], + "10": [ + "11 G de visionnements", + 11358400300 + ] + }, + "gl": { + "1": [ + "23 reproducións", + 23 + ], + "2": [ + "447 reproducións", + 447 + ], + "3": [ + "2423 reproducións", + 2423 + ], + "4": [ + "22.795 reproducións", + 22795 + ], + "5": [ + "103.450 reproducións", + 103450 + ], + "6": [ + "1,4 M reproducións", + 1468050 + ], + "8": [ + "135 M reproducións", + 135582351 + ], + "9": [ + "1109 M reproducións", + 1109852895 + ], + "10": [ + "11.358 M reproducións", + 11358400300 + ] + }, + "gu": { + "1": [ + "23 જોવાયાની સંખ્યા", + 23 + ], + "2": [ + "447 જોવાયાની સંખ્યા", + 447 + ], + "3": [ + "2.4 હજાર જોવાયાની સંખ્યા", + 2423 + ], + "4": [ + "22 હજાર જોવાયાની સંખ્યા", + 22795 + ], + "5": [ + "1 લાખ જોવાયાની સંખ્યા", + 103450 + ], + "6": [ + "14 લાખ જોવાયાની સંખ્યા", + 1468050 + ], + "8": [ + "13 કરોડ જોવાયાની સંખ્યા", + 135582351 + ], + "9": [ + "1.1 અબજ જોવાયાની સંખ્યા", + 1109852895 + ], + "10": [ + "11 અબજ જોવાયાની સંખ્યા", + 11358400300 + ] + }, + "hi": { + "1": [ + "23 बार देखा गया", + 23 + ], + "2": [ + "447 बार देखा गया", + 447 + ], + "3": [ + "2.4 हज़ार बार देखा गया", + 2423 + ], + "4": [ + "22 हज़ार बार देखा गया", + 22795 + ], + "5": [ + "1 लाख बार देखा गया", + 103450 + ], + "6": [ + "14 लाख बार देखा गया", + 1468050 + ], + "8": [ + "13 क॰ बार देखा गया", + 135582351 + ], + "9": [ + "1.1 अ॰ बार देखा गया", + 1109852895 + ], + "10": [ + "11 अ॰ बार देखा गया", + 11358400300 + ] + }, + "hr": { + "1": [ + "23 pregleda", + 23 + ], + "2": [ + "447 pregleda", + 447 + ], + "3": [ + "2,4 tis. pregleda", + 2423 + ], + "4": [ + "22 tis. pregleda", + 22795 + ], + "5": [ + "103 tis. pregleda", + 103450 + ], + "6": [ + "1,4 mil. pregleda", + 1468050 + ], + "8": [ + "135 mil. pregleda", + 135582351 + ], + "9": [ + "1,1 mlr. pregleda", + 1109852895 + ], + "10": [ + "11 mlr. pregleda", + 11358400300 + ] + }, + "hu": { + "1": [ + "23 megtekintés", + 23 + ], + "2": [ + "447 megtekintés", + 447 + ], + "3": [ + "2,4 E megtekintés", + 2423 + ], + "4": [ + "22 E megtekintés", + 22795 + ], + "5": [ + "103 E megtekintés", + 103450 + ], + "6": [ + "1,4 M megtekintés", + 1468050 + ], + "8": [ + "135 M megtekintés", + 135582351 + ], + "9": [ + "1,1 Mrd megtekintés", + 1109852895 + ], + "10": [ + "11 Mrd megtekintés", + 11358400300 + ] + }, + "hy": { + "1": [ + "23 դիտում", + 23 + ], + "2": [ + "447 դիտում", + 447 + ], + "3": [ + "2,4 հզր դիտում", + 2423 + ], + "4": [ + "22 հզր դիտում", + 22795 + ], + "5": [ + "103 հզր դիտում", + 103450 + ], + "6": [ + "1,4 մլն դիտում", + 1468050 + ], + "8": [ + "135 մլն դիտում", + 135582351 + ], + "9": [ + "1,1 մլրդ դիտում", + 1109852895 + ], + "10": [ + "11 մլրդ դիտում", + 11358400300 + ] + }, + "id": { + "1": [ + "23 x ditonton", + 23 + ], + "2": [ + "447 x ditonton", + 447 + ], + "3": [ + "2,4 rb x ditonton", + 2423 + ], + "4": [ + "22 rb x ditonton", + 22795 + ], + "5": [ + "103 rb x ditonton", + 103450 + ], + "6": [ + "1,4 jt x ditonton", + 1468050 + ], + "8": [ + "135 jt x ditonton", + 135582351 + ], + "9": [ + "1,1 M x ditonton", + 1109852895 + ], + "10": [ + "11 M x ditonton", + 11358400300 + ] + }, + "is": { + "1": [ + "23 áhorf", + 23 + ], + "2": [ + "447 áhorf", + 447 + ], + "3": [ + "2,4 þ. áhorf", + 2423 + ], + "4": [ + "22 þ. áhorf", + 22795 + ], + "5": [ + "103 þ. áhorf", + 103450 + ], + "6": [ + "1,4 m. áhorf", + 1468050 + ], + "8": [ + "135 m. áhorf", + 135582351 + ], + "9": [ + "1,1 ma. áhorf", + 1109852895 + ], + "10": [ + "11 ma. áhorf", + 11358400300 + ] + }, + "it": { + "1": [ + "23 visualizzazioni", + 23 + ], + "2": [ + "447 visualizzazioni", + 447 + ], + "3": [ + "2423 visualizzazioni", + 2423 + ], + "4": [ + "22.795 visualizzazioni", + 22795 + ], + "5": [ + "103.450 visualizzazioni", + 103450 + ], + "6": [ + "1,4 Mln di visualizzazioni", + 1468050 + ], + "8": [ + "135 Mln di visualizzazioni", + 135582351 + ], + "9": [ + "1,1 Mrd di visualizzazioni", + 1109852895 + ], + "10": [ + "11 Mrd di visualizzazioni", + 11358400300 + ] + }, + "iw": { + "1": [ + "‫23‬ צפיות", + 23 + ], + "2": [ + "‫447‬ צפיות", + 447 + ], + "3": [ + "‫2.4K‏‬ צפיות", + 2423 + ], + "4": [ + "‫22K‏‬ צפיות", + 22795 + ], + "5": [ + "‫103K‏‬ צפיות", + 103450 + ], + "6": [ + "‫1.4M‏‬ צפיות", + 1468050 + ], + "8": [ + "‫135M‏‬ צפיות", + 135582351 + ], + "9": [ + "‫1.1B‏‬ צפיות", + 1109852895 + ], + "10": [ + "‫11B‏‬ צפיות", + 11358400300 + ] + }, + "ja": { + "1": [ + "23 回視聴", + 23 + ], + "2": [ + "447 回視聴", + 447 + ], + "3": [ + "2423 回視聴", + 2423 + ], + "4": [ + "2.2万 回視聴", + 22795 + ], + "5": [ + "10万 回視聴", + 103450 + ], + "6": [ + "146万 回視聴", + 1468050 + ], + "8": [ + "1.3億 回視聴", + 135582351 + ], + "9": [ + "11億 回視聴", + 1109852895 + ], + "10": [ + "113億 回視聴", + 11358400300 + ] + }, + "ka": { + "1": [ + "23 ნახვა", + 23 + ], + "2": [ + "447 ნახვა", + 447 + ], + "3": [ + "2,4 ათ. ნახვა", + 2423 + ], + "4": [ + "22 ათ. ნახვა", + 22795 + ], + "5": [ + "103 ათ. ნახვა", + 103450 + ], + "6": [ + "1,4 მლნ. ნახვა", + 1468050 + ], + "8": [ + "135 მლნ. ნახვა", + 135582351 + ], + "9": [ + "1,1 მლრდ. ნახვა", + 1109852895 + ], + "10": [ + "11 მლრდ. ნახვა", + 11358400300 + ] + }, + "kk": { + "1": [ + "23 рет көрілді", + 23 + ], + "2": [ + "447 рет көрілді", + 447 + ], + "3": [ + "2,4 мың рет көрілді", + 2423 + ], + "4": [ + "22 мың рет көрілді", + 22795 + ], + "5": [ + "103 м. рет көрілді", + 103450 + ], + "6": [ + "1,4 млн рет көрілді", + 1468050 + ], + "8": [ + "135 млн рет көрілді", + 135582351 + ], + "9": [ + "1,1 млрд рет көрілді", + 1109852895 + ], + "10": [ + "11 млрд рет көрілді", + 11358400300 + ] + }, + "km": { + "1": [ + "ចំនួនមើល 23", + 23 + ], + "2": [ + "ចំនួនមើល 447", + 447 + ], + "3": [ + "ចំនួនមើល 2,4ពាន់", + 2423 + ], + "4": [ + "ចំនួនមើល 22 ពាន់", + 22795 + ], + "5": [ + "ចំនួនមើល 103 ពាន់", + 103450 + ], + "6": [ + "ចំនួនមើល 1,4 លាន", + 1468050 + ], + "8": [ + "ចំនួនមើល 135 លាន", + 135582351 + ], + "9": [ + "ចំនួនមើល 1,1 ប៊ីលាន", + 1109852895 + ], + "10": [ + "ចំនួនមើល 11 ប៊ីលាន", + 11358400300 + ] + }, + "kn": { + "1": [ + "23 ವೀಕ್ಷಣೆಗಳು", + 23 + ], + "2": [ + "447 ವೀಕ್ಷಣೆಗಳು", + 447 + ], + "3": [ + "2,423 ವೀಕ್ಷಣೆಗಳು", + 2423 + ], + "4": [ + "22,795 ವೀಕ್ಷಣೆಗಳು", + 22795 + ], + "5": [ + "1 ಲಕ್ಷ ವೀಕ್ಷಣೆಗಳು", + 103450 + ], + "6": [ + "14 ಲಕ್ಷ ವೀಕ್ಷಣೆಗಳು", + 1468050 + ], + "8": [ + "13 ಕೋಟಿ ವೀಕ್ಷಣೆಗಳು", + 135582351 + ], + "9": [ + "110 ಕೋಟಿ ವೀಕ್ಷಣೆಗಳು", + 1109852895 + ], + "10": [ + "1,135 ಕೋಟಿ ವೀಕ್ಷಣೆಗಳು", + 11358400300 + ] + }, + "ko": { + "1": [ + "조회수 23회", + 23 + ], + "2": [ + "조회수 447회", + 447 + ], + "3": [ + "조회수 2.4천회", + 2423 + ], + "4": [ + "조회수 2.2만회", + 22795 + ], + "5": [ + "조회수 10만회", + 103450 + ], + "6": [ + "조회수 146만회", + 1468050 + ], + "8": [ + "조회수 1.3억회", + 135582351 + ], + "9": [ + "조회수 11억회", + 1109852895 + ], + "10": [ + "조회수 113억회", + 11358400300 + ] + }, + "ky": { + "1": [ + "23 жолу көрүлдү", + 23 + ], + "2": [ + "447 жолу көрүлдү", + 447 + ], + "3": [ + "2,4 миң жолу көрүлдү", + 2423 + ], + "4": [ + "22 миң жолу көрүлдү", + 22795 + ], + "5": [ + "103 миң жолу көрүлдү", + 103450 + ], + "6": [ + "1,4 млн жолу көрүлдү", + 1468050 + ], + "8": [ + "135 млн жолу көрүлдү", + 135582351 + ], + "9": [ + "1,1 млд жолу көрүлдү", + 1109852895 + ], + "10": [ + "11 млд жолу көрүлдү", + 11358400300 + ] + }, + "lo": { + "1": [ + "ຍອດເບິ່ງ 23 ເທື່ອ", + 23 + ], + "2": [ + "ຍອດເບິ່ງ 447 ເທື່ອ", + 447 + ], + "3": [ + "ຍອດເບິ່ງ 2,4 ພັນ ເທື່ອ", + 2423 + ], + "4": [ + "ຍອດເບິ່ງ 22 ພັນ ເທື່ອ", + 22795 + ], + "5": [ + "ຍອດເບິ່ງ 103 ກີບ ເທື່ອ", + 103450 + ], + "6": [ + "ຍອດເບິ່ງ 1,4 ລ້ານ ເທື່ອ", + 1468050 + ], + "8": [ + "ຍອດເບິ່ງ 135 ລ້ານ ເທື່ອ", + 135582351 + ], + "9": [ + "ຍອດເບິ່ງ 1,1 ຕື້ ເທື່ອ", + 1109852895 + ], + "10": [ + "ຍອດເບິ່ງ 11 ຕື້ ເທື່ອ", + 11358400300 + ] + }, + "lt": { + "1": [ + "23 views", + 23 + ], + "2": [ + "447 views", + 447 + ], + "3": [ + "2,4 tūkst. peržiūrų", + 2423 + ], + "4": [ + "22 tūkst. peržiūrų", + 22795 + ], + "5": [ + "103 tūkst. peržiūrų", + 103450 + ], + "6": [ + "1,4 mln. peržiūrų", + 1468050 + ], + "8": [ + "135 mln. peržiūrų", + 135582351 + ], + "9": [ + "1,1 mlrd. peržiūrų", + 1109852895 + ], + "10": [ + "11 mlrd. peržiūrų", + 11358400300 + ] + }, + "lv": { + "1": [ + "23 skatījumi", + 23 + ], + "2": [ + "447 skatījumi", + 447 + ], + "3": [ + "2,4 tūkst. skatījumu", + 2423 + ], + "4": [ + "22 tūkst. skatījumu", + 22795 + ], + "5": [ + "103 tūkst. skatījumu", + 103450 + ], + "6": [ + "1,4 milj. skatījumu", + 1468050 + ], + "8": [ + "135 milj. skatījumu", + 135582351 + ], + "9": [ + "1,1 mljrd. skatījumu", + 1109852895 + ], + "10": [ + "11 mljrd. skatījumu", + 11358400300 + ] + }, + "mk": { + "1": [ + "23 прегледи", + 23 + ], + "2": [ + "447 прегледи", + 447 + ], + "3": [ + "2,4 илј. прегледи", + 2423 + ], + "4": [ + "22 илј. прегледи", + 22795 + ], + "5": [ + "103 илј. прегледи", + 103450 + ], + "6": [ + "1,4 мил. прегледи", + 1468050 + ], + "8": [ + "135 М прегледи", + 135582351 + ], + "9": [ + "1,1 милј. прегледи", + 1109852895 + ], + "10": [ + "11 милј. прегледи", + 11358400300 + ] + }, + "ml": { + "1": [ + "23 കാഴ്‌ച", + 23 + ], + "2": [ + "447 കാഴ്‌ച", + 447 + ], + "3": [ + "2,423 കാഴ്‌ച", + 2423 + ], + "4": [ + "22,795 കാഴ്‌ച", + 22795 + ], + "5": [ + "1 ലക്ഷം കാഴ്‌ച", + 103450 + ], + "6": [ + "14 ലക്ഷം കാഴ്‌ച", + 1468050 + ], + "8": [ + "13 കോടി കാഴ്‌ച", + 135582351 + ], + "9": [ + "110 കോടി കാഴ്‌ച", + 1109852895 + ], + "10": [ + "1,135 കോടി കാഴ്‌ച", + 11358400300 + ] + }, + "mn": { + "1": [ + "23 үзэлт", + 23 + ], + "2": [ + "447 үзэлт", + 447 + ], + "3": [ + "2.4 мянга үзэлт", + 2423 + ], + "4": [ + "22 мянга үзэлт", + 22795 + ], + "5": [ + "103 мянга үзэлт", + 103450 + ], + "6": [ + "1.4 сая үзэлт", + 1468050 + ], + "8": [ + "135 сая үзэлт", + 135582351 + ], + "9": [ + "1.1 тэрбум үзэлт", + 1109852895 + ], + "10": [ + "11 тэрбум үзэлт", + 11358400300 + ] + }, + "mr": { + "1": [ + "23 व्ह्यू", + 23 + ], + "2": [ + "447 व्ह्यू", + 447 + ], + "3": [ + "2.4 ह व्ह्यू", + 2423 + ], + "4": [ + "22 ह व्ह्यू", + 22795 + ], + "5": [ + "1 लाख व्ह्यू", + 103450 + ], + "6": [ + "14 लाख व्ह्यू", + 1468050 + ], + "8": [ + "13 कोटी व्ह्यू", + 135582351 + ], + "9": [ + "1.1 अब्ज व्ह्यू", + 1109852895 + ], + "10": [ + "11 अब्ज व्ह्यू", + 11358400300 + ] + }, + "ms": { + "1": [ + "23 tontonan", + 23 + ], + "2": [ + "447 tontonan", + 447 + ], + "3": [ + "2.4K tontonan", + 2423 + ], + "4": [ + "22K tontonan", + 22795 + ], + "5": [ + "103K tontonan", + 103450 + ], + "6": [ + "1.4J tontonan", + 1468050 + ], + "8": [ + "135J tontonan", + 135582351 + ], + "9": [ + "1.1B tontonan", + 1109852895 + ], + "10": [ + "11B tontonan", + 11358400300 + ] + }, + "my": { + "1": [ + "ကြည့်ရှုမှု 23", + 23 + ], + "2": [ + "ကြည့်ရှုမှု 447", + 447 + ], + "3": [ + "ကြည့်ရှုမှု 2.4ထောင်", + 2423 + ], + "4": [ + "ကြည့်ရှုမှု 2.2သောင်း", + 22795 + ], + "5": [ + "ကြည့်ရှုမှု 1သိန်း", + 103450 + ], + "6": [ + "ကြည့်ရှုမှု 1.4သန်း", + 1468050 + ], + "8": [ + "ကြည့်ရှုမှု 13ကုဋေ", + 135582351 + ], + "9": [ + "ကြည့်ရှုမှု ကုဋေ110", + 1109852895 + ], + "10": [ + "ကြည့်ရှုမှု ကုဋေ1.1ထ", + 11358400300 + ] + }, + "ne": { + "1": [ + "23 भ्यु", + 23 + ], + "2": [ + "447 भ्यु", + 447 + ], + "3": [ + "2.4 हजार भ्यु", + 2423 + ], + "4": [ + "22 हजार भ्यु", + 22795 + ], + "5": [ + "1 लाख भ्यु", + 103450 + ], + "6": [ + "14 लाख भ्यु", + 1468050 + ], + "8": [ + "13 करोड भ्यु", + 135582351 + ], + "9": [ + "1.1 अरब भ्यु", + 1109852895 + ], + "10": [ + "11 अरब भ्यु", + 11358400300 + ] + }, + "nl": { + "1": [ + "23 weergaven", + 23 + ], + "2": [ + "447 weergaven", + 447 + ], + "3": [ + "2,4K weergaven", + 2423 + ], + "4": [ + "22K weergaven", + 22795 + ], + "5": [ + "103K weergaven", + 103450 + ], + "6": [ + "1,4 mln. weergaven", + 1468050 + ], + "8": [ + "135 mln. weergaven", + 135582351 + ], + "9": [ + "1,1 mld. weergaven", + 1109852895 + ], + "10": [ + "11 mld. weergaven", + 11358400300 + ] + }, + "no": { + "1": [ + "Sett 23 ganger", + 23 + ], + "2": [ + "Sett 447 ganger", + 447 + ], + "3": [ + "Sett 2,4k ganger", + 2423 + ], + "4": [ + "Sett 22k ganger", + 22795 + ], + "5": [ + "Sett 103k ganger", + 103450 + ], + "6": [ + "Sett 1,4 mill. ganger", + 1468050 + ], + "8": [ + "Sett 135 mill. ganger", + 135582351 + ], + "9": [ + "Sett 1,1 mrd. ganger", + 1109852895 + ], + "10": [ + "Sett 11 mrd. ganger", + 11358400300 + ] + }, + "or": { + "1": [ + "23ଟି ଭ୍ୟୁ", + 23 + ], + "2": [ + "447ଟି ଭ୍ୟୁ", + 447 + ], + "3": [ + "2.4ହଟି ଭ୍ୟୁ", + 2423 + ], + "4": [ + "22ହଟି ଭ୍ୟୁ", + 22795 + ], + "5": [ + "103ହଟି ଭ୍ୟୁ", + 103450 + ], + "6": [ + "1.4ନିଟି ଭ୍ୟୁ", + 1468050 + ], + "8": [ + "135ନିଟି ଭ୍ୟୁ", + 135582351 + ], + "9": [ + "1.1ବିଟି ଭ୍ୟୁ", + 1109852895 + ], + "10": [ + "11ବିଟି ଭ୍ୟୁ", + 11358400300 + ] + }, + "pa": { + "1": [ + "23 ਵਾਰ ਦੇਖਿਆ", + 23 + ], + "2": [ + "447 ਵਾਰ ਦੇਖਿਆ", + 447 + ], + "3": [ + "2.4 ਹਜ਼ਾਰ ਵਾਰ ਦੇਖਿਆ", + 2423 + ], + "4": [ + "22 ਹਜ਼ਾਰ ਵਾਰ ਦੇਖਿਆ", + 22795 + ], + "5": [ + "1 ਲੱਖ ਵਾਰ ਦੇਖਿਆ", + 103450 + ], + "6": [ + "14 ਲੱਖ ਵਾਰ ਦੇਖਿਆ", + 1468050 + ], + "8": [ + "13 ਕਰੋੜ ਵਾਰ ਦੇਖਿਆ", + 135582351 + ], + "9": [ + "1.1 ਅਰਬ ਵਾਰ ਦੇਖਿਆ", + 1109852895 + ], + "10": [ + "11 ਅਰਬ ਵਾਰ ਦੇਖਿਆ", + 11358400300 + ] + }, + "pl": { + "1": [ + "23 wyświetlenia", + 23 + ], + "2": [ + "447 wyświetleń", + 447 + ], + "3": [ + "2,4 tys. wyświetleń", + 2423 + ], + "4": [ + "22 tys. wyświetleń", + 22795 + ], + "5": [ + "103 tys. wyświetleń", + 103450 + ], + "6": [ + "1,4 mln wyświetleń", + 1468050 + ], + "8": [ + "135 mln wyświetleń", + 135582351 + ], + "9": [ + "1,1 mld wyświetleń", + 1109852895 + ], + "10": [ + "11 mld wyświetleń", + 11358400300 + ] + }, + "pt": { + "1": [ + "23 visualizações", + 23 + ], + "2": [ + "447 visualizações", + 447 + ], + "3": [ + "2,4 mil visualizações", + 2423 + ], + "4": [ + "22 mil visualizações", + 22795 + ], + "5": [ + "103 mil visualizações", + 103450 + ], + "6": [ + "1,4 mi de visualizações", + 1468050 + ], + "8": [ + "135 mi de visualizações", + 135582351 + ], + "9": [ + "1,1 bi de visualizações", + 1109852895 + ], + "10": [ + "11 bi de visualizações", + 11358400300 + ] + }, + "pt-PT": { + "1": [ + "23 visualizações", + 23 + ], + "2": [ + "447 visualizações", + 447 + ], + "3": [ + "2,4 mil visualizações", + 2423 + ], + "4": [ + "22 mil visualizações", + 22795 + ], + "5": [ + "103 mil visualizações", + 103450 + ], + "6": [ + "1,4 M de visualizações", + 1468050 + ], + "8": [ + "135 M de visualizações", + 135582351 + ], + "9": [ + "1,1 mM de visualizações", + 1109852895 + ], + "10": [ + "11 mM de visualizações", + 11358400300 + ] + }, + "ro": { + "1": [ + "23 de vizionări", + 23 + ], + "2": [ + "447 de vizionări", + 447 + ], + "3": [ + "2,4 K de vizionări", + 2423 + ], + "4": [ + "22 K de vizionări", + 22795 + ], + "5": [ + "103 K de vizionări", + 103450 + ], + "6": [ + "1,4 mil. de vizionări", + 1468050 + ], + "8": [ + "135 mil. de vizionări", + 135582351 + ], + "9": [ + "1,1 mld. de vizionări", + 1109852895 + ], + "10": [ + "11 mld. de vizionări", + 11358400300 + ] + }, + "ru": { + "1": [ + "23 просмотра", + 23 + ], + "2": [ + "447 просмотров", + 447 + ], + "3": [ + "2,4 тыс. просмотров", + 2423 + ], + "4": [ + "22 тыс. просмотров", + 22795 + ], + "5": [ + "103 тыс. просмотров", + 103450 + ], + "6": [ + "1,4 млн просмотров", + 1468050 + ], + "8": [ + "135 млн просмотров", + 135582351 + ], + "9": [ + "1,1 млрд просмотров", + 1109852895 + ], + "10": [ + "11 млрд просмотров", + 11358400300 + ] + }, + "si": { + "1": [ + "බැලීම් 23", + 23 + ], + "2": [ + "බැලීම් 447", + 447 + ], + "3": [ + "බැලීම් ද2.4", + 2423 + ], + "4": [ + "බැලීම් ද22", + 22795 + ], + "5": [ + "බැලීම් ද103", + 103450 + ], + "6": [ + "බැලීම් මි1.4", + 1468050 + ], + "8": [ + "බැලීම් මි135", + 135582429 + ], + "9": [ + "බැලීම් බි1.1", + 1109852895 + ], + "10": [ + "බැලීම් බි11", + 11358400300 + ] + }, + "sk": { + "1": [ + "23 zhliadnutí", + 23 + ], + "2": [ + "447 zhliadnutí", + 447 + ], + "3": [ + "2,4 tis. zhliadnutí", + 2423 + ], + "4": [ + "22 tis. zhliadnutí", + 22795 + ], + "5": [ + "103 tis. zhliadnutí", + 103450 + ], + "6": [ + "1,4 mil. zhliadnutí", + 1468050 + ], + "8": [ + "135 mil. zhliadnutí", + 135582429 + ], + "9": [ + "1,1 mld. zhliadnutí", + 1109852895 + ], + "10": [ + "11 mld. zhliadnutí", + 11358400300 + ] + }, + "sl": { + "1": [ + "23 ogledov", + 23 + ], + "2": [ + "447 ogledov", + 447 + ], + "3": [ + "2,4 tis. ogledov", + 2423 + ], + "4": [ + "22 tis. ogledov", + 22795 + ], + "5": [ + "103 tis. ogledov", + 103450 + ], + "6": [ + "1,4 mio. ogledov", + 1468050 + ], + "8": [ + "135 mio. ogledov", + 135582429 + ], + "9": [ + "1,1 mrd. ogledov", + 1109852895 + ], + "10": [ + "11 mrd. ogledov", + 11358400300 + ] + }, + "sq": { + "1": [ + "23 shikime", + 23 + ], + "2": [ + "447 shikime", + 447 + ], + "3": [ + "2,4 mijë shikime", + 2423 + ], + "4": [ + "22 mijë shikime", + 22795 + ], + "5": [ + "103 mijë shikime", + 103450 + ], + "6": [ + "1,4 mln shikime", + 1468050 + ], + "8": [ + "135 mln shikime", + 135582429 + ], + "9": [ + "1,1 mld shikime", + 1109852895 + ], + "10": [ + "11 mld shikime", + 11358400300 + ] + }, + "sr": { + "1": [ + "23 прегледа", + 23 + ], + "2": [ + "447 приказа", + 447 + ], + "3": [ + "2,4 хиљ. приказа", + 2423 + ], + "4": [ + "22 хиљ. приказа", + 22795 + ], + "5": [ + "103 хиљ. приказа", + 103450 + ], + "6": [ + "1,4 мил. приказа", + 1468050 + ], + "8": [ + "135 мил. приказа", + 135582429 + ], + "9": [ + "1,1 млрд. приказа", + 1109852895 + ], + "10": [ + "11 млрд. приказа", + 11358400300 + ] + }, + "sr-Latn": { + "1": [ + "23 pregleda", + 23 + ], + "2": [ + "447 prikaza", + 447 + ], + "3": [ + "2,4 hilj. prikaza", + 2423 + ], + "4": [ + "22 hilj. prikaza", + 22795 + ], + "5": [ + "103 hilj. prikaza", + 103450 + ], + "6": [ + "1,4 mil. prikaza", + 1468050 + ], + "8": [ + "135 mil. prikaza", + 135582429 + ], + "9": [ + "1,1 mlrd. prikaza", + 1109852895 + ], + "10": [ + "11 mlrd. prikaza", + 11358400300 + ] + }, + "sv": { + "1": [ + "23 visningar", + 23 + ], + "2": [ + "447 visningar", + 447 + ], + "3": [ + "2 423 visningar", + 2423 + ], + "4": [ + "22 795 visningar", + 22795 + ], + "5": [ + "103 450 visningar", + 103450 + ], + "6": [ + "1,4 mn visningar", + 1468050 + ], + "8": [ + "135 mn visningar", + 135582429 + ], + "9": [ + "1,1 md visningar", + 1109852895 + ], + "10": [ + "11 md visningar", + 11358400300 + ] + }, + "sw": { + "1": [ + "Kutazamwa:\n23", + 23 + ], + "2": [ + "Kutazamwa:\n447", + 447 + ], + "3": [ + "Kutazamwa:\nelfu 2.4", + 2423 + ], + "4": [ + "Kutazamwa:\nelfu 22", + 22795 + ], + "5": [ + "Kutazamwa:\nelfu 103", + 103450 + ], + "6": [ + "Kutazamwa:\n1.4M", + 1468050 + ], + "8": [ + "Kutazamwa:\n135M", + 135582429 + ], + "9": [ + "Kutazamwa:\n1.1B", + 1109852895 + ], + "10": [ + "Kutazamwa:\n11B", + 11358400300 + ] + }, + "ta": { + "1": [ + "23 பார்வைகள்", + 23 + ], + "2": [ + "447 பார்வைகள்", + 447 + ], + "3": [ + "2,423 பார்வைகள்", + 2423 + ], + "4": [ + "22,795 பார்வைகள்", + 22795 + ], + "5": [ + "1 லட்சம் பார்வைகள்", + 103450 + ], + "6": [ + "14 லட்சம் பார்வைகள்", + 1468050 + ], + "8": [ + "13 கோடி பார்வைகள்", + 135582429 + ], + "9": [ + "110 கோடி பார்வைகள்", + 1109852895 + ], + "10": [ + "1,135 கோடி பார்வைகள்", + 11358400300 + ] + }, + "te": { + "1": [ + "23 వీక్షణలు", + 23 + ], + "2": [ + "447 వీక్షణలు", + 447 + ], + "3": [ + "2,423 వీక్షణలు", + 2423 + ], + "4": [ + "22,795 వీక్షణలు", + 22795 + ], + "5": [ + "1 లక్ష వీక్షణలు", + 103450 + ], + "6": [ + "14 లక్షలు వీక్షణలు", + 1468050 + ], + "8": [ + "13 కోట్లు వీక్షణలు", + 135582429 + ], + "9": [ + "110 కోట్లు వీక్షణలు", + 1109852895 + ], + "10": [ + "1,135 కోట్లు వీక్షణలు", + 11358400300 + ] + }, + "th": { + "1": [ + "การดู 23 ครั้ง", + 23 + ], + "2": [ + "การดู 447 ครั้ง", + 447 + ], + "3": [ + "การดู 2.4 พัน ครั้ง", + 2423 + ], + "4": [ + "การดู 2.2 หมื่น ครั้ง", + 22795 + ], + "5": [ + "การดู 1 แสน ครั้ง", + 103450 + ], + "6": [ + "การดู 1.4 ล้าน ครั้ง", + 1468050 + ], + "8": [ + "การดู 135 ล้าน ครั้ง", + 135582429 + ], + "9": [ + "การดู 1.1 พันล้าน ครั้ง", + 1109852895 + ], + "10": [ + "การดู 1.1 หมื่นล้าน ครั้ง", + 11358400300 + ] + }, + "tr": { + "1": [ + "23 görüntüleme", + 23 + ], + "2": [ + "447 görüntüleme", + 447 + ], + "3": [ + "2,4 B görüntüleme", + 2423 + ], + "4": [ + "22 B görüntüleme", + 22795 + ], + "5": [ + "103 B görüntüleme", + 103450 + ], + "6": [ + "1,4 Mn görüntüleme", + 1468050 + ], + "8": [ + "135 Mn görüntüleme", + 135582429 + ], + "9": [ + "1,1 Mr görüntüleme", + 1109852895 + ], + "10": [ + "11 Mr görüntüleme", + 11358400300 + ] + }, + "uk": { + "1": [ + "23 перегляди", + 23 + ], + "2": [ + "447 переглядів", + 447 + ], + "3": [ + "2,4 тис. переглядів", + 2423 + ], + "4": [ + "22 тис. переглядів", + 22795 + ], + "5": [ + "103 тис. переглядів", + 103450 + ], + "6": [ + "1,4 млн переглядів", + 1468050 + ], + "8": [ + "135 млн переглядів", + 135582429 + ], + "9": [ + "1,1 млрд переглядів", + 1109852895 + ], + "10": [ + "11 млрд переглядів", + 11358400300 + ] + }, + "ur": { + "1": [ + "23 ملاحظات", + 23 + ], + "2": [ + "447 ملاحظات", + 447 + ], + "3": [ + "2.4 ہزار ملاحظات", + 2423 + ], + "4": [ + "22 ہزار ملاحظات", + 22795 + ], + "5": [ + "1 لاکھ ملاحظات", + 103450 + ], + "6": [ + "14 لاکھ ملاحظات", + 1468050 + ], + "8": [ + "13 کروڑ ملاحظات", + 135582429 + ], + "9": [ + "1.1 ارب ملاحظات", + 1109852895 + ], + "10": [ + "11 ارب ملاحظات", + 11358400300 + ] + }, + "uz": { + "1": [ + "23 marta", + 23 + ], + "2": [ + "447 marta", + 447 + ], + "3": [ + "2,4 ming marta", + 2423 + ], + "4": [ + "22 ming marta", + 22795 + ], + "5": [ + "103 ming marta", + 103450 + ], + "6": [ + "1,4 mln marta", + 1468050 + ], + "8": [ + "135 mln marta", + 135582429 + ], + "9": [ + "1,1 mlrd marta", + 1109852895 + ], + "10": [ + "11 mlrd marta", + 11358400300 + ] + }, + "vi": { + "1": [ + "23 lượt xem", + 23 + ], + "2": [ + "447 lượt xem", + 447 + ], + "3": [ + "2,4 N lượt xem", + 2423 + ], + "4": [ + "22 N lượt xem", + 22795 + ], + "5": [ + "103 N lượt xem", + 103450 + ], + "6": [ + "1,4 Tr lượt xem", + 1468050 + ], + "8": [ + "135 Tr lượt xem", + 135582429 + ], + "9": [ + "1,1 T lượt xem", + 1109852895 + ], + "10": [ + "11 T lượt xem", + 11358400300 + ] + }, + "zh-CN": { + "1": [ + "23次观看", + 23 + ], + "2": [ + "447次观看", + 447 + ], + "3": [ + "2423次观看", + 2423 + ], + "4": [ + "2.2万次观看", + 22795 + ], + "5": [ + "10万次观看", + 103450 + ], + "6": [ + "146万次观看", + 1468050 + ], + "8": [ + "1.3亿次观看", + 135582429 + ], + "9": [ + "11亿次观看", + 1109853150 + ], + "10": [ + "113亿次观看", + 11358400300 + ] + }, + "zh-HK": { + "1": [ + "收看次數:23 次", + 23 + ], + "2": [ + "收看次數:447 次", + 447 + ], + "3": [ + "收看次數:2.4K 次", + 2423 + ], + "4": [ + "收看次數:22K 次", + 22795 + ], + "5": [ + "收看次數:103K 次", + 103450 + ], + "6": [ + "收看次數:1.4M 次", + 1468050 + ], + "8": [ + "收看次數:135M 次", + 135582429 + ], + "9": [ + "收看次數:1.1B 次", + 1109853150 + ], + "10": [ + "收看次數:11B 次", + 11358400300 + ] + }, + "zh-TW": { + "1": [ + "觀看次數:23次", + 23 + ], + "2": [ + "觀看次數:447次", + 447 + ], + "3": [ + "觀看次數:2423次", + 2423 + ], + "4": [ + "觀看次數:2.2萬次", + 22795 + ], + "5": [ + "觀看次數:10萬次", + 103450 + ], + "6": [ + "觀看次數:146萬次", + 1468050 + ], + "8": [ + "觀看次數:1.3億次", + 135582429 + ], + "9": [ + "觀看次數:11億次", + 1109853150 + ], + "10": [ + "觀看次數:113億次", + 11358400300 + ] + }, + "zu": { + "1": [ + "23 ukubukwa", + 23 + ], + "2": [ + "447 ukubukwa", + 447 + ], + "3": [ + "2.4K ukubukwa", + 2423 + ], + "4": [ + "22K ukubukwa", + 22795 + ], + "5": [ + "103K ukubukwa", + 103450 + ], + "6": [ + "1.4M ukubukwa", + 1468050 + ], + "8": [ + "135M ukubukwa", + 135582429 + ], + "9": [ + "1.1B ukubukwa", + 1109853150 + ], + "10": [ + "11B ukubukwa", + 11358400300 + ] + } +} diff --git a/testfiles/date/playlist_samples.json b/testfiles/dict/playlist_samples.json similarity index 100% rename from testfiles/date/playlist_samples.json rename to testfiles/dict/playlist_samples.json diff --git a/testfiles/date/timeago_samples.json b/testfiles/dict/timeago_samples.json similarity index 100% rename from testfiles/date/timeago_samples.json rename to testfiles/dict/timeago_samples.json diff --git a/testfiles/date/timeago_table.json b/testfiles/dict/timeago_table.json similarity index 100% rename from testfiles/date/timeago_table.json rename to testfiles/dict/timeago_table.json