Skip to content

Split leap-year and weekday-match intents#184

Merged
JarbasAl merged 11 commits into
devfrom
feat/split-date-check-intents
May 10, 2026
Merged

Split leap-year and weekday-match intents#184
JarbasAl merged 11 commits into
devfrom
feat/split-date-check-intents

Conversation

@goldyfruit

@goldyfruit goldyfruit commented Mar 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • split leap-year yes/no queries into a dedicated is.leap.year.intent
  • split weekday yes/no checks into a dedicated weekday.matches.date.intent
  • add the matching English and French intents, dialogs, and translation snapshots

Context

This pulls the new behavior out of #183 so the French locale PR stays translation-focused.

Summary by CodeRabbit

  • New Features

    • Leap-year queries: ask whether this year, next year, or "either" is a leap year.
    • Weekday matching: ask if a given date falls on a specified weekday.
  • Localization

    • Added English and French dialogs, intents, vocab and weekday entities for leap-year and weekday-date queries.
  • Bug Fixes

    • Improved handling of failed date extraction to prevent incorrect follow-up responses.

@coderabbitai

coderabbitai Bot commented Mar 9, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c2ef4ac7-b592-4a91-a744-ab300ecbf6d0

📥 Commits

Reviewing files that changed from the base of the PR and between 9bc8d33 and 66ca248.

📒 Files selected for processing (43)
  • __init__.py
  • locale/en-US/dialog/leap.year.current.no.dialog
  • locale/en-US/dialog/leap.year.current.yes.dialog
  • locale/en-US/dialog/leap.year.either.no.dialog
  • locale/en-US/dialog/leap.year.either.yes.dialog
  • locale/en-US/dialog/leap.year.next.no.dialog
  • locale/en-US/dialog/leap.year.next.yes.dialog
  • locale/en-US/dialog/weekday.matches.date.future.no.dialog
  • locale/en-US/dialog/weekday.matches.date.future.yes.dialog
  • locale/en-US/dialog/weekday.matches.date.past.no.dialog
  • locale/en-US/dialog/weekday.matches.date.past.yes.dialog
  • locale/en-US/dialog/weekday.matches.date.today.no.dialog
  • locale/en-US/dialog/weekday.matches.date.today.yes.dialog
  • locale/en-US/intents/is.leap.year.intent
  • locale/en-US/intents/next.leap.year.intent
  • locale/en-US/intents/weekday.for.date.intent
  • locale/en-US/intents/weekday.matches.date.intent
  • locale/en-US/vocab/leap.year.scope.either.voc
  • locale/en-US/vocab/leap.year.scope.next.voc
  • locale/en-US/weekday.entity
  • locale/fr-FR/dialog/leap.year.current.no.dialog
  • locale/fr-FR/dialog/leap.year.current.yes.dialog
  • locale/fr-FR/dialog/leap.year.either.no.dialog
  • locale/fr-FR/dialog/leap.year.either.yes.dialog
  • locale/fr-FR/dialog/leap.year.next.no.dialog
  • locale/fr-FR/dialog/leap.year.next.yes.dialog
  • locale/fr-FR/dialog/weekday.matches.date.future.no.dialog
  • locale/fr-FR/dialog/weekday.matches.date.future.yes.dialog
  • locale/fr-FR/dialog/weekday.matches.date.past.no.dialog
  • locale/fr-FR/dialog/weekday.matches.date.past.yes.dialog
  • locale/fr-FR/dialog/weekday.matches.date.today.no.dialog
  • locale/fr-FR/dialog/weekday.matches.date.today.yes.dialog
  • locale/fr-FR/intents/is.leap.year.intent
  • locale/fr-FR/intents/weekday.matches.date.intent
  • locale/fr-FR/vocab/leap.year.scope.either.voc
  • locale/fr-FR/vocab/leap.year.scope.next.voc
  • locale/fr-FR/weekday.entity
  • translations/en-us/dialogs.json
  • translations/en-us/entities.json
  • translations/en-us/intents.json
  • translations/fr-fr/dialogs.json
  • translations/fr-fr/entities.json
  • translations/fr-fr/intents.json
✅ Files skipped from review due to trivial changes (39)
  • locale/fr-FR/dialog/weekday.matches.date.future.yes.dialog
  • locale/en-US/dialog/leap.year.next.yes.dialog
  • locale/en-US/dialog/weekday.matches.date.future.yes.dialog
  • locale/en-US/dialog/leap.year.current.no.dialog
  • locale/en-US/dialog/weekday.matches.date.future.no.dialog
  • locale/en-US/dialog/weekday.matches.date.past.yes.dialog
  • locale/en-US/dialog/leap.year.either.no.dialog
  • locale/en-US/vocab/leap.year.scope.next.voc
  • locale/fr-FR/dialog/leap.year.next.yes.dialog
  • locale/en-US/dialog/leap.year.current.yes.dialog
  • locale/fr-FR/intents/weekday.matches.date.intent
  • locale/en-US/intents/weekday.matches.date.intent
  • locale/fr-FR/dialog/leap.year.current.yes.dialog
  • locale/fr-FR/intents/is.leap.year.intent
  • locale/fr-FR/dialog/leap.year.either.yes.dialog
  • locale/en-US/vocab/leap.year.scope.either.voc
  • locale/fr-FR/dialog/weekday.matches.date.today.no.dialog
  • locale/fr-FR/dialog/weekday.matches.date.past.yes.dialog
  • locale/en-US/dialog/weekday.matches.date.today.yes.dialog
  • locale/fr-FR/vocab/leap.year.scope.next.voc
  • locale/fr-FR/dialog/leap.year.next.no.dialog
  • locale/en-US/dialog/leap.year.either.yes.dialog
  • locale/fr-FR/dialog/leap.year.either.no.dialog
  • locale/fr-FR/dialog/weekday.matches.date.past.no.dialog
  • locale/fr-FR/dialog/leap.year.current.no.dialog
  • locale/fr-FR/dialog/weekday.matches.date.today.yes.dialog
  • translations/fr-fr/entities.json
  • locale/en-US/weekday.entity
  • locale/en-US/intents/is.leap.year.intent
  • locale/en-US/dialog/weekday.matches.date.today.no.dialog
  • locale/en-US/dialog/weekday.matches.date.past.no.dialog
  • locale/fr-FR/weekday.entity
  • locale/en-US/dialog/leap.year.next.no.dialog
  • translations/en-us/dialogs.json
  • translations/en-us/entities.json
  • locale/fr-FR/vocab/leap.year.scope.either.voc
  • locale/fr-FR/dialog/weekday.matches.date.future.no.dialog
  • translations/fr-fr/dialogs.json
  • locale/en-US/intents/weekday.for.date.intent
🚧 Files skipped from review as they are similar to previous changes (4)
  • locale/en-US/intents/next.leap.year.intent
  • translations/fr-fr/intents.json
  • init.py
  • translations/en-us/intents.json

📝 Walkthrough

Walkthrough

This PR extends TimeSkill with helpers for localized weekday entities and leap-year scope, adds two intent handlers (weekday.matches.date and is.leap.year), and supplies corresponding English and French locale data: intents, dialogs, vocab, and weekday entity files.

Changes

TimeSkill weekday & leap-year

