Skip to content

refactor(i18n): show plan usage reports from Kiro to OpenRouter through Fluent - #969

Merged
penso merged 16 commits into
mainfrom
i18n/usage-providers-c
Nov 1, 2026
Merged

penso merged 16 commits into
mainfrom
i18n/usage-providers-c

Conversation

@penso

@penso penso commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #968 (base i18n/usage-providers-b), and through it on #967 and #955. Merge those first.

Summary

Part of Phase 2 of docs/i18n.md: the herdr-usage report words, following #967. This PR covers 19 providers, Kiro through OpenRouter: Kiro, LiteLLM, llmman, LLM Proxy, LongCat, Manus, MiMo, MiniMax, Mistral, Moonshot, Muse, Neuralwatt, Notion, Nous, Ollama, OpenAI, OpenCode, OpenCode Go, and OpenRouter. OneConsole is shared gateway code and shows no words.

  • Messages: each provider names its report's words in its own usage-<provider>.ftl. usage-kiro.ftl is new. Plans, models, product names (Vibe, Notion AI, Ollama Cloud, OpenCode Go), and the services' own status words stay as the service sends them.

  • OpenAI: unnamed line items and models used English fallback keys ("API", "Responses and Chat Completions"). They are now None and shown through messages. A line item the API itself calls "API" no longer merges with unnamed ones.

  • LiteLLM: the spend parser matched its own label string. It now takes a Reporter enum, and the period value ("start – end UTC") is a message.

  • MiniMax: the daily and hourly window names take a nested $service argument, either a message such as "Video" or the model's name.

  • Plurals: MiMo's credits, Neuralwatt's requests, and Muse's hours are Fluent selectors. These read as before except at 1, where they now say "1 credit" instead of "1 credits".

  • Window order: Report::new sorts named windows by their words, which for a message is its ID and arguments. I tried keeping each provider's insertion order instead, but several providers (Antigravity, Cursor, Factory, Gemini, Manus, Windsurf) build windows from maps and relied on the alphabetical sort. So the sort stays. Message IDs are chosen so each provider's windows keep their order, and its tests hold it. Report::new documents this.

  • Tests: herdr-usage tests assert message IDs and arguments. usage/tests/words_c.rs checks that each provider's English reads as it wrote it, for every selector value.

  • docs/i18n.md is left as main has it: one later change updates its "What is left" list once the open i18n PRs merge.

Screenshots

None for this PR: these providers need real sign-ins, which the isolated sandbox doesn't have. #967 shows the same panel and section code with a provider whose report is fully named.

QA

  • just format
  • just ci on 49cdc1a2d (macOS arm64): passed, with its base and origin/main merged in
  • herdr-usage tests (429), with each provider's window order unchanged
  • words_c.rs: each provider's English reads as before (except the singulars noted above)
  • Report message scan: every ID exists with exactly its chained arguments
  • With a signed-in OpenAI, OpenRouter, or Mistral account under en-XA: the panel's own labels are bracketed, and model and plan names stay as sent
  • English: these providers' panels read as before

🤖 Generated with Claude Code

https://claude.ai/code/session_01BFavh7vQNk6CpU1rxrJkHw

penso added 5 commits October 31, 2026 21:12
Each usage provider's settings carried their help as English in
herdr-usage, which the usage panel's Setup block showed as written.

Setting::help becomes Setting::message, the ID of a message in the
provider's own locales/en-US/usage-<id>.ftl (156 messages across the
providers that read settings). The panel shows it with i18n::message.
One file per provider keeps parallel provider PRs out of each other's
catalogs.

The example config's generated provider section came from the English in
herdr-usage. Its generator and bless test move to the app's usage tests,
which read the English messages. The section is unchanged byte for byte.
A new test checks that every setting names a message without arguments,
and the en-XA leak test no longer allows the help as data.
herdr-usage reports carried English Strings for section titles, fact
labels and values, share labels, balance labels, window names, and the
account line, and count units as English words, which the usage panel
showed whatever the language.

herdr_usage::Text is now the words a report shows: a message ID with
arguments, which the app writes with usage::text::words, or the service's
own words. Count units are a typed Count the app writes with a plural
(usage-amount-*). Wayfinder names all of its words in usage-wayfinder.ftl;
the other providers keep their English through a transitional
From<&str>/From<String> for Text and pair/pairs/share/shares helpers,
which go once the last of them names its words.

