fix: parsing history dates

This commit is contained in:
ThetaDev 2025-01-18 05:51:41 +01:00
parent 32fda234e4
commit af7dc10163
No known key found for this signature in database
GPG key ID: E319D3C5148D65B6
10 changed files with 2084 additions and 429 deletions

View file

@ -5,26 +5,25 @@ use rustypipe::{
client::RustyPipe,
param::{Language, LANGUAGES},
};
use serde::{Deserialize, Serialize};
use crate::util::{self, DICT_DIR};
type CollectedDates = BTreeMap<Language, HistoryDates>;
type CollectedDates = BTreeMap<Language, BTreeMap<String, String>>;
#[derive(Debug, Serialize, Deserialize)]
struct HistoryDates {
this_week: String,
last_week: String,
}
const THIS_WEEK: &str = "this_week";
const LAST_WEEK: &str = "last_week";
pub async fn collect_dates() {
pub async fn collect_dates_music() {
let json_path = path!(*DICT_DIR / "history_date_samples.json");
let rp = RustyPipe::builder()
.storage_dir("/home/thetadev/Documents/Programmieren/Rust/rustypipe")
.storage_dir(path!(env!("CARGO_MANIFEST_DIR") / ".."))
.build()
.unwrap();
let mut res: CollectedDates = BTreeMap::new();
let mut res: CollectedDates = {
let json_file = File::open(&json_path).unwrap();
serde_json::from_reader(BufReader::new(json_file)).unwrap()
};
for lang in LANGUAGES {
println!("{lang}");
@ -34,14 +33,56 @@ pub async fn collect_dates() {
}
// The indexes have to be adapted before running
let d = HistoryDates {
this_week: history.items[0].playback_date_txt.clone().unwrap(),
last_week: history.items[18].playback_date_txt.clone().unwrap(),
};
res.insert(lang, d);
let entry = res.entry(lang).or_default();
entry.insert(
THIS_WEEK.to_owned(),
history.items[0].playback_date_txt.clone().unwrap(),
);
entry.insert(
LAST_WEEK.to_owned(),
history.items[18].playback_date_txt.clone().unwrap(),
);
}
let file = File::create(json_path).unwrap();
let file = File::create(&json_path).unwrap();
serde_json::to_writer_pretty(file, &res).unwrap();
}
pub async fn collect_dates() {
let json_path = path!(*DICT_DIR / "history_date_samples.json");
let rp = RustyPipe::builder()
.storage_dir(path!(env!("CARGO_MANIFEST_DIR") / ".."))
.build()
.unwrap();
let mut res: CollectedDates = {
let json_file = File::open(&json_path).unwrap();
serde_json::from_reader(BufReader::new(json_file)).unwrap()
};
for lang in LANGUAGES {
println!("{lang}");
let history = rp.query().lang(lang).history().await.unwrap();
if history.items.len() < 3 {
panic!("{lang} empty history")
}
let entry = res.entry(lang).or_default();
entry.insert(
"tuesday".to_owned(),
history.items[0].playback_date_txt.clone().unwrap(),
);
entry.insert(
"0000-01-06".to_owned(),
history.items[1].playback_date_txt.clone().unwrap(),
);
entry.insert(
"2024-12-28".to_owned(),
history.items[15].playback_date_txt.clone().unwrap(),
);
}
let file = File::create(&json_path).unwrap();
serde_json::to_writer_pretty(file, &res).unwrap();
}
@ -59,10 +100,10 @@ pub fn write_samples_to_dict() {
let cd = &collected_dates[&lang];
dict_entry
.timeago_nd_tokens
.insert(util::filter_datestr(&cd.this_week), "0Wl".to_owned());
.insert(util::filter_datestr(&cd[THIS_WEEK]), "0Wl".to_owned());
dict_entry
.timeago_nd_tokens
.insert(util::filter_datestr(&cd.last_week), "1Wl".to_owned());
.insert(util::filter_datestr(&cd[LAST_WEEK]), "1Wl".to_owned());
}
util::write_dict(dict);

View file

@ -45,7 +45,7 @@ pub fn generate_dictionary() {
use crate::{
model::AlbumType,
param::Language,
util::timeago::{DateCmp, TaToken, TimeUnit},
util::timeago::{TaToken, TimeUnit},
};
/// Dictionary entry containing language-specific parsing information
@ -57,14 +57,13 @@ pub(crate) struct Entry {
/// 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).
/// True if the month has to be parsed before the day
///
/// Examples:
///
/// - 03.01.2020 => `"DMY"`
/// - Jan 3, 2020 => `"DY"`
pub date_order: &'static [DateCmp],
/// - 03.01.2020 => DMY => false
/// - 01/03/2020 => MDY => true
pub month_before_day: bool,
/// Tokens for parsing month names.
///
/// Format: Parsed token -> Month number (starting from 1)
@ -139,13 +138,6 @@ pub(crate) fn entry(lang: Language) -> Entry {
};
});
// Date order
let mut date_order = "&[".to_owned();
entry.date_order.chars().for_each(|c| {
write!(date_order, "DateCmp::{c}, ").unwrap();
});
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)| {
@ -186,8 +178,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
.to_string()
.replace('\n', "\n ");
write!(code_timeago_tokens, "{} => Entry {{\n timeago_tokens: {},\n date_order: {},\n months: {},\n timeago_nd_tokens: {},\n comma_decimal: {:?},\n number_tokens: {},\n number_nd_tokens: {},\n album_types: {},\n chan_prefix: {:?},\n chan_suffix: {:?},\n }},\n ",
selector, code_ta_tokens, date_order, code_months, code_ta_nd_tokens, entry.comma_decimal, code_number_tokens, code_number_nd_tokens, code_album_types, entry.chan_prefix, entry.chan_suffix).unwrap();
write!(code_timeago_tokens, "{} => Entry {{\n timeago_tokens: {},\n month_before_day: {:?},\n months: {},\n timeago_nd_tokens: {},\n comma_decimal: {:?},\n number_tokens: {},\n number_nd_tokens: {},\n album_types: {},\n chan_prefix: {:?},\n chan_suffix: {:?},\n }},\n ",
selector, code_ta_tokens, entry.month_before_day, code_months, code_ta_nd_tokens, entry.comma_decimal, code_number_tokens, code_number_nd_tokens, code_album_types, entry.chan_prefix, entry.chan_suffix).unwrap();
}
code_timeago_tokens = code_timeago_tokens.trim_end().to_owned() + "\n }\n}\n";

View file