Layer / File(s) Summary
Imports
__init__.py
Adds import calendar and ResourceFile import.
Helpers
__init__.py
Adds _load_cached_entity, _get_requested_weekday, _render_weekday, _get_leap_year_query_scope.
Handler fixes
__init__.py
Removes unused exception binding in handle_query_date; returns early in handle_weekday after speaking extract.date.error.
Weekday-match handler
__init__.py
Adds handle_weekday_match for weekday.matches.date.intent: parse weekday and date, compare dt.weekday(), speak localized yes/no by tense.
Leap-year handler
__init__.py
Adds handle_is_leap_year for is.leap.year.intent: classify scope and use calendar.isleap to select localized leap.year.{scope}.{yes

English locale resources

Layer / File(s) Summary
Dialog strings & entities (en-US)
translations/en-us/dialogs.json, locale/en-US/dialog/*, locale/en-US/weekday.entity
Adds leap-year dialog templates and weekday-match dialog templates plus weekday.entity.
Intents & vocab (en-US)
translations/en-us/intents.json, locale/en-US/intents/*, locale/en-US/vocab/*
Creates is.leap.year.intent and weekday.matches.date.intent; removes hardcoded weekday enumerations from weekday.for.date.intent; adds leap year scope vocab entries and intent training files.
Translations update
translations/en-us/entities.json
Appends weekday.entity translation list.

French locale resources

Layer / File(s) Summary
Dialog strings (fr-FR)
translations/fr-fr/dialogs.json, locale/fr-FR/dialog/*
Adds French leap-year and weekday-match dialog strings (yes/no variants).
Intents, vocab & entities (fr-FR)
translations/fr-fr/intents.json, locale/fr-FR/intents/*, locale/fr-FR/vocab/*, locale/fr-FR/weekday.entity
Adds is.leap.year.intent and weekday.matches.date.intent in French, vocab files for leap-year scope, and French weekday.entity; updates translations entries.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Intent as Intent Recognizer
    participant Handler as handle_weekday_match
    participant DateParser as Date Parser
    participant Dialog as Dialog System

    User->>Intent: "does July 4th fall on a Monday?"
    Intent->>Handler: weekday.matches.date.intent (weekday="monday", date="July 4th")
    Handler->>Handler: _get_requested_weekday(entities)
    Handler->>DateParser: parse date from message
    DateParser-->>Handler: datetime dt
    Handler->>Handler: compare dt.weekday() with requested weekday index
    alt Match Found
        Handler->>Dialog: speak weekday.matches.date.{tense}.yes (date, weekday)
    else No Match
        Handler->>Dialog: speak weekday.matches.date.{tense}.no (date, actual_weekday, weekday)
    end
    Dialog-->>User: Confirmation or correction
Loading
sequenceDiagram
    participant User
    participant Intent as Intent Recognizer
    participant Handler as handle_is_leap_year
    participant Classifier as _get_leap_year_query_scope
    participant Calendar as calendar.isleap
    participant Dialog as Dialog System

    User->>Intent: "is next year a leap year?"
    Intent->>Handler: is.leap.year.intent
    Handler->>Classifier: classify scope from utterance (next/current/either)
    Classifier-->>Handler: scope
    Handler->>Calendar: calendar.isleap(year)
    Calendar-->>Handler: True/False
    Handler->>Dialog: speak leap.year.{scope}.{yes|no} with year parameter
    Dialog-->>User: Answer about leap year
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 New handlers bound and ready to play,
Weekdays and leap years join the fray.
Locales sprout phrases in two tongues bright,
Caching and parsing keep responses light.
Hop, TimeSkill, hop — tell us the date tonight!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: splitting leap-year and weekday-match intents into separate, dedicated intent handlers. It is specific, concise, and directly reflects the core objective of the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/split-date-check-intents

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@JarbasAl JarbasAl requested a review from mikejgray March 9, 2026 01:57
@goldyfruit goldyfruit self-assigned this Mar 9, 2026
@goldyfruit goldyfruit added the translation Localization and translation changes label Mar 9, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
translations/fr-fr/intents.json (1)

20-29: Consider adding l'an prochain variants here.

_get_leap_year_query_scope() already checks for an prochain, but this intent set only trains l'année prochaine. Adding one or two l'an prochain examples would widen French coverage and exercise the branch you just added.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@translations/fr-fr/intents.json` around lines 20 - 29, The intent examples
for "/intents/is.leap.year.intent" lack colloquial "l'an prochain" variants
needed to train the model branch used by _get_leap_year_query_scope(); add one
or two phrases such as "l'an prochain est‑ce bissextile" or "l'an prochain
est‑elle bissextile" to translations/fr-fr/intents.json under that intent so the
"an prochain" pattern is covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@__init__.py`:
- Around line 621-632: The current comparison dt.date() >= now.date() treats
same-day queries as future; change the branching to three-way logic: if
dt.date() > now.date() treat as future (use the existing
"weekday.matches.date.future.yes"/"future.no"), elif dt.date() == now.date()
handle a neutral/today path (add dialog keys like
"weekday.matches.date.today.yes" and "weekday.matches.date.today.no") and else
treat as past (keep "weekday.matches.date.past.*"); update the code around the
dialog variable assignment and use dt.weekday() and expected_weekday exactly as
before to choose yes/no variants.
- Around line 200-202: The French weekday matcher only matches "tombe..." forms
so queries like "tombait-il" or "tombera-t-il" fall through; update the "fr"
regex (the entry containing the phrase pattern
rf"\b(?P<phrase>tombe(?:-t-il)?\s+un\s+(?P<weekday>{names}))\b") to accept
past/future conjugations (e.g., tombait-il, tombera-t-il, tomberait-il) by
expanding the alternation/quantifier in that pattern, so those variants route
into the existing handle_weekday_match() branch; leave handle_weekday_match()
unchanged.

In `@locale/fr-fr/dialog/weekday.matches.date.future.no.dialog`:
- Line 1: The French template string weekday.matches.date.future.no.dialog
currently prefixes the {date} token with a hard-coded "le" which breaks outputs
when nice_date(...) returns standalone relative dates (e.g., "aujourd'hui",
"demain"); update the template for weekday.matches.date.future.no.dialog to
remove the hard-coded "le " and use {date} alone so the generated phrase uses
whatever nice_date(...) returns without an extra article.

In `@locale/fr-fr/dialog/weekday.matches.date.future.yes.dialog`:
- Line 1: The template has a hard-coded "le" before {date} which breaks grammar
when handle_weekday_match() passes a preformatted nice_date(...) like
"aujourd'hui" or "demain"; remove the fixed article so the template reads "Oui,
{date} tombera un {weekday}." and ensure handle_weekday_match() / nice_date()
continues to supply already-correct, localized date strings without adding an
article.

---

Nitpick comments:
In `@translations/fr-fr/intents.json`:
- Around line 20-29: The intent examples for "/intents/is.leap.year.intent" lack
colloquial "l'an prochain" variants needed to train the model branch used by
_get_leap_year_query_scope(); add one or two phrases such as "l'an prochain
est‑ce bissextile" or "l'an prochain est‑elle bissextile" to
translations/fr-fr/intents.json under that intent so the "an prochain" pattern
is covered.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fef5fb79-a973-4c4c-8c21-088ebbd3c38f

📥 Commits

Reviewing files that changed from the base of the PR and between d8ed365 and 2062d6f.

📒 Files selected for processing (31)
  • __init__.py
  • locale/en-us/dialog/leap.year.current.no.dialog
  • locale/en-us/dialog/leap.year.current.yes.dialog
  • locale/en-us/dialog/leap.year.either.no.dialog
  • locale/en-us/dialog/leap.year.either.yes.dialog
  • locale/en-us/dialog/leap.year.next.no.dialog
  • locale/en-us/dialog/leap.year.next.yes.dialog
  • locale/en-us/dialog/weekday.matches.date.future.no.dialog
  • locale/en-us/dialog/weekday.matches.date.future.yes.dialog
  • locale/en-us/dialog/weekday.matches.date.past.no.dialog
  • locale/en-us/dialog/weekday.matches.date.past.yes.dialog
  • locale/en-us/intents/is.leap.year.intent
  • locale/en-us/intents/next.leap.year.intent
  • locale/en-us/intents/weekday.for.date.intent
  • locale/en-us/intents/weekday.matches.date.intent
  • locale/fr-fr/dialog/leap.year.current.no.dialog
  • locale/fr-fr/dialog/leap.year.current.yes.dialog
  • locale/fr-fr/dialog/leap.year.either.no.dialog
  • locale/fr-fr/dialog/leap.year.either.yes.dialog
  • locale/fr-fr/dialog/leap.year.next.no.dialog
  • locale/fr-fr/dialog/leap.year.next.yes.dialog
  • locale/fr-fr/dialog/weekday.matches.date.future.no.dialog
  • locale/fr-fr/dialog/weekday.matches.date.future.yes.dialog
  • locale/fr-fr/dialog/weekday.matches.date.past.no.dialog
  • locale/fr-fr/dialog/weekday.matches.date.past.yes.dialog
  • locale/fr-fr/intents/is.leap.year.intent
  • locale/fr-fr/intents/weekday.matches.date.intent
  • translations/en-us/dialogs.json
  • translations/en-us/intents.json
  • translations/fr-fr/dialogs.json
  • translations/fr-fr/intents.json

Comment thread __init__.py Outdated
Comment thread __init__.py Outdated
Comment thread locale/fr-fr/dialog/weekday.matches.date.future.no.dialog Outdated
Comment thread locale/fr-fr/dialog/weekday.matches.date.future.yes.dialog Outdated
@goldyfruit

Copy link
Copy Markdown
Collaborator Author

Split the __init__.py changes into #188 so this PR stays locale/resource-only.\n\n#188 now contains the leap-year and weekday-match handler code.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
__init__.py (1)

588-597: ⚠️ Potential issue | 🔴 Critical

Keep the weekday response inside the successful parse branch.

Line 595 is currently outside the else: block, so a failed extract_datetime() still falls through to self.speak_dialog(dialog, ...) with dialog unset.

Proposed fix
         if not dt:
             self.speak_dialog("extract.date.error")
         else:
             if dt >= now:
                 dialog = "weekday.at.date.future"
             else:
                 dialog = "weekday.at.date.past"
             # TODO - "today" should never trigger this intent, but if it does,
             #  should we handle it better? nice_date will return "today" in that case
-        self.speak_dialog(dialog, {
+            self.speak_dialog(dialog, {
                 "date": nice_date(dt, lang=self.lang, now=now),
                 "weekday": nice_weekday(dt, lang=self.lang)})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@__init__.py` around lines 588 - 597, The speak_dialog call is outside the
successful-parse branch causing a failed extract_datetime() to fall through with
dialog unset; move the self.speak_dialog(dialog, {...}) call so it is executed
inside the else: block where dialog is defined (the branch that sets dialog
based on dt >= now) and ensure the same variables (dt, now, self.lang) are in
scope for nice_date and nice_weekday; keep extract_datetime usage and the
weekday/dialog assignment logic as-is but enclose the speak_dialog invocation
within that else branch to prevent speaking with an undefined dialog.
♻️ Duplicate comments (1)
__init__.py (1)

195-199: ⚠️ Potential issue | 🟡 Minor

Support did … fall on … in the English matcher too.

Line 197 only matches does ... fall ..., so past-tense queries like “Did February 29, 2024 fall on a Thursday?” will miss the weekday extraction and end up in extract.date.error.

Proposed fix
             "en": [
                 rf"\b(?:is|was)\b.*?\b(?P<phrase>(?:on\s+)?(?:a|an)\s+(?P<weekday>{names}))\b",
-                rf"\bdoes\b.*?\b(?P<phrase>fall\s+(?:on\s+)?(?:a|an)\s+(?P<weekday>{names}))\b",
+                rf"\b(?:does|did)\b.*?\b(?P<phrase>fall\s+(?:on\s+)?(?:a|an)\s+(?P<weekday>{names}))\b",
                 rf"\bwill\b.*?\bbe\s+(?P<phrase>(?:on\s+)?(?:a|an)\s+(?P<weekday>{names}))\b",
             ],
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@__init__.py` around lines 195 - 199, The English regex list for weekday
extraction misses past-tense "did ... fall ..." queries (currently only matches
"does ... fall ..."), so update the pattern(s) in the "en" array to also match
"did" (e.g., change the second pattern that contains
\bdoes\b.*?\b(?P<phrase>fall...) to accept \bdoes\b|\bdid\b or add a separate
\bdid\b pattern) so past-tense queries like "Did February 29, 2024 fall on a
Thursday?" will capture the (?P<phrase>) and (?P<weekday>) groups; adjust the
same regex structure used in the existing pattern to keep group names identical.
🧹 Nitpick comments (1)
translations/fr-fr/dialogs.json (1)

98-100: Minor: Inconsistent character encoding style.

Line 99 uses the literal character 'était while other lines in this file (e.g., line 24) use Unicode escapes like \u00e9tait. This is functionally equivalent but creates slight inconsistency. Not a blocker—the prepare_translations.py and sync_translations.py scripts will handle either form correctly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@translations/fr-fr/dialogs.json` around lines 98 - 100, The translation entry
for "/dialog/weekday.matches.date.past.no.dialog" uses a literal accented
character ("était") which is inconsistent with other entries using Unicode
escapes; update the string value to replace "était" with the escaped form
("\u00e9tait") so it matches the file's encoding style and maintain consistency
with entries like the one at line 24.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@__init__.py`:
- Around line 588-597: The speak_dialog call is outside the successful-parse
branch causing a failed extract_datetime() to fall through with dialog unset;
move the self.speak_dialog(dialog, {...}) call so it is executed inside the
else: block where dialog is defined (the branch that sets dialog based on dt >=
now) and ensure the same variables (dt, now, self.lang) are in scope for
nice_date and nice_weekday; keep extract_datetime usage and the weekday/dialog
assignment logic as-is but enclose the speak_dialog invocation within that else
branch to prevent speaking with an undefined dialog.

---

Duplicate comments:
In `@__init__.py`:
- Around line 195-199: The English regex list for weekday extraction misses
past-tense "did ... fall ..." queries (currently only matches "does ... fall
..."), so update the pattern(s) in the "en" array to also match "did" (e.g.,
change the second pattern that contains \bdoes\b.*?\b(?P<phrase>fall...) to
accept \bdoes\b|\bdid\b or add a separate \bdid\b pattern) so past-tense queries
like "Did February 29, 2024 fall on a Thursday?" will capture the (?P<phrase>)
and (?P<weekday>) groups; adjust the same regex structure used in the existing
pattern to keep group names identical.

---

Nitpick comments:
In `@translations/fr-fr/dialogs.json`:
- Around line 98-100: The translation entry for
"/dialog/weekday.matches.date.past.no.dialog" uses a literal accented character
("était") which is inconsistent with other entries using Unicode escapes; update
the string value to replace "était" with the escaped form ("\u00e9tait") so it
matches the file's encoding style and maintain consistency with entries like the
one at line 24.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a9e6a373-5af1-4116-856c-d07787566389

📥 Commits

Reviewing files that changed from the base of the PR and between 2062d6f and 81a4319.

📒 Files selected for processing (13)
  • __init__.py
  • locale/en-us/dialog/weekday.matches.date.today.no.dialog
  • locale/en-us/dialog/weekday.matches.date.today.yes.dialog
  • locale/fr-fr/dialog/weekday.matches.date.future.no.dialog
  • locale/fr-fr/dialog/weekday.matches.date.future.yes.dialog
  • locale/fr-fr/dialog/weekday.matches.date.past.no.dialog
  • locale/fr-fr/dialog/weekday.matches.date.past.yes.dialog
  • locale/fr-fr/dialog/weekday.matches.date.today.no.dialog
  • locale/fr-fr/dialog/weekday.matches.date.today.yes.dialog
  • locale/fr-fr/intents/is.leap.year.intent
  • translations/en-us/dialogs.json
  • translations/fr-fr/dialogs.json
  • translations/fr-fr/intents.json
🚧 Files skipped from review as they are similar to previous changes (7)
  • translations/en-us/dialogs.json
  • locale/fr-fr/dialog/weekday.matches.date.future.yes.dialog
  • locale/fr-fr/dialog/weekday.matches.date.past.no.dialog
  • translations/fr-fr/intents.json
  • locale/fr-fr/dialog/weekday.matches.date.future.no.dialog
  • locale/fr-fr/intents/is.leap.year.intent
  • locale/fr-fr/dialog/weekday.matches.date.past.yes.dialog

@goldyfruit

Copy link
Copy Markdown
Collaborator Author

Added the locale parser resources that #188 now loads for weekday matching and leap-year scope detection.\n\nThat keeps #184 resource-only and removes the hardcoded en/fr parsing tables from #188.

@mikejgray mikejgray left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Some of these new intents don't have handlers in init.py, which means they would just break where they were moved. However, since you're only updating en-us and fr-fr, a code update must be backwards compatible or you must move the intents across all locales.

@goldyfruit

Copy link
Copy Markdown
Collaborator Author

Some of these new intents don't have handlers in init.py

It is here #188

@mikejgray

Copy link
Copy Markdown
Collaborator

Cross-linking my follow-up comment on #188 — TL;DR: let's recombine #184 and #188 into a single PR so we get one working alpha release instead of two PRs that have to land in lockstep. Full reasoning over there.

@goldyfruit

Copy link
Copy Markdown
Collaborator Author

Recombined this PR so it is self-contained again.

It now includes:

I am closing #188 as superseded so this can merge as one atomic alpha update.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
__init__.py (1)

573-579: ⚠️ Potential issue | 🟡 Minor

Use date-only comparison to avoid same-day misclassification in weekday-for-date replies.

At Line 573, dt >= now compares full timestamps. If dt is date-only (often midnight), same-day queries can fall into the past branch depending on current time.

Suggested fix
-        if dt >= now:
+        if dt.date() > now.date():
             dialog = "weekday.at.date.future"
+        elif dt.date() == now.date():
+            dialog = "weekday.at.date.future"  # or a dedicated "today" dialog if available
         else:
             dialog = "weekday.at.date.past"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@__init__.py` around lines 573 - 579, The comparison dt >= now uses full
datetimes and misclassifies same-day date-only inputs; update the condition to
compare dates only (e.g., compute left = dt.date() if dt has .date() else dt and
right = now.date() and then use left >= right) so the intent selection before
calling self.speak_dialog(dialog, {...}) uses date-only semantics; modify the
branch that sets dialog (currently using dt and now) to use these date-only
variables (or normalized datetimes at midnight) to avoid same-day
misclassification.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@__init__.py`:
- Around line 573-579: The comparison dt >= now uses full datetimes and
misclassifies same-day date-only inputs; update the condition to compare dates
only (e.g., compute left = dt.date() if dt has .date() else dt and right =
now.date() and then use left >= right) so the intent selection before calling
self.speak_dialog(dialog, {...}) uses date-only semantics; modify the branch
that sets dialog (currently using dt and now) to use these date-only variables
(or normalized datetimes at midnight) to avoid same-day misclassification.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 306e81c2-85b4-4562-89a5-368bef5edfc0

📥 Commits

Reviewing files that changed from the base of the PR and between 81a4319 and a56f993.

📒 Files selected for processing (11)
  • __init__.py
  • locale/en-us/leap.year.scope.either_phrases.list
  • locale/en-us/leap.year.scope.next_phrases.list
  • locale/en-us/weekday.match.patterns.list
  • locale/en-us/weekday.match.strip_prefixes.list
  • locale/en-us/weekday.match.strip_suffixes.list
  • locale/en-us/weekday.match.weekdays.value
  • locale/fr-fr/leap.year.scope.either_phrases.list
  • locale/fr-fr/leap.year.scope.next_phrases.list
  • locale/fr-fr/weekday.match.patterns.list
  • locale/fr-fr/weekday.match.weekdays.value
✅ Files skipped from review due to trivial changes (9)
  • locale/en-us/leap.year.scope.next_phrases.list
  • locale/en-us/leap.year.scope.either_phrases.list
  • locale/fr-fr/leap.year.scope.either_phrases.list
  • locale/en-us/weekday.match.strip_suffixes.list
  • locale/fr-fr/weekday.match.weekdays.value
  • locale/fr-fr/leap.year.scope.next_phrases.list
  • locale/en-us/weekday.match.weekdays.value
  • locale/en-us/weekday.match.strip_prefixes.list
  • locale/fr-fr/weekday.match.patterns.list

@github-actions

github-actions Bot commented Apr 7, 2026

Copy link
Copy Markdown

The bots have finished their work. Take a look! 🤖

I've aggregated the results of the automated checks for this PR below.

🎙️ Skill

I've given your skill a thorough inspection! 🕵️

🎙️ ovos-skill-date-time.openvoiceos — 20 languages

en-US: 14 intents · 2 vocab · 30 dialogs · skill.json ✅

Translation coverage — 19 languages (1 complete, 7 partial, 11 incomplete)
Language Progress Coverage
ca-ES ██████░░░░ ⚠️ 63.6% (35/55)
cs-CZ ███░░░░░░░ ❌ 32.7% (18/55)
da-DK ██████░░░░ ⚠️ 60.0% (33/55)
de-DE ██████░░░░ ⚠️ 63.6% (35/55)
es-ES ██████░░░░ ⚠️ 63.6% (35/55)
eu-ES █████░░░░░ ❌ 47.3% (26/55)
fa-IR ████░░░░░░ ❌ 43.6% (24/55)
fr-FR ██████████ ✅ 100.0% (55/55)
gl-ES ██████░░░░ ⚠️ 63.6% (35/55)
hu-HU ███░░░░░░░ ❌ 32.7% (18/55)
it-IT ████░░░░░░ ❌ 41.8% (23/55)
nl-NL ███░░░░░░░ ❌ 34.5% (19/55)
pl-PL ███░░░░░░░ ❌ 32.7% (18/55)
pt-BR ██████░░░░ ⚠️ 63.6% (35/55)
pt-PT █████░░░░░ ⚠️ 52.7% (29/55)
ru-RU ███░░░░░░░ ❌ 32.7% (18/55)
sv-FI ███░░░░░░░ ❌ 32.7% (18/55)
sv-SE ███░░░░░░░ ❌ 32.7% (18/55)
tr-TR ███░░░░░░░ ❌ 34.5% (19/55)

🔍 Lint

Another check completed successfully! 🏁

ruff: no issues

📊 Coverage

A deep dive into the sea of test results. 🌊

20.2% total coverage

Per-file coverage (3 files)
File Coverage Missing lines
setup.py 0.0% 50
version.py 0.0% 4
__init__.py 22.9% 313

Full report: download the coverage-report artifact.

🔌 Skill Tests (ovoscope)

Scanning for any 'resource leaks' during long usage. 🚰

0/0 passed

🚌 Bus Coverage

Peeking under the hood at the message traffic. 🏎️

⚠️ Bus coverage report unavailable — check the job log.

🏷️ Release Preview

I've checked the 'Legal' section for the release. ⚖️

Current: 1.1.10a3Next: 1.1.10a4

Signal Value
Label translation
PR title Split leap-year and weekday-match intents
Bump alpha

⚠️ No conventional commit prefix — alpha-only bump.
Suggested: fix: update the thing or feat: update the thing


🚀 Release Channel Compatibility

Predicted next version: 1.1.10a4

Channel Status Note Current Constraint
Stable Too new (must be <0.5.0) ovos-skill-date-time>=0.4.20,<0.5.0
Testing Compatible ovos-skill-date-time>=1.1.5,<2.0.0
Alpha Compatible ovos-skill-date-time>=1.1.10a2

📋 Repo Health

I've checked the repo's flexibility (aka refactorability). 🧘‍♂️

✅ All required files present.

Latest Version: 1.1.10a3

version.py — Version file
README.md — README
LICENSE — License file
⚠️ pyproject.toml — pyproject.toml
setup.py — setup.py
CHANGELOG.md — Changelog
requirements.txt — Requirements
version.py has valid version block markers

🔒 Security (pip-audit)

Evaluating the risk associated with these changes. ⚖️

✅ No known vulnerabilities found (84 packages scanned).

🔨 Build Tests

Checking if the code is ready for prime time. 📺

✅ All versions pass

Python Build Install Tests
3.10
3.11
3.12
3.13
3.14

⚖️ License Check

I've checked the licenses of our bundled assets. 📦

✅ No license violations found (64 packages).

License distribution: 15× MIT License, 11× Apache Software License, 10× MIT, 7× Apache-2.0, 3× BSD-3-Clause, 2× BSD License, 2× ISC License (ISCL), 2× PSF-2.0, +10 more

Full breakdown — 64 packages
Package Version License URL
audioop-lts 0.2.2 PSF-2.0 link
build 1.5.0 MIT link
certifi 2026.4.22 Mozilla Public License 2.0 (MPL 2.0) link
cffi 2.0.0 MIT link
charset-normalizer 3.4.7 MIT link
click 8.3.3 BSD-3-Clause link
combo_lock 0.3.1 Apache-2.0 link
dateparser 1.4.0 BSD License link
decorator 5.2.1 BSD License
filelock 3.29.0 MIT link
flatbuffers 25.12.19 Apache Software License link
ftfy 6.3.1 Apache-2.0 link
future 1.0.0 MIT License link
geocoder 1.38.1 Apache Software License link
h3 4.4.2 Apache Software License link
idna 3.14 BSD-3-Clause link
importlib_metadata 9.0.0 Apache-2.0 link
json-database 0.10.1 MIT link
kthread 0.2.3 MIT License link
langcodes 3.5.1 MIT License link
markdown-it-py 4.2.0 MIT License link
mdurl 0.1.2 MIT License link
memory-tempfile 2.2.3 MIT License link
numpy 2.4.4 BSD-3-Clause AND 0BSD AND MIT AND Zlib AND CC0-1.0 link
ovos-config 2.1.1 Apache-2.0 link
ovos-date-parser 0.6.5 Apache Software License link
ovos-number-parser 0.5.1 Apache Software License link
ovos-plugin-manager 2.2.0 Apache-2.0 link
ovos-skill-date-time 1.1.10a3 Apache-2.0 link
ovos-solver-yes-no-plugin 0.2.8 MIT link
ovos-utils 0.8.5 Apache-2.0 link
ovos-utterance-normalizer 0.2.3 Apache Software License link
ovos_bus_client 1.5.0 Apache Software License link
ovos_workshop 8.0.0 apache-2.0 link
packaging 26.2 Apache-2.0 OR BSD-2-Clause link
padacioso 1.0.0 apache-2.0 link
pexpect 4.9.0 ISC License (ISCL) link
ptyprocess 0.7.0 ISC License (ISCL) link
pycparser 3.0 BSD-3-Clause link
pyee 12.1.1 MIT License link
Pygments 2.20.0 BSD-2-Clause link
pyproject_hooks 1.2.0 MIT License link
python-dateutil 2.9.0.post0 Apache Software License; BSD License link
pytz 2026.2 MIT License link
PyYAML 6.0.3 MIT License link
quebra-frases 0.3.7 Apache Software License link
RapidFuzz 3.14.5 MIT link
ratelim 0.1.6 MIT link
regex 2026.5.9 Apache-2.0 AND CNRI-Python link
requests 2.33.1 Apache Software License link
rich 13.9.4 MIT License link
rich-click 1.9.7 MIT License

Copyright (c) 2022 Phil Ewels

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
| link |
| simplematch | 1.4 | MIT License | link |
| six | 1.17.0 | MIT License | link |
| standard-aifc | 3.13.0 | Python Software Foundation License | link |
| standard-chunk | 3.13.0 | Python Software Foundation License | link |
| timezonefinder | 8.2.4 | The MIT License (MIT)

Copyright (c) 2016 Jannik Michelfeit

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
| link |
| typing_extensions | 4.15.0 | PSF-2.0 | link |
| tzlocal | 5.3.1 | MIT License | link |
| unicode-rbnf | 2.4.0 | MIT License | |
| urllib3 | 2.7.0 | MIT | link |
| watchdog | 6.0.0 | Apache Software License | link |
| websocket-client | 1.9.0 | Apache Software License | link |
| zipp | 3.23.1 | MIT | link |

Policy: Apache 2.0 (universal donor). StrongCopyleft / NetworkCopyleft / WeakCopyleft / Other / Error categories fail. MPL allowed.


Your automated companion in the OpenVoiceOS journey. 🤝

@@ -0,0 +1 @@
\b(?P<phrase>(?:tombe(?:-t-il)?|tombait(?:-il)?|tombera(?:-t-il)?|tomberait(?:-il)?)\s+un\s+(?P<weekday>__WEEKDAY_NAMES__))\b

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this is very hard to translate for regular users, please try to avoid regex

@JarbasAl

JarbasAl commented Apr 8, 2026

Copy link
Copy Markdown
Member

do we need a extract-weekday in ovos-date-parser? i'd prefer to keep skills minimal and more focused on the voice part.

I also discourage using regex for translatable resources.

what about using {weekday} capture group in .intent files + weekday.entity files?

Comment thread locale/en-US/vocab/leap.year.scope.next.voc
@goldyfruit

goldyfruit commented Apr 8, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed Jarbas' review points on this branch.

  • replaced the translator-facing weekday regex resources with {weekday} capture in the .intent files plus new weekday.entity files
  • replaced leap-year scope phrase .list files with .voc resources and switched the code to self.voc_match(...)
  • removed the weekday regex stripping/parsing helpers from __init__.py
  • kept the loader test fix in place and revalidated the branch

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@__init__.py`:
- Around line 670-705: handle_is_leap_year currently passes the non-leap year
into speak_dialog for the "next" and "current" scopes; update the call sites so
when calendar.isleap(next_year) is False you pass {"year":
get_next_leap_year(next_year)} and when calendar.isleap(current_year) is False
you pass {"year": get_next_leap_year(current_year)} (leave the "either" branch
as-is or optionally use get_next_leap_year(next_year) there); modify the
branches around calendar.isleap in handle_is_leap_year to compute and pass the
correct next leap year to speak_dialog.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3046f41f-7d34-422b-8945-84f42b28765f

📥 Commits

Reviewing files that changed from the base of the PR and between 9bc8d33 and 0426263.

📒 Files selected for processing (13)
  • __init__.py
  • locale/en-US/intents/weekday.matches.date.intent
  • locale/en-US/vocab/leap.year.scope.either.voc
  • locale/en-US/vocab/leap.year.scope.next.voc
  • locale/en-US/weekday.entity
  • locale/fr-FR/intents/weekday.matches.date.intent
  • locale/fr-FR/vocab/leap.year.scope.either.voc
  • locale/fr-FR/vocab/leap.year.scope.next.voc
  • locale/fr-FR/weekday.entity
  • translations/en-us/entities.json
  • translations/en-us/intents.json
  • translations/fr-fr/entities.json
  • translations/fr-fr/intents.json
✅ Files skipped from review due to trivial changes (10)
  • locale/fr-FR/vocab/leap.year.scope.either.voc
  • locale/en-US/vocab/leap.year.scope.either.voc
  • locale/fr-FR/vocab/leap.year.scope.next.voc
  • locale/fr-FR/intents/weekday.matches.date.intent
  • locale/en-US/intents/weekday.matches.date.intent
  • locale/fr-FR/weekday.entity
  • locale/en-US/weekday.entity
  • translations/fr-fr/entities.json
  • translations/en-us/entities.json
  • locale/en-US/vocab/leap.year.scope.next.voc
🚧 Files skipped from review as they are similar to previous changes (1)
  • translations/en-us/intents.json

Comment thread __init__.py Outdated
@goldyfruit goldyfruit requested a review from mikejgray April 9, 2026 16:13

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
__init__.py (1)

687-689: Consider simplifying to get_next_leap_year(next_year) for consistency.

Line 689 uses get_next_leap_year(next_year + 1), while lines 697 and 705 use get_next_leap_year(next_year) and get_next_leap_year(current_year) respectively. Since get_next_leap_year(year) returns the next leap year after year, the + 1 is unnecessary when next_year is already confirmed non-leap. Using get_next_leap_year(next_year) would yield the same result and maintain consistency.

♻️ Optional consistency fix
             else:
                 self.speak_dialog("leap.year.either.no",
-                                  {"year": get_next_leap_year(next_year + 1)})
+                                  {"year": get_next_leap_year(next_year)})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@__init__.py` around lines 687 - 689, Replace the call
get_next_leap_year(next_year + 1) with get_next_leap_year(next_year) to remove
the unnecessary +1; locate the branch that calls
self.speak_dialog("leap.year.either.no", {"year": ...}) and update the argument
so it consistently uses get_next_leap_year(next_year) (the helper
get_next_leap_year already returns the next leap year after the given year).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@__init__.py`:
- Around line 687-689: Replace the call get_next_leap_year(next_year + 1) with
get_next_leap_year(next_year) to remove the unnecessary +1; locate the branch
that calls self.speak_dialog("leap.year.either.no", {"year": ...}) and update
the argument so it consistently uses get_next_leap_year(next_year) (the helper
get_next_leap_year already returns the next leap year after the given year).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dde80695-1bfd-48db-9393-e78e464ca805

📥 Commits

Reviewing files that changed from the base of the PR and between 9bc8d33 and a9ed20a.

📒 Files selected for processing (13)
  • __init__.py
  • locale/en-US/intents/weekday.matches.date.intent
  • locale/en-US/vocab/leap.year.scope.either.voc
  • locale/en-US/vocab/leap.year.scope.next.voc
  • locale/en-US/weekday.entity
  • locale/fr-FR/intents/weekday.matches.date.intent
  • locale/fr-FR/vocab/leap.year.scope.either.voc
  • locale/fr-FR/vocab/leap.year.scope.next.voc
  • locale/fr-FR/weekday.entity
  • translations/en-us/entities.json
  • translations/en-us/intents.json
  • translations/fr-fr/entities.json
  • translations/fr-fr/intents.json
✅ Files skipped from review due to trivial changes (11)
  • locale/en-US/vocab/leap.year.scope.next.voc
  • locale/en-US/vocab/leap.year.scope.either.voc
  • locale/fr-FR/vocab/leap.year.scope.next.voc
  • locale/fr-FR/intents/weekday.matches.date.intent
  • locale/fr-FR/vocab/leap.year.scope.either.voc
  • locale/en-US/weekday.entity
  • locale/fr-FR/weekday.entity
  • translations/fr-fr/entities.json
  • translations/en-us/entities.json
  • locale/en-US/intents/weekday.matches.date.intent
  • translations/fr-fr/intents.json

@goldyfruit goldyfruit force-pushed the feat/split-date-check-intents branch from a9ed20a to 66ca248 Compare May 10, 2026 22:47
@JarbasAl JarbasAl merged commit 514f470 into dev May 10, 2026
14 of 15 checks passed
@JarbasAl JarbasAl deleted the feat/split-date-check-intents branch May 10, 2026 23:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

translation Localization and translation changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants