-
Notifications
You must be signed in to change notification settings - Fork 336
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #485 from S4M3R/master
Basic spanish support
- Loading branch information
Showing
14 changed files
with
970 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
export const WEEKDAY_DICTIONARY: { [word: string]: number } = { | ||
"domingo": 0, | ||
"dom": 0, | ||
"lunes": 1, | ||
"lun": 1, | ||
"martes": 2, | ||
"mar": 2, | ||
"miércoles": 3, | ||
"miercoles": 3, | ||
"mié": 3, | ||
"mie": 3, | ||
"jueves": 4, | ||
"jue": 4, | ||
"viernes": 5, | ||
"vie": 5, | ||
"sábado": 6, | ||
"sabado": 6, | ||
"sáb": 6, | ||
"sab": 6, | ||
}; | ||
|
||
export const MONTH_DICTIONARY: { [word: string]: number } = { | ||
"enero": 1, | ||
"ene": 1, | ||
"ene.": 1, | ||
"febrero": 2, | ||
"feb": 2, | ||
"feb.": 2, | ||
"marzo": 3, | ||
"mar": 3, | ||
"mar.": 3, | ||
"abril": 4, | ||
"abr": 4, | ||
"abr.": 4, | ||
"mayo": 5, | ||
"may": 5, | ||
"may.": 5, | ||
"junio": 6, | ||
"jun": 6, | ||
"jun.": 6, | ||
"julio": 7, | ||
"jul": 7, | ||
"jul.": 7, | ||
"agosto": 8, | ||
"ago": 8, | ||
"ago.": 8, | ||
"septiembre": 9, | ||
"setiembre": 9, | ||
"sep": 9, | ||
"sep.": 9, | ||
"octubre": 10, | ||
"oct": 10, | ||
"oct.": 10, | ||
"noviembre": 11, | ||
"nov": 11, | ||
"nov.": 11, | ||
"diciembre": 12, | ||
"dic": 12, | ||
"dic.": 12, | ||
}; | ||
|
||
//----------------------------- | ||
// 88 p. Chr. n. | ||
// 234 AC | ||
export const YEAR_PATTERN = "[0-9]{1,4}(?![^\\s]\\d)(?:\\s*[a|d]\\.?\\s*c\\.?|\\s*a\\.?\\s*d\\.?)?"; | ||
export function parseYear(match: string): number { | ||
if (match.match(/^[0-9]{1,4}$/)) { | ||
let yearNumber = parseInt(match); | ||
if (yearNumber < 100) { | ||
if (yearNumber > 50) { | ||
yearNumber = yearNumber + 1900; | ||
} else { | ||
yearNumber = yearNumber + 2000; | ||
} | ||
} | ||
return yearNumber; | ||
} | ||
|
||
if (match.match(/a\.?\s*c\.?/i)) { | ||
match = match.replace(/a\.?\s*c\.?/i, ""); | ||
return -parseInt(match); | ||
} | ||
|
||
return parseInt(match); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/** | ||
* Chrono components for Portuguese support (*parsers*, *refiners*, and *configuration*) | ||
* | ||
* @module | ||
*/ | ||
|
||
import { includeCommonConfiguration } from "../../configurations"; | ||
import { ParsedResult, ParsingOption } from "../../index"; | ||
import { Chrono, Configuration } from "../../chrono"; | ||
import SlashDateFormatParser from "../../common/parsers/SlashDateFormatParser"; | ||
import ESWeekdayParser from "./parsers/ESWeekdayParser"; | ||
import ESTimeExpressionParser from "./parsers/ESTimeExpressionParser"; | ||
import ESMergeDateTimeRefiner from "./refiners/ESMergeDateTimeRefiner"; | ||
import ESMergeDateRangeRefiner from "./refiners/ESMergeDateRangeRefiner"; | ||
import ESMonthNameLittleEndianParser from "./parsers/ESMonthNameLittleEndianParser"; | ||
import ESCasualDateParser from "./parsers/ESCasualDateParser"; | ||
import ESCasualTimeParser from "./parsers/ESCasualTimeParser"; | ||
|
||
// Shortcuts | ||
export const casual = new Chrono(createCasualConfiguration()); | ||
export const strict = new Chrono(createConfiguration(true)); | ||
|
||
export function parse(text: string, ref?: Date, option?: ParsingOption): ParsedResult[] { | ||
return casual.parse(text, ref, option); | ||
} | ||
|
||
export function parseDate(text: string, ref?: Date, option?: ParsingOption): Date { | ||
return casual.parseDate(text, ref, option); | ||
} | ||
|
||
/** | ||
* @ignore (to be documented later) | ||
*/ | ||
export function createCasualConfiguration(littleEndian = true): Configuration { | ||
const option = createConfiguration(false, littleEndian); | ||
option.parsers.push(new ESCasualDateParser()); | ||
option.parsers.push(new ESCasualTimeParser()); | ||
return option; | ||
} | ||
|
||
/** | ||
* @ignore (to be documented later) | ||
*/ | ||
export function createConfiguration(strictMode = true, littleEndian = true): Configuration { | ||
return includeCommonConfiguration( | ||
{ | ||
parsers: [ | ||
new SlashDateFormatParser(littleEndian), | ||
new ESWeekdayParser(), | ||
new ESTimeExpressionParser(), | ||
new ESMonthNameLittleEndianParser(), | ||
], | ||
refiners: [new ESMergeDateTimeRefiner(), new ESMergeDateRangeRefiner()], | ||
}, | ||
strictMode | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { ParsingContext } from "../../../chrono"; | ||
import { ParsingComponents, ParsingResult } from "../../../results"; | ||
import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/AbstractParserWithWordBoundary"; | ||
import * as references from "../../../common/casualReferences"; | ||
|
||
export default class ESCasualDateParser extends AbstractParserWithWordBoundaryChecking { | ||
innerPattern(context: ParsingContext): RegExp { | ||
return /(ahora|hoy|mañana|ayer)(?=\W|$)/i; | ||
} | ||
|
||
innerExtract(context: ParsingContext, match: RegExpMatchArray): ParsingComponents | ParsingResult { | ||
const lowerText = match[0].toLowerCase(); | ||
const component = context.createParsingComponents(); | ||
|
||
switch (lowerText) { | ||
case "ahora": | ||
return references.now(context.reference); | ||
|
||
case "hoy": | ||
return references.today(context.reference); | ||
|
||
case "mañana": | ||
return references.tomorrow(context.reference); | ||
|
||
case "ayer": | ||
return references.yesterday(context.reference); | ||
} | ||
|
||
return component; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { ParsingContext } from "../../../chrono"; | ||
import { Meridiem } from "../../../index"; | ||
import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/AbstractParserWithWordBoundary"; | ||
import { assignTheNextDay } from "../../../utils/dayjs"; | ||
import dayjs from "dayjs"; | ||
|
||
export default class ESCasualTimeParser extends AbstractParserWithWordBoundaryChecking { | ||
innerPattern() { | ||
return /(?:esta\s*)?(mañana|tarde|medianoche|mediodia|mediodía|noche)(?=\W|$)/i; | ||
} | ||
|
||
innerExtract(context: ParsingContext, match: RegExpMatchArray) { | ||
const targetDate = dayjs(context.refDate); | ||
const component = context.createParsingComponents(); | ||
switch (match[1].toLowerCase()) { | ||
case "tarde": | ||
component.imply("meridiem", Meridiem.PM); | ||
component.imply("hour", 15); | ||
break; | ||
|
||
case "noche": | ||
component.imply("meridiem", Meridiem.PM); | ||
component.imply("hour", 22); | ||
break; | ||
|
||
case "mañana": | ||
component.imply("meridiem", Meridiem.AM); | ||
component.imply("hour", 6); | ||
break; | ||
|
||
case "medianoche": | ||
assignTheNextDay(component, targetDate); | ||
component.imply("hour", 0); | ||
component.imply("minute", 0); | ||
component.imply("second", 0); | ||
break; | ||
|
||
case "mediodia": | ||
case "mediodía": | ||
component.imply("meridiem", Meridiem.AM); | ||
component.imply("hour", 12); | ||
break; | ||
} | ||
|
||
return component; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { ParsingContext } from "../../../chrono"; | ||
import { ParsingResult } from "../../../results"; | ||
import { findYearClosestToRef } from "../../../calculation/years"; | ||
import { MONTH_DICTIONARY } from "../constants"; | ||
import { YEAR_PATTERN, parseYear } from "../constants"; | ||
import { matchAnyPattern } from "../../../utils/pattern"; | ||
import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/AbstractParserWithWordBoundary"; | ||
|
||
const PATTERN = new RegExp( | ||
`([0-9]{1,2})(?:º|ª|°)?` + | ||
"(?:\\s*(?:desde|de|\\-|\\–|ao?|\\s)\\s*([0-9]{1,2})(?:º|ª|°)?)?\\s*(?:de)?\\s*" + | ||
`(?:-|/|\\s*(?:de|,)?\\s*)` + | ||
`(${matchAnyPattern(MONTH_DICTIONARY)})` + | ||
`(?:\\s*(?:de|,)?\\s*(${YEAR_PATTERN}))?` + | ||
`(?=\\W|$)`, | ||
"i" | ||
); | ||
|
||
const DATE_GROUP = 1; | ||
const DATE_TO_GROUP = 2; | ||
const MONTH_NAME_GROUP = 3; | ||
const YEAR_GROUP = 4; | ||
|
||
export default class ESMonthNameLittleEndianParser extends AbstractParserWithWordBoundaryChecking { | ||
innerPattern(): RegExp { | ||
return PATTERN; | ||
} | ||
|
||
innerExtract(context: ParsingContext, match: RegExpMatchArray): ParsingResult { | ||
const result = context.createParsingResult(match.index, match[0]); | ||
|
||
const month = MONTH_DICTIONARY[match[MONTH_NAME_GROUP].toLowerCase()]; | ||
const day = parseInt(match[DATE_GROUP]); | ||
if (day > 31) { | ||
// e.g. "[96 Aug]" => "9[6 Aug]", we need to shift away from the next number | ||
match.index = match.index + match[DATE_GROUP].length; | ||
return null; | ||
} | ||
|
||
result.start.assign("month", month); | ||
result.start.assign("day", day); | ||
|
||
if (match[YEAR_GROUP]) { | ||
const yearNumber = parseYear(match[YEAR_GROUP]); | ||
result.start.assign("year", yearNumber); | ||
} else { | ||
const year = findYearClosestToRef(context.refDate, day, month); | ||
result.start.imply("year", year); | ||
} | ||
|
||
if (match[DATE_TO_GROUP]) { | ||
const endDate = parseInt(match[DATE_TO_GROUP]); | ||
|
||
result.end = result.start.clone(); | ||
result.end.assign("day", endDate); | ||
} | ||
|
||
return result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { AbstractTimeExpressionParser } from "../../../common/parsers/AbstractTimeExpressionParser"; | ||
|
||
export default class ESTimeExpressionParser extends AbstractTimeExpressionParser { | ||
primaryPrefix(): string { | ||
return "(?:(?:aslas|deslas|las?|al?|de|del)\\s*)?"; | ||
} | ||
|
||
followingPhase(): string { | ||
return "\\s*(?:\\-|\\–|\\~|\\〜|a(?:l)?|\\?)\\s*"; | ||
} | ||
|
||
// extractPrimaryTimeComponents(context: ParsingContext, match: RegExpMatchArray): ParsingComponents | null { | ||
// // This looks more like a year e.g. 2020 | ||
// // if (match[0].match(/^\s*\d{4}\s*$/)) { | ||
// // return null; | ||
// // } | ||
// | ||
// return super.extractPrimaryTimeComponents(context, match); | ||
// } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { ParsingContext } from "../../../chrono"; | ||
import { ParsingComponents } from "../../../results"; | ||
import { WEEKDAY_DICTIONARY } from "../constants"; | ||
import { matchAnyPattern } from "../../../utils/pattern"; | ||
import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/AbstractParserWithWordBoundary"; | ||
import { createParsingComponentsAtWeekday } from "../../../common/calculation/weekdays"; | ||
|
||
const PATTERN = new RegExp( | ||
"(?:(?:\\,|\\(|\\()\\s*)?" + | ||
"(?:(este|esta|pasado|pr[oó]ximo)\\s*)?" + | ||
`(${matchAnyPattern(WEEKDAY_DICTIONARY)})` + | ||
"(?:\\s*(?:\\,|\\)|\\)))?" + | ||
"(?:\\s*(este|esta|pasado|pr[óo]ximo)\\s*semana)?" + | ||
"(?=\\W|\\d|$)", | ||
"i" | ||
); | ||
|
||
const PREFIX_GROUP = 1; | ||
const WEEKDAY_GROUP = 2; | ||
const POSTFIX_GROUP = 3; | ||
|
||
export default class ESWeekdayParser extends AbstractParserWithWordBoundaryChecking { | ||
innerPattern(): RegExp { | ||
return PATTERN; | ||
} | ||
|
||
innerExtract(context: ParsingContext, match: RegExpMatchArray): ParsingComponents { | ||
const dayOfWeek = match[WEEKDAY_GROUP].toLowerCase(); | ||
const weekday = WEEKDAY_DICTIONARY[dayOfWeek]; | ||
if (weekday === undefined) { | ||
return null; | ||
} | ||
|
||
const prefix = match[PREFIX_GROUP]; | ||
const postfix = match[POSTFIX_GROUP]; | ||
let norm = prefix || postfix || ""; | ||
norm = norm.toLowerCase(); | ||
|
||
let modifier = null; | ||
if (norm == "pasado") { | ||
modifier = "this"; | ||
} else if (norm == "próximo" || norm == "proximo") { | ||
modifier = "next"; | ||
} else if (norm == "este") { | ||
modifier = "this"; | ||
} | ||
|
||
return createParsingComponentsAtWeekday(context.reference, weekday, modifier); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/* | ||
*/ | ||
|
||
import AbstractMergeDateRangeRefiner from "../../../common/refiners/AbstractMergeDateRangeRefiner"; | ||
|
||
/** | ||
* Merging before and after results (see. AbstractMergeDateRangeRefiner) | ||
* | ||
*/ | ||
export default class ESMergeDateRangeRefiner extends AbstractMergeDateRangeRefiner { | ||
patternBetween(): RegExp { | ||
return /^\s*(?:-)\s*$/i; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import AbstractMergeDateTimeRefiner from "../../../common/refiners/AbstractMergeDateTimeRefiner"; | ||
|
||
/** | ||
* Merging date-only result and time-only result (see. AbstractMergeDateTimeRefiner). | ||
*/ | ||
export default class ESMergeDateTimeRefiner extends AbstractMergeDateTimeRefiner { | ||
patternBetween(): RegExp { | ||
return new RegExp("^\\s*(?:,|de|aslas|a)?\\s*$"); | ||
} | ||
} |
Oops, something went wrong.