@ -32,6 +32,7 @@ enum Commands {
CollectVideoDurations,
CollectVideoDates,
CollectHistoryDates,
CollectMusicHistoryDates,
CollectChanPrefixes,
ParsePlaylistDates,
ParseHistoryDates,
@ -74,6 +75,9 @@ async fn main() {
Commands::CollectHistoryDates => {
collect_history_dates::collect_dates().await;
}
Commands::CollectMusicHistoryDates => {
collect_history_dates::collect_dates_music().await;
}
Commands::CollectChanPrefixes => {
collect_chan_prefixes::collect_chan_prefixes().await;
}

View file

@ -13,6 +13,13 @@ pub struct DictEntry {
/// Should the language be parsed by character instead of by word?
/// (e.g. Chinese/Japanese)
pub by_char: bool,
/// True if the month has to be parsed before the day
///
/// Examples:
///
/// - 03.01.2020 => DMY => false
/// - 01/03/2020 => MDY => true
pub month_before_day: bool,
/// Tokens for parsing timeago strings.
///
/// Format: Parsed token -> \[Quantity\] Identifier

View file

@ -8,7 +8,7 @@
use crate::{
model::AlbumType,
param::Language,
util::timeago::{DateCmp, TaToken, TimeUnit},
util::timeago::{TaToken, TimeUnit},
};
/// Dictionary entry containing language-specific parsing information
@ -20,14 +20,13 @@ pub(crate) struct Entry {
/// 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).
/// True if the month has to be parsed before the day
///
/// Examples:
///
/// - 03.01.2020 => `"DMY"`
/// - Jan 3, 2020 => `"DY"`
pub date_order: &'static [DateCmp],
/// - 03.01.2020 => DMY => false
/// - 01/03/2020 => MDY => true
pub month_before_day: bool,
/// Tokens for parsing month names.
///
/// Format: Parsed token -> Month number (starting from 1)
@ -89,7 +88,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("jaar", TaToken { n: 1, unit: Some(TimeUnit::Year) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: true,
months: ::phf::Map {
key: 12213676231523076107,
disps: &[
@ -216,7 +215,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("ቀናት", TaToken { n: 1, unit: Some(TimeUnit::Day) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -360,7 +359,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("دقائق", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
],
},
date_order: &[DateCmp::D, DateCmp::M, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -464,27 +463,35 @@ pub(crate) fn entry(lang: Language) -> Entry {
("মিনিট", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
],
},
date_order: &[DateCmp::D, DateCmp::M, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
(3, 11),
(2, 2),
(0, 0),
(1, 0),
(13, 15),
(3, 15),
(0, 15),
],
entries: &[
("ছেপ\u{9cd}তেম\u{9cd}বৰ", 9),
("\u{9be}\u{9c1}\u{9be}ৰী", 1),
("আগষ\u{9cd}", 8),
("মে’", 5),
("অক\u{9cd}টোবৰ", 10),
("এপ\u{9cd}ৰিল", 4),
("ডিচেম\u{9cd}বৰ", 12),
("ফেব\u{9cd}\u{9c1}\u{9be}ৰী", 2),
("\u{9c1}", 6),
("ফেব\u{9cd}\u{9c1}", 2),
("\u{9be}\u{9cd}", 3),
("\u{9c1}\u{9be}", 7),
("ডিচেম\u{9cd}বৰ", 12),
("নৱেম\u{9cd}বৰ", 11),
("ডিচে", 12),
("নৱে", 11),
("এপ\u{9cd}ৰিল", 4),
("\u{9c1}\u{9be}", 7),
("ফেব\u{9cd}\u{9c1}\u{9be}ৰী", 2),
("মে’", 5),
("\u{9be}\u{9c1}\u{9be}ৰী", 1),
("ছেপ\u{9cd}তে", 9),
("আগ", 8),
("আগষ\u{9cd}", 8),
("ছেপ\u{9cd}তেম\u{9cd}বৰ", 9),
("\u{9c1}", 6),
("অক\u{9cd}টো", 10),
("\u{9be}\u{9c1}", 1),
("অক\u{9cd}টোবৰ", 10),
],
},
timeago_nd_tokens: ::phf::Map {
@ -580,7 +587,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("ay", TaToken { n: 1, unit: Some(TimeUnit::Month) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -724,7 +731,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("хвіліна", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -855,7 +862,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("седмици", TaToken { n: 1, unit: Some(TimeUnit::Week) }),
],
},
date_order: &[DateCmp::D, DateCmp::M, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -956,7 +963,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("সেকেন\u{9cd}", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -1097,7 +1104,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("sedmice", TaToken { n: 1, unit: Some(TimeUnit::Week) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -1225,7 +1232,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("setmana", TaToken { n: 1, unit: Some(TimeUnit::Week) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -1367,7 +1374,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("minuta", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
],
},
date_order: &[DateCmp::D, DateCmp::M, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -1478,7 +1485,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("dage", TaToken { n: 1, unit: Some(TimeUnit::Day) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 15467950696543387533,
disps: &[
@ -1602,27 +1609,36 @@ pub(crate) fn entry(lang: Language) -> Entry {
("sek", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::D, DateCmp::M, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 7485420634051515786,
key: 12913932095322966823,
disps: &[
(0, 0),
(1, 8),
(0, 3),
(17, 15),
(3, 6),
(5, 10),
],
entries: &[
("januar", 1),
("august", 8),
("februar", 2),
("dezember", 12),
("oktober", 10),
("september", 9),
("november", 11),
("juli", 7),
("juni", 6),
("april", 4),
("mai", 5),
("sept", 9),
("märz", 3),
("mai", 5),
("september", 9),
("dez", 12),
("apr", 4),
("august", 8),
("april", 4),
("oktober", 10),
("aug", 8),
("februar", 2),
("juli", 7),
("dezember", 12),
("nov", 11),
("feb", 2),
("okt", 10),
("juni", 6),
("november", 11),
("januar", 1),
("jan", 1),
],
},
timeago_nd_tokens: ::phf::Map {
@ -1717,7 +1733,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("λεπτά", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 15467950696543387533,
disps: &[
@ -1857,7 +1873,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("second", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: true,
months: ::phf::Map {
key: 351906021642186605,
disps: &[
@ -1988,7 +2004,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("meses", TaToken { n: 1, unit: Some(TimeUnit::Month) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 8602556344903797927,
disps: &[
@ -2114,7 +2130,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("sem", TaToken { n: 1, unit: Some(TimeUnit::Week) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 8602556344903797927,
disps: &[
@ -2243,7 +2259,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("päeva", TaToken { n: 1, unit: Some(TimeUnit::Day) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 11210181029210336526,
disps: &[
@ -2356,7 +2372,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("s", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::Y, DateCmp::D],
month_before_day: true,
months: ::phf::Map {
key: 4594751852016600049,
disps: &[
@ -2469,7 +2485,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("دقیقه", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: true,
months: ::phf::Map {
key: 7485420634051515786,
disps: &[
@ -2593,7 +2609,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("viikko", TaToken { n: 1, unit: Some(TimeUnit::Week) }),
],
},
date_order: &[DateCmp::D, DateCmp::M, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 7485420634051515786,
disps: &[
@ -2697,7 +2713,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("linggo", TaToken { n: 1, unit: Some(TimeUnit::Week) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: true,
months: ::phf::Map {
key: 345707026197253659,
disps: &[
@ -2826,7 +2842,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("jour", TaToken { n: 1, unit: Some(TimeUnit::Day) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -2956,7 +2972,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("semana", TaToken { n: 1, unit: Some(TimeUnit::Week) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -3068,7 +3084,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("કલાક", TaToken { n: 1, unit: Some(TimeUnit::Hour) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -3175,7 +3191,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("\u{947}\u{902}", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -3312,7 +3328,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("g", TaToken { n: 1, unit: Some(TimeUnit::Year) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 8694567506910003252,
disps: &[
@ -3441,7 +3457,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("órával", TaToken { n: 1, unit: Some(TimeUnit::Hour) }),
],
},
date_order: &[DateCmp::Y, DateCmp::D],
month_before_day: true,
months: ::phf::Map {
key: 15467950696543387533,
disps: &[
@ -3562,7 +3578,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("ամիս", TaToken { n: 1, unit: Some(TimeUnit::Month) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 8694567506910003252,
disps: &[
@ -3685,7 +3701,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("menit", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 15467950696543387533,
disps: &[
@ -3814,7 +3830,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("mán", TaToken { n: 1, unit: Some(TimeUnit::Month) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 15467950696543387533,
disps: &[
@ -3947,7 +3963,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("secondo", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 5516568623150984925,
disps: &[
@ -4085,7 +4101,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("דקות", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 7485420634051515786,
disps: &[
@ -4200,7 +4216,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
],
},
date_order: &[DateCmp::Y, DateCmp::M, DateCmp::D],
month_before_day: true,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -4287,7 +4303,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("წმ", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 14108922650502679131,
disps: &[
@ -4409,7 +4425,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("мин", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
],
},
date_order: &[DateCmp::Y, DateCmp::D],
month_before_day: false,
months: ::phf::Map {
key: 42584678569483946,
disps: &[
@ -4527,7 +4543,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("នាទ\u{17b8}", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 7485420634051515786,
disps: &[
@ -4642,7 +4658,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("\u{cc6}\u{cc6}ಂಡ\u{ccd}", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 8602556344903797927,
disps: &[
@ -4751,7 +4767,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("", TaToken { n: 1, unit: Some(TimeUnit::Week) }),
],
},
date_order: &[DateCmp::Y, DateCmp::M, DateCmp::D],
month_before_day: true,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -4837,7 +4853,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("ай", TaToken { n: 1, unit: Some(TimeUnit::Month) }),
],
},
date_order: &[DateCmp::Y, DateCmp::D],
month_before_day: false,
months: ::phf::Map {
key: 8694567506910003252,
disps: &[
@ -4960,7 +4976,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("ຊມ", TaToken { n: 1, unit: Some(TimeUnit::Hour) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 7485420634051515786,
disps: &[
@ -5111,7 +5127,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("dieną", TaToken { n: 1, unit: Some(TimeUnit::Day) }),
],
},
date_order: &[DateCmp::Y, DateCmp::M, DateCmp::D],
month_before_day: true,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -5233,7 +5249,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("ned", TaToken { n: 1, unit: Some(TimeUnit::Week) }),
],
},
date_order: &[DateCmp::Y, DateCmp::D],
month_before_day: false,
months: ::phf::Map {
key: 10121458955350035957,
disps: &[
@ -5358,27 +5374,40 @@ pub(crate) fn entry(lang: Language) -> Entry {
("секунди", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::D, DateCmp::M, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
(5, 0),
(4, 10),
(0, 10),
(1, 0),
(5, 1),
(2, 0),
(20, 19),
],
entries: &[
("јул", 7),
("апр", 4),
("февруари", 2),
("јануари", 1),
("мар", 3),
("јан", 1),
("септември", 9),
("јун", 6),
("август", 8),
("сеп", 9),
("фев", 2),
("јули", 7),
("април", 4),
("ное", 11),
("окт", 10),
("ноември", 11),
("март", 3),
("декември", 12),
("октомври", 10),
("авг", 8),
("мај", 5),
("октомври", 10),
("јуни", 6),
("август", 8),
("април", 4),
("јануари", 1),
("јули", 7),
("септември", 9),
("февруари", 2),
("дек", 12),
("декември", 12),
],
},
timeago_nd_tokens: ::phf::Map {
@ -5463,7 +5492,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("സെക\u{d4d}കൻഡ\u{d4d}", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::Y, DateCmp::D],
month_before_day: false,
months: ::phf::Map {
key: 15467950696543387533,
disps: &[
@ -5581,7 +5610,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("секундын", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::Y, DateCmp::M, DateCmp::D],
month_before_day: true,
months: ::phf::Map {
key: 14108922650502679131,
disps: &[
@ -5594,10 +5623,10 @@ pub(crate) fn entry(lang: Language) -> Entry {
("долоодугаар", 7),
("тавдугаар", 5),
("аравдугаар", 10),
("хоёрдугаар", 12),
("хоёрдугаар", 2),
("дөрөвдүгээр", 4),
("зургаадугаар", 6),
("нэгдүгээр", 11),
("нэгдүгээр", 1),
("гуравдугаар", 3),
],
},
@ -5693,7 +5722,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("\u{947}", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 15467950696543387533,
disps: &[
@ -5807,7 +5836,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("hari", TaToken { n: 1, unit: Some(TimeUnit::Day) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 15467950696543387533,
disps: &[
@ -5918,7 +5947,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("\u{103e}\u{103a}", TaToken { n: 1, unit: Some(TimeUnit::Year) }),
],
},
date_order: &[DateCmp::Y, DateCmp::D],
month_before_day: false,
months: ::phf::Map {
key: 7485420634051515786,
disps: &[
@ -6036,7 +6065,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("\u{947}\u{947}\u{94d}", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::Y, DateCmp::D],
month_before_day: true,
months: ::phf::Map {
key: 15467950696543387533,
disps: &[
@ -6147,7 +6176,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("dagen", TaToken { n: 1, unit: Some(TimeUnit::Day) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 7485420634051515786,
disps: &[
@ -6275,7 +6304,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("d", TaToken { n: 1, unit: Some(TimeUnit::Day) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -6396,7 +6425,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("ସେ", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: true,
months: ::phf::Map {
key: 7485420634051515786,
disps: &[
@ -6506,7 +6535,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("\u{a70}ਟਾ", TaToken { n: 1, unit: Some(TimeUnit::Hour) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 7485420634051515786,
disps: &[
@ -6648,7 +6677,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("roku", TaToken { n: 1, unit: Some(TimeUnit::Year) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -6777,7 +6806,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("s", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 7485420634051515786,
disps: &[
@ -6905,7 +6934,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("dia", TaToken { n: 1, unit: Some(TimeUnit::Day) }),
],
},
date_order: &[DateCmp::D, DateCmp::M, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 15467950696543387533,
disps: &[
@ -7018,7 +7047,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("ani", TaToken { n: 1, unit: Some(TimeUnit::Year) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 15467950696543387533,
disps: &[
@ -7162,7 +7191,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("секунда", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -7277,7 +7306,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("\u{dd2}", TaToken { n: 1, unit: Some(TimeUnit::Day) }),
],
},
date_order: &[DateCmp::Y, DateCmp::D],
month_before_day: true,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -7415,7 +7444,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("dňa", TaToken { n: 1, unit: Some(TimeUnit::Day) }),
],
},
date_order: &[DateCmp::D, DateCmp::M, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 10121458955350035957,
disps: &[
@ -7551,7 +7580,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("meseci", TaToken { n: 1, unit: Some(TimeUnit::Month) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 15467950696543387533,
disps: &[
@ -7671,7 +7700,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("orë", TaToken { n: 1, unit: Some(TimeUnit::Hour) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -7803,27 +7832,38 @@ pub(crate) fn entry(lang: Language) -> Entry {
("сек", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::D, DateCmp::M, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 10121458955350035957,
key: 15467950696543387533,
disps: &[
(2, 8),
(1, 0),
(0, 0),
(0, 18),
(0, 4),
(2, 0),
(2, 0),
(3, 16),
],
entries: &[
("мај", 5),
("феб", 2),
("мар", 3),
("јануар", 1),
("окт", 10),
("дец", 12),
("август", 8),
("март", 3),
("фебруар", 2),
("новембар", 11),
("јун", 6),
("октобар", 10),
("април", 4),
("децембар", 12),
("јул", 7),
("нов", 11),
("сеп", 9),
("април", 4),
("јан", 1),
("октобар", 10),
("септембар", 9),
("апр", 4),
("авг", 8),
("новембар", 11),
("децембар", 12),
("фебруар", 2),
],
},
timeago_nd_tokens: ::phf::Map {
@ -7922,27 +7962,38 @@ pub(crate) fn entry(lang: Language) -> Entry {
("sati", TaToken { n: 1, unit: Some(TimeUnit::Hour) }),
],
},
date_order: &[DateCmp::D, DateCmp::M, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 15467950696543387533,
key: 10121458955350035957,
disps: &[
(1, 3),
(5, 11),
(9, 16),
(0, 6),
(5, 10),
(2, 5),
(0, 0),
],
entries: &[
("decembar", 12),
("april", 4),
("februar", 2),
("jul", 7),
("jan", 1),
("okt", 10),
("novembar", 11),
("maj", 5),
("jun", 6),
("avgust", 8),
("januar", 1),
("septembar", 9),
("feb", 2),
("februar", 2),
("decembar", 12),
("sep", 9),
("april", 4),
("jul", 7),
("dec", 12),
("mar", 3),
("jun", 6),
("nov", 11),
("oktobar", 10),
("avg", 8),
("apr", 4),
("septembar", 9),
("mart", 3),
("maj", 5),
("januar", 1),
],
},
timeago_nd_tokens: ::phf::Map {
@ -8037,7 +8088,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("sekund", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: true,
months: ::phf::Map {
key: 10121458955350035957,
disps: &[
@ -8147,7 +8198,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("miaka", TaToken { n: 1, unit: Some(TimeUnit::Year) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -8277,7 +8328,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("நிமிடத\u{bcd}திற\u{bcd}கு", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -8403,7 +8454,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("సంవత\u{c4d}సర\u{c3e}", TaToken { n: 1, unit: Some(TimeUnit::Year) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 7485420634051515786,
disps: &[
@ -8526,7 +8577,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("เด\u{e37}อนท\u{e35}\u{e48}แล\u{e49}", TaToken { n: 1, unit: Some(TimeUnit::Month) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -8649,7 +8700,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("sa", TaToken { n: 1, unit: Some(TimeUnit::Hour) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 3599879742736855518,
disps: &[
@ -8796,7 +8847,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("хвилина", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 7485420634051515786,
disps: &[
@ -8921,7 +8972,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("سیکنڈز", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 10121458955350035957,
disps: &[
@ -9039,7 +9090,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("son", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -9151,7 +9202,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("tuần", TaToken { n: 1, unit: Some(TimeUnit::Week) }),
],
},
date_order: &[DateCmp::D, DateCmp::M, DateCmp::Y],
month_before_day: false,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -9232,7 +9283,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("", TaToken { n: 1, unit: Some(TimeUnit::Hour) }),
],
},
date_order: &[DateCmp::Y, DateCmp::M, DateCmp::D],
month_before_day: true,
months: ::phf::Map {
key: 106375038446233661,
disps: &[
@ -9330,7 +9381,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
],
},
date_order: &[DateCmp::Y, DateCmp::M, DateCmp::D],
month_before_day: true,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -9410,7 +9461,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
],
},
date_order: &[DateCmp::Y, DateCmp::M, DateCmp::D],
month_before_day: true,
months: ::phf::Map {
key: 12913932095322966823,
disps: &[
@ -9510,7 +9561,7 @@ pub(crate) fn entry(lang: Language) -> Entry {
("emahoreni", TaToken { n: 1, unit: Some(TimeUnit::Hour) }),
],
},
date_order: &[DateCmp::D, DateCmp::Y],
month_before_day: true,
months: ::phf::Map {
key: 2126027241312876569,
disps: &[

View file

@ -72,12 +72,6 @@ pub struct TaToken {
pub unit: Option<TimeUnit>,
}
pub enum DateCmp {
Y,
M,
D,
}
impl TimeUnit {
pub fn secs(self) -> u32 {
match self {
@ -207,10 +201,19 @@ impl Iterator for TaTokenParser<'_> {
}
}
fn parse_textual_month(entry: &dictionary::Entry, filtered_str: &str) -> Option<u8> {
fn parse_textual_month(lang: Language, filtered_str: &str) -> Option<u8> {
let entry = dictionary::entry(lang);
filtered_str
.split_whitespace()
.find_map(|word| entry.months.get(word).copied())
.map(|mon| {
// Mongolian has an extra number word that adds 10 to a month
if lang == Language::Mn && filtered_str.split_whitespace().any(|s| s == "арван") {
mon + 10
} else {
mon
}
})
}
/// Parse a TimeAgo string (e.g. "29 minutes ago") into a TimeAgo object.
@ -278,53 +281,49 @@ pub fn parse_textual_date(lang: Language, textual_date: &str) -> Option<ParsedDa
.or_else(|| TaTokenParser::new(&entry, by_char, false, &filtered_str).next())
.map(ParsedDate::Relative)
} else {
if nums.len() == 1 {
if nums.len() == 1 && nums[0] < 2000 {
if let Some(timeago) = TaTokenParser::new(&entry, by_char, false, &filtered_str).next()
{
return Some(ParsedDate::Relative(timeago * nums[0] as u8));
}
}
let mut date_order = entry.date_order;
let with_day = if entry.date_order.len() == nums.len() {
true
} else if entry.date_order.len() - 1 == nums.len() {
false
} else if nums.len() == 1 {
date_order = &[DateCmp::Y];
false
} else {
return None;
};
let mut y: Option<u16> = None;
let mut m: Option<u16> = None;
let mut m = parse_textual_month(lang, &filtered_str).map(u16::from);
let mut d: Option<u16> = None;
let mut i = 0;
for dc in date_order.iter() {
match dc {
DateCmp::Y => y = Some(nums[i]),
DateCmp::M => m = Some(nums[i]),
DateCmp::D => {
if with_day {
d = Some(nums[i]);
} else {
continue;
}
for num in nums {
if num > 31 {
if y.is_none() {
y = Some(num);
} else {
return None;
}
} else if m.is_none() && (entry.month_before_day || d.is_some()) {
m = Some(num);
} else if d.is_none() {
d = Some(num);
} else {
return None;
}
i += 1;
}
if m.is_none() {
m = parse_textual_month(&entry, &filtered_str).map(u16::from);
if m.is_none() && d.is_some() {
m = d;
d = None;
}
match (y, m, d) {
(Some(y), Some(m), d) => Month::try_from(m as u8)
(y, Some(m), d) => Month::try_from(m as u8)
.ok()
.and_then(|m| Date::from_calendar_date(y.into(), m, d.unwrap_or(1) as u8).ok())
.and_then(|m| {
Date::from_calendar_date(
y.map(i32::from)
.unwrap_or_else(|| OffsetDateTime::now_utc().year()),
m,
d.unwrap_or(1) as u8,
)
.ok()
})
.map(ParsedDate::Absolute),
_ => None,
}
@ -460,7 +459,7 @@ fn split_duration_txt(txt: &str, start_word: bool) -> Vec<DurationTxtSegment> {
#[cfg(test)]
mod tests {
use std::{collections::BTreeMap, fs::File, io::BufReader};
use std::{collections::BTreeMap, fs::File, io::BufReader, str::FromStr};
use path_macro::path;
use rstest::rstest;
@ -911,6 +910,20 @@ mod tests {
assert_eq!(parsed_date, expect);
}
#[rstest]
#[case(Language::En, "Jan 5", date!(0000-01-05))]
fn t_parse_date_this_year(
#[case] lang: Language,
#[case] textual_date: &str,
#[case] expect: Date,
) {
let parsed_date = parse_textual_date(lang, textual_date);
let expected_date = expect
.replace_year(OffsetDateTime::now_utc().year())
.unwrap();
assert_eq!(parsed_date, Some(ParsedDate::Absolute(expected_date)));
}
#[test]
fn t_parse_date_samples() {
let json_path = path!(*TESTFILES / "dict" / "playlist_samples.json");
@ -1008,34 +1021,48 @@ mod tests {
#[test]
fn t_parse_history_date_samples() {
#[derive(Deserialize)]
struct HistoryDates {
this_week: String,
last_week: String,
}
let json_path = path!(*TESTFILES / "dict" / "history_date_samples.json");
let json_file = File::open(json_path).unwrap();
let date_samples: BTreeMap<Language, HistoryDates> =
let date_samples: BTreeMap<Language, BTreeMap<String, String>> =
serde_json::from_reader(BufReader::new(json_file)).unwrap();
for (lang, samples) in date_samples {
assert_eq!(
parse_textual_date(lang, &samples.this_week),
Some(ParsedDate::Relative(TimeAgo {
n: 0,
unit: TimeUnit::LastWeek
})),
"lang: {lang}"
);
assert_eq!(
parse_textual_date(lang, &samples.last_week),
Some(ParsedDate::Relative(TimeAgo {
n: 1,
unit: TimeUnit::LastWeek
})),
"lang: {lang}"
);
for (k, v) in samples {
let expected = match k.as_str() {
"this_week" => ParsedDate::Relative(TimeAgo {
n: 0,
unit: TimeUnit::LastWeek,
}),
"last_week" => ParsedDate::Relative(TimeAgo {
n: 1,
unit: TimeUnit::LastWeek,
}),
_ => {
if let Ok(wd) = time::Weekday::from_str(&k) {
ParsedDate::Relative(TimeAgo {
n: wd.number_days_from_monday(),
unit: TimeUnit::LastWeekday,
})
} else {
let mut date_nums = k.split('-');
let mut y = date_nums.next().unwrap().parse::<i32>().unwrap();
if y == 0 {
y = OffsetDateTime::now_utc().date().year();
}
let m = date_nums.next().unwrap().parse::<u8>().unwrap();
let d = date_nums.next().unwrap().parse::<u8>().unwrap();
ParsedDate::Absolute(
Date::from_calendar_date(y, m.try_into().unwrap(), d).unwrap(),
)
}
}
};
assert_eq!(
parse_textual_date(lang, &v),
Some(expected),
"lang={lang}; {k}"
);
}
}
}

View file

@ -0,0 +1,59 @@
const fs = require("fs");
const DICT_PATH = "../dictionary.json";
function translateLang(lang) {
switch (lang) {
case "iw": // Hebrew
return "he";
case "zh-CN": // Simplified Chinese
return "zh-Hans";
case "zh-HK":
return "zh-Hant-HK";
case "zh-TW":
return "zh-Hant";
default:
return lang;
}
}
function isMonthBeforeDay(lang) {
const cldrLang = translateLang(lang);
const dates = require(`cldr-dates-modern/main/${cldrLang}/ca-gregorian.json`);
const dateFields = dates.main[cldrLang].dates.calendars.gregorian;
const dateFmt = dateFields.dateFormats.short;
const mPos = dateFmt.indexOf("M");
const dPos = dateFmt.indexOf("d");
if (mPos < 0 || dPos < 0) throw new Error(`invalid fmt for ${lang}: ${dateFmt}`);
return dPos > mPos;
}
const dict = JSON.parse(fs.readFileSync(DICT_PATH));
for (const [mainLang, entry] of Object.entries(dict)) {
const langs = [mainLang, ...entry["equivalent"]];
const dateOrder = entry["date_order"];
const mPos = dateOrder.indexOf("M");
const dPos = dateOrder.indexOf("D");
let expectMbd = mPos < 0 || dPos < 0 ? null : dPos > mPos;
if (mainLang === "en" || mainLang.startsWith("zh-")) {
expectMbd = true;
} else if (mainLang === "fr")
expectMbd = false;
else {
for (lang of langs) {
const mbd = isMonthBeforeDay(lang)
if (expectMbd === null) {
expectMbd = mbd;
} else if (mbd !== expectMbd) {
throw new Error(`unexpected mbd for ${lang}`);
}
}
}
dict[mainLang]["month_before_day"] = expectMbd;
}
fs.writeFileSync(DICT_PATH, JSON.stringify(dict, null, 2));

View file

@ -17,27 +17,46 @@ function translateLang(lang) {
}
}
function collectMonthNames(lang, by_char, monthNames, weekdayNames) {
function collectMonthNames(lang, by_char, monthNames, monthShortNames, weekdayNames) {
const cldrLang = translateLang(lang);
const dates = require(`cldr-dates-modern/main/${cldrLang}/ca-gregorian.json`);
const dateFields = dates.main[cldrLang].dates.calendars.gregorian;
const months = dateFields.months["stand-alone"].wide;
for (const [n, name] of Object.entries(months)) {
let name2 = name.toLowerCase();
if (name2.includes(n)) {
// Some languages dont have named months
console.log(`${lang}: month name '${name2}' includes number; skipped`);
continue;
// Mongolian dates have the extra numbe арван and have to be handled manually
if (!["mn"].includes(lang)) {
for (const [n, name] of Object.entries(months)) {
let name2 = name.toLowerCase();
if (name2.includes(n)) {
// Some languages dont have named months
console.log(`${lang}: month name '${name2}' includes number; skipped`);
continue;
}
if (/\s/g.test(name2)) {
throw new Error(`${lang}: month name '${name2}' contains whitespace`);
}
monthNames[name2] = parseInt(n);
}
if (lang === "mn") {
name2 = name2.replace(" сар", "").replace("арван ", "");
}
if (!["bg", "fi", "cs", "iw", "lt", "pt-PT", "sk"].includes(lang)) {
const monthsShort = dateFields.months.format.abbreviated;
for (const [n, name] of Object.entries(monthsShort)) {
let name2 = name.toLowerCase().replaceAll(".", "");
if (name2.includes(n)) {
// Some languages dont have named months
console.log(`${lang}: month name '${name2}' includes number; skipped`);
continue;
}
if (lang === "ca") {
name2 = name2.replace("de ", "");
}
if (/\s/g.test(name2)) {
throw new Error(`${lang}: month name '${name2}' contains whitespace`);
}
monthShortNames[name2] = parseInt(n);
}
if (/\s/g.test(name2)) {
throw new Error(`${lang}: month name '${name2}' contains whitespace`);
}
monthNames[name2.toLowerCase()] = parseInt(n);
}
const weekdays = dateFields.days["stand-alone"].wide;
@ -72,12 +91,23 @@ const dict = JSON.parse(fs.readFileSync(DICT_PATH));
for (const [mainLang, entry] of Object.entries(dict)) {
const langs = [mainLang, ...entry["equivalent"]];
let monthNames = {};
let monthShortNames = {};
let weekdayNames = {};
for (lang of langs) {
collectMonthNames(lang, entry["by_char"], monthNames, weekdayNames);
collectMonthNames(
lang,
entry["by_char"],
monthNames,
monthShortNames,
weekdayNames
);
}
dict[mainLang]["months"] = { ...dict[mainLang]["months"], ...monthNames };
dict[mainLang]["months"] = {
...dict[mainLang]["months"],
...monthNames,
...monthShortNames,
};
dict[mainLang]["timeago_nd_tokens"] = {
...dict[mainLang]["timeago_nd_tokens"],
...weekdayNames,

View file

@ -79,7 +79,8 @@
"enkelsnitte": "single"
},
"chan_prefix": "deur",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": true
},
"am": {
"equivalent": [],
@ -162,7 +163,8 @@
"ነጠላዎች": "single"
},
"chan_prefix": "በ",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"ar": {
"equivalent": [],
@ -252,7 +254,8 @@
"أغنية منفردة": "single"
},
"chan_prefix": "بواسطة",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"as": {
"equivalent": [],
@ -268,17 +271,24 @@
},
"date_order": "DMY",
"months": {
"জানু": 1,
"জানুৱাৰী": 1,
"ফেব্ৰু": 2,
"ফেব্ৰুৱাৰী": 2,
"মাৰ্চ": 3,
"এপ্ৰিল": 4,
"মে’": 5,
"জুন": 6,
"জুলাই": 7,
"আগ": 8,
"আগষ্ট": 8,
"ছেপ্তে": 9,
"ছেপ্তেম্বৰ": 9,
"অক্টো": 10,
"অক্টোবৰ": 10,
"নৱে": 11,
"নৱেম্বৰ": 11,
"ডিচে": 12,
"ডিচেম্বৰ": 12
},
"timeago_nd_tokens": {
@ -324,7 +334,8 @@
"এককসমূহ": "single"
},
"chan_prefix": "",
"chan_suffix": "ৰ দ্বাৰা"
"chan_suffix": "ৰ দ্বাৰা",
"month_before_day": false
},
"az": {
"equivalent": [],
@ -397,7 +408,8 @@
"tək": "single"
},
"chan_prefix": "by",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"be": {
"equivalent": [],
@ -497,7 +509,8 @@
"сінглы": "single"
},
"chan_prefix": "ад",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"bg": {
"equivalent": [],
@ -571,7 +584,8 @@
"сингъл": "single"
},
"chan_prefix": "от",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"bn": {
"equivalent": [],
@ -645,7 +659,8 @@
"সিঙ্গেলস": "single"
},
"chan_prefix": ",",
"chan_suffix": "দ্বারা"
"chan_suffix": "দ্বারা",
"month_before_day": false
},
"bs": {
"equivalent": [],
@ -738,7 +753,8 @@
"singlovi": "single"
},
"chan_prefix": "od",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"ca": {
"equivalent": [],
@ -818,7 +834,8 @@
"singles": "single"
},
"chan_prefix": "de:",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"cs": {
"equivalent": [],
@ -903,7 +920,8 @@
"singly": "single"
},
"chan_prefix": "autor:",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"da": {
"equivalent": [],
@ -983,7 +1001,8 @@
"singler": "single"
},
"chan_prefix": "af",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"de": {
"equivalent": [],
@ -1009,17 +1028,25 @@
},
"date_order": "DMY",
"months": {
"jan": 1,
"januar": 1,
"feb": 2,
"februar": 2,
"märz": 3,
"apr": 4,
"april": 4,
"mai": 5,
"juni": 6,
"juli": 7,
"aug": 8,
"august": 8,
"sept": 9,
"september": 9,
"okt": 10,
"oktober": 10,
"nov": 11,
"november": 11,
"dez": 12,
"dezember": 12
},
"timeago_nd_tokens": {
@ -1053,7 +1080,8 @@
"singles": "single"
},
"chan_prefix": "von",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"el": {
"equivalent": [],
@ -1139,13 +1167,11 @@
"σινγκλ": "single"
},
"chan_prefix": "από το χρήστη",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"en": {
"equivalent": [
"en-GB",
"en-IN"
],
"equivalent": ["en-GB", "en-IN"],
"by_char": false,
"timeago_tokens": {
"s": "s",
@ -1237,7 +1263,8 @@
"singles": "single"
},
"chan_prefix": "by",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": true
},
"es": {
"equivalent": [],
@ -1320,12 +1347,11 @@
"single": "single"
},
"chan_prefix": "de",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"es-US": {
"equivalent": [
"es-419"
],
"equivalent": ["es-419"],
"by_char": false,
"timeago_tokens": {
"s": "s",
@ -1406,7 +1432,8 @@
"sencillos": "single"
},
"chan_prefix": "de",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"et": {
"equivalent": [],
@ -1488,7 +1515,8 @@
"singlid": "single"
},
"chan_prefix": "kanalilt",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"eu": {
"equivalent": [],
@ -1562,7 +1590,8 @@
"singleak": "single"
},
"chan_prefix": "egilea:",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": true
},
"fa": {
"equivalent": [],
@ -1628,7 +1657,8 @@
"تک‌آهنگ‌ها": "single"
},
"chan_prefix": "توسط",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": true
},
"fi": {
"equivalent": [],
@ -1704,7 +1734,8 @@
"singlet": "single"
},
"chan_prefix": "tekijä:",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"fil": {
"equivalent": [],
@ -1779,12 +1810,11 @@
"single": "single"
},
"chan_prefix": "ni/ng",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": true
},
"fr": {
"equivalent": [
"fr-CA"
],
"equivalent": ["fr-CA"],
"by_char": false,
"timeago_tokens": {
"s": "s",
@ -1868,7 +1898,8 @@
"singles": "single"
},
"chan_prefix": "de",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"gl": {
"equivalent": [],
@ -1948,7 +1979,8 @@
"singles": "single"
},
"chan_prefix": "de",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"gu": {
"equivalent": [],
@ -2013,7 +2045,8 @@
"સિંગલ": "single"
},
"chan_prefix": "",
"chan_suffix": "દ્વારા"
"chan_suffix": "દ્વારા",
"month_before_day": false
},
"hi": {
"equivalent": [],
@ -2087,7 +2120,8 @@
"सिंगल": "single"
},
"chan_prefix": "",
"chan_suffix": "के ज़रिए"
"chan_suffix": "के ज़रिए",
"month_before_day": false
},
"hr": {
"equivalent": [],
@ -2180,7 +2214,8 @@
"singlovi": "single"
},
"chan_prefix": "omogućio kanal",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"hu": {
"equivalent": [],
@ -2265,7 +2300,8 @@
"kislemezek": "single"
},
"chan_prefix": "",
"chan_suffix": "csatornától"
"chan_suffix": "csatornától",
"month_before_day": true
},
"hy": {
"equivalent": [],
@ -2344,7 +2380,8 @@
"սինգլներ": "single"
},
"chan_prefix": "հեղինակ՝",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"id": {
"equivalent": [],
@ -2420,7 +2457,8 @@
"single": "single"
},
"chan_prefix": "oleh",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"is": {
"equivalent": [],
@ -2509,7 +2547,8 @@
"smáskífur": "single"
},
"chan_prefix": "eftir",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"it": {
"equivalent": [],
@ -2596,7 +2635,8 @@
"singolo": "single"
},
"chan_prefix": "di",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"iw": {
"equivalent": [],
@ -2688,7 +2728,8 @@
"סינגלים": "single"
},
"chan_prefix": "מאת",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"ja": {
"equivalent": [],
@ -2731,7 +2772,8 @@
"シングル": "single"
},
"chan_prefix": "作成者:",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": true
},
"ka": {
"equivalent": [],
@ -2810,7 +2852,8 @@
"სინგლი": "single"
},
"chan_prefix": "",
"chan_suffix": "-ის მიერ"
"chan_suffix": "-ის მიერ",
"month_before_day": false
},
"kk": {
"equivalent": [],
@ -2890,7 +2933,8 @@
"синглдер": "single"
},
"chan_prefix": "қосқан",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"km": {
"equivalent": [],
@ -2951,7 +2995,8 @@
"ចម្រៀងទោល": "single"
},
"chan_prefix": "ដោយ",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"kn": {
"equivalent": [],
@ -3033,7 +3078,8 @@
"ಸಿಂಗಲ್ಸ್": "single"
},
"chan_prefix": "",
"chan_suffix": "ಚಾನಲ್‌ನಿಂದ"
"chan_suffix": "ಚಾನಲ್‌ನಿಂದ",
"month_before_day": false
},
"ko": {
"equivalent": [],
@ -3079,7 +3125,8 @@
"싱글": "single"
},
"chan_prefix": "게시자:",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": true
},
"ky": {
"equivalent": [],
@ -3155,7 +3202,8 @@
"синглдар": "single"
},
"chan_prefix": "",
"chan_suffix": "каналы аркылуу"
"chan_suffix": "каналы аркылуу",
"month_before_day": false
},
"lo": {
"equivalent": [],
@ -3238,7 +3286,8 @@
"ຜົນງານເພງ": "single"
},
"chan_prefix": "ໂດຍ",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"lt": {
"equivalent": [],
@ -3327,7 +3376,8 @@
"singlas": "single"
},
"chan_prefix": "pridėjo",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": true
},
"lv": {
"equivalent": [],
@ -3416,7 +3466,8 @@
"singls": "single"
},
"chan_prefix": "autors:",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"mk": {
"equivalent": [],
@ -3442,17 +3493,28 @@
},
"date_order": "DMY",
"months": {
"јан": 1,
"јануари": 1,
"фев": 2,
"февруари": 2,
"мар": 3,
"март": 3,
"апр": 4,
"април": 4,
"мај": 5,
"јун": 6,
"јуни": 6,
"јул": 7,
"јули": 7,
"авг": 8,
"август": 8,
"сеп": 9,
"септември": 9,
"окт": 10,
"октомври": 10,
"ное": 11,
"ноември": 11,
"дек": 12,
"декември": 12
},
"timeago_nd_tokens": {
@ -3488,7 +3550,8 @@
"синглови": "single"
},
"chan_prefix": "од",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"ml": {
"equivalent": [],
@ -3560,7 +3623,8 @@
"സിംഗിൾസ്": "single"
},
"chan_prefix": "",
"chan_suffix": "മുഖേന"
"chan_suffix": "മുഖേന",
"month_before_day": false
},
"mn": {
"equivalent": [],
@ -3582,6 +3646,8 @@
},
"date_order": "YMD",
"months": {
"нэгдүгээр": 1,
"хоёрдугаар": 2,
"гуравдугаар": 3,
"дөрөвдүгээр": 4,
"тавдугаар": 5,
@ -3589,9 +3655,7 @@
"долоодугаар": 7,
"наймдугаар": 8,
"есдүгээр": 9,
"аравдугаар": 10,
"нэгдүгээр": 11,
"хоёрдугаар": 12
"аравдугаар": 10
},
"timeago_nd_tokens": {
"өнөөдөр": "0D",
@ -3624,7 +3688,8 @@
"синглүүд": "single"
},
"chan_prefix": "сувгийн нэр:",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": true
},
"mr": {
"equivalent": [],
@ -3706,7 +3771,8 @@
"सिंगल": "single"
},
"chan_prefix": "",
"chan_suffix": "द्वारे"
"chan_suffix": "द्वारे",
"month_before_day": false
},
"ms": {
"equivalent": [],
@ -3777,7 +3843,8 @@
"rekod single": "single"
},
"chan_prefix": "oleh",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"my": {
"equivalent": [],
@ -3854,7 +3921,8 @@
"တစ်ပုဒ်ချင်းများ": "single"
},
"chan_prefix": "",
"chan_suffix": "မှ"
"chan_suffix": "မှ",
"month_before_day": false
},
"ne": {
"equivalent": [],
@ -3917,7 +3985,8 @@
"एकल एल्बमहरू": "single"
},
"chan_prefix": "",
"chan_suffix": "द्वारा"
"chan_suffix": "द्वारा",
"month_before_day": true
},
"nl": {
"equivalent": [],
@ -3996,7 +4065,8 @@
"singles": "single"
},
"chan_prefix": "door",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"no": {
"equivalent": [],
@ -4080,7 +4150,8 @@
"singler": "single"
},
"chan_prefix": "av",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"or": {
"equivalent": [],
@ -4153,7 +4224,8 @@
"ସିଙ୍ଗଲ୍": "single"
},
"chan_prefix": "",
"chan_suffix": "ଦ୍ଵାରା"
"chan_suffix": "ଦ୍ଵାରା",
"month_before_day": true
},
"pa": {
"equivalent": [],
@ -4226,7 +4298,8 @@
"ਸਿੰਗਲ": "single"
},
"chan_prefix": "",
"chan_suffix": "ਵੱਲੋਂ"
"chan_suffix": "ਵੱਲੋਂ",
"month_before_day": false
},
"pl": {
"equivalent": [],
@ -4324,7 +4397,8 @@
"single": "single"
},
"chan_prefix": "autor:",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"pt": {
"equivalent": [],
@ -4409,7 +4483,8 @@
"singles": "single"
},
"chan_prefix": "por",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"pt-PT": {
"equivalent": [],
@ -4479,7 +4554,8 @@
"singles": "single"
},
"chan_prefix": "de",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"ro": {
"equivalent": [],
@ -4563,7 +4639,8 @@
"single-uri": "single"
},
"chan_prefix": "de",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"ru": {
"equivalent": [],
@ -4659,7 +4736,8 @@
"синглы": "single"
},
"chan_prefix": "",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"si": {
"equivalent": [],
@ -4729,7 +4807,8 @@
"තනි": "single"
},
"chan_prefix": "",
"chan_suffix": "විසින්"
"chan_suffix": "විසින්",
"month_before_day": true
},
"sk": {
"equivalent": [],
@ -4814,7 +4893,8 @@
"single": "single"
},
"chan_prefix": "Autori:",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"sl": {
"equivalent": [],
@ -4915,7 +4995,8 @@
"singli": "single"
},
"chan_prefix": "kanal",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"sq": {
"equivalent": [],
@ -4992,7 +5073,8 @@
"single": "single"
},
"chan_prefix": "nga",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"sr": {
"equivalent": [],
@ -5023,17 +5105,26 @@
},
"date_order": "DMY",
"months": {
"јан": 1,
"јануар": 1,
"феб": 2,
"фебруар": 2,
"мар": 3,
"март": 3,
"апр": 4,
"април": 4,
"мај": 5,
"јун": 6,
"јул": 7,
"авг": 8,
"август": 8,
"сеп": 9,
"септембар": 9,
"окт": 10,
"октобар": 10,
"нов": 11,
"новембар": 11,
"дец": 12,
"децембар": 12
},
"timeago_nd_tokens": {
@ -5068,7 +5159,8 @@
"синглови": "single"
},
"chan_prefix": "са канала",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"sr-Latn": {
"equivalent": [],
@ -5099,17 +5191,26 @@
},
"date_order": "DMY",
"months": {
"jan": 1,
"januar": 1,
"feb": 2,
"februar": 2,
"mar": 3,
"mart": 3,
"apr": 4,
"april": 4,
"maj": 5,
"jun": 6,
"jul": 7,
"avg": 8,
"avgust": 8,
"sep": 9,
"septembar": 9,
"okt": 10,
"oktobar": 10,
"nov": 11,
"novembar": 11,
"dec": 12,
"decembar": 12
},
"timeago_nd_tokens": {
@ -5144,7 +5245,8 @@
"singlovi": "single"
},
"chan_prefix": "sa kanala",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"sv": {
"equivalent": [],
@ -5223,7 +5325,8 @@
"singlar": "single"
},
"chan_prefix": "från",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": true
},
"sw": {
"equivalent": [],
@ -5295,7 +5398,8 @@
"singo": "single"
},
"chan_prefix": "kutoka",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"ta": {
"equivalent": [],
@ -5380,7 +5484,8 @@
"சிங்கிள்ஸ்": "single"
},
"chan_prefix": "வழங்கியவர்:",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"te": {
"equivalent": [],
@ -5463,7 +5568,8 @@
"సింగిల్స్": "single"
},
"chan_prefix": "",
"chan_suffix": "ఛానెల్ ద్వారా"
"chan_suffix": "ఛానెల్ ద్వారా",
"month_before_day": false
},
"th": {
"equivalent": [],
@ -5549,7 +5655,8 @@
"ซิงเกิล": "single"
},
"chan_prefix": "โดย",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"tr": {
"equivalent": [],
@ -5626,7 +5733,8 @@
"single'lar": "single"
},
"chan_prefix": "",
"chan_suffix": "tarafından"
"chan_suffix": "tarafından",
"month_before_day": false
},
"uk": {
"equivalent": [],
@ -5727,7 +5835,8 @@
"сингли": "single"
},
"chan_prefix": "власник:",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"ur": {
"equivalent": [],
@ -5809,7 +5918,8 @@
"واحد": "single"
},
"chan_prefix": "منجانب",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"uz": {
"equivalent": [],
@ -5881,7 +5991,8 @@
"singllar": "single"
},
"chan_prefix": "muallif:",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"vi": {
"equivalent": [],
@ -5925,7 +6036,8 @@
"đĩa đơn": "single"
},
"chan_prefix": "của",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": false
},
"zh-CN": {
"equivalent": [],
@ -5983,7 +6095,8 @@
"单曲": "single"
},
"chan_prefix": "创建者:",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": true
},
"zh-HK": {
"equivalent": [],
@ -6027,7 +6140,8 @@
"單曲": "single"
},
"chan_prefix": "來自",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": true
},
"zh-TW": {
"equivalent": [],
@ -6070,7 +6184,8 @@
"單曲": "single"
},
"chan_prefix": "由",
"chan_suffix": "建立"
"chan_suffix": "建立",
"month_before_day": true
},
"zu": {
"equivalent": [],
@ -6160,6 +6275,7 @@
"i-single": "single"
},
"chan_prefix": "ka-",
"chan_suffix": ""
"chan_suffix": "",
"month_before_day": true
}
}

File diff suppressed because it is too large Load diff