A crate below the app cannot use fl!'s compile-time check, so an app test
scans herdr-usage for Text::message IDs and the arguments chained to
them and checks each against the English messages. The en-XA leak test
now draws facts, shares, and a credits balance a provider names.
A fact's value sat at its natural width, so a longer one, as en-XA or
another language writes it, ran past the usage card's edge. The value
may now shrink and wraps under itself, set against the end side.
…Fluent

Copilot, Cursor, Deepgram, DeepInfra, DeepSeek, Devin, DevPass, Doubao,
ElevenLabs, Factory, Fireworks, Gemini, GitKraken, Grok, Groq, Helmcode,
Hugging Face, Hyper, IBM Bob, JetBrains, Kilo, and Kimi now name each
word their reports show in their own usage-<provider>.ftl: section
titles, fact labels, values with English words or plurals, balance
labels, the windows they name, and plan lines they compose. Names the
services send (plans, models, tenants, products) stay as the service's
words, and none of them uses Text's transitional conversions.

Where a provider matched its own English labels (Cursor's on-demand
budget, Doubao's window periods), it now carries a selector key the
message picks by. Counts whose English never had a singular ("1
credits") keep it byte for byte, with only an other variant for
translators to extend. usage/tests/words_b.rs checks each provider's
messages read in English as it wrote them.
…gh Fluent

Kiro, LiteLLM, llmman, LLM Proxy, LongCat, Manus, MiMo, MiniMax,
Mistral, Moonshot, Muse, Neuralwatt, Notion, Nous, Ollama, OpenAI,
OpenCode, OpenCode Go, and OpenRouter now name each word their reports
show in their own usage-<provider>.ftl. Plans, models, product names
(Vibe, Notion AI, Ollama Cloud), and the services' own status words stay
as the service's words. OneConsole is shared gateway code and shows
none.

OpenAI's unnamed line items and models are now None rather than English
fallback keys, and show through messages. LiteLLM's spend parser takes a
Reporter enum instead of matching its own label. MiMo, Neuralwatt, and
Muse counts gain a singular ("1 credit" where it said "1 credits").

Named windows sort by their words; message IDs are chosen so each
provider's windows keep their order, which its tests hold, and
Report::new documents it. usage/tests/words_c.rs checks each provider's
English reads as it wrote it.
@penso

penso commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator Author

just ci ran locally and passed on 49cdc1a2d (macOS arm64).

@greptile-apps

greptile-apps Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no blocking issue was found.

Summary

Moves report text for 19 providers, Kiro through OpenRouter, into Fluent messages while keeping service names unchanged.

  • Usage reports show provider labels and combined wording through Fluent messages.

Reviews (4) · Last reviewed commit: "Merge branch 'i18n/usage-providers-b' in..." · Reviewed by Greptile

@penso

penso commented Nov 1, 2026

Copy link
Copy Markdown
Collaborator Author

just ci ran locally and passed on aa4ed2c42 (macOS arm64).

penso added 2 commits November 1, 2026 09:49
Named windows became message IDs in this branch, and the usage command
labeled each window with `Kind::title`, which gives a named window's ID:
it printed usage-copilot-premium instead of Premium, and Doubao's window
lost its plan and period, which only the message's arguments carry. The
command now writes a named window through `usage::text::english`, and a
test checks the labels and the JSON the command answers.
@penso

penso commented Nov 1, 2026

Copy link
Copy Markdown
Collaborator Author

@greptileai review

penso added 5 commits November 1, 2026 11:02
Every open i18n pull request edits the remaining list in docs/i18n.md, so
each merge made the others conflict. This branch now keeps main's copy;
one change updates the list once they have all merged.
@penso

penso commented Nov 1, 2026

Copy link
Copy Markdown
Collaborator Author

@greptileai review

@penso

penso commented Nov 1, 2026

Copy link
Copy Markdown
Collaborator Author

@greptileai review

Base automatically changed from i18n/usage-providers-b to main November 1, 2026 21:44
@netlify

netlify Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for herdr-ui canceled.

Name Link
🔨 Latest commit 7506078
🔍 Latest deploy log https://app.netlify.com/projects/herdr-ui/deploys/6ae7b2ba89cdad7533b359e0

@penso
penso merged commit 44ccf52 into main Nov 1, 2026
4 checks passed
@penso
penso deleted the i18n/usage-providers-c branch November 1, 2026 21:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant