feat(i18n): make lib.js strings I18n source keys (strategy A); remove dead symbol exports; update tests; add i18n/ scaffolding + en.json placeholder
- getStrings().copied now returns template key "Copied %1 to clipboard" (interpolation at QML call site via .arg) - Removed unused clearExitNode/setExitNode from getStrings (were dead code) - Tests updated for new shape while preserving coverage - New tailscalectl/i18n/ with README + en.json for future-proofing (per dms-plugin-dev best practice) - Exact behavior preserved; no logic changes Written by AI agent working for @jtmorris. Model: grok-build-0.1.
This commit is contained in:
parent
bc864bb9d8
commit
eb5325af9b
4 changed files with 59 additions and 7 deletions
40
tailscalectl/i18n/README.md
Normal file
40
tailscalectl/i18n/README.md
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# I18n for tailscalectl
|
||||
|
||||
This plugin is fully instrumented with `I18n.tr(...)` (from `qs.Common`) for all user-facing strings.
|
||||
|
||||
- Source keys are the American English strings defined in `lib.js` (returned by `getStrings()`, plus bases from `errorMessage()` / `formatError()`).
|
||||
- Call sites in `TailscaleWidget.qml` wrap them: `I18n.tr(TailscaleLib.getStrings().foo)` or `I18n.tr(TailscaleLib.getStrings().copied).arg(text)`.
|
||||
- Today: falls back to the key (perfect en-US).
|
||||
- Future: Drop additional `xx.json` here (or contribute keys to DMS core translations) when a loader or extraction process supports per-plugin locales.
|
||||
|
||||
## Current keys (source of truth)
|
||||
|
||||
See `getStrings()` and `errorMessage()` in `lib.js` for the canonical list.
|
||||
|
||||
Example `en.json` (for documentation / future tools):
|
||||
|
||||
```json
|
||||
{
|
||||
"Tailscale": "Tailscale",
|
||||
"Connected": "Connected",
|
||||
"Disconnected": "Disconnected",
|
||||
"Exit node: ": "Exit node: ",
|
||||
"None": "None",
|
||||
"Copied %1 to clipboard": "Copied %1 to clipboard",
|
||||
"Invalid exit node hostname": "Invalid exit node hostname",
|
||||
"Failed to connect to Tailscale": "Failed to connect to Tailscale",
|
||||
"Failed to disconnect from Tailscale": "Failed to disconnect from Tailscale",
|
||||
"Failed to set exit node": "Failed to set exit node",
|
||||
"Failed to read Tailscale status": "Failed to read Tailscale status",
|
||||
"Error copying to clipboard": "Error copying to clipboard",
|
||||
"Tailscale command failed": "Tailscale command failed"
|
||||
}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Symbols/glyphs ("×", "↗", "—") are intentionally left as literals in the UI (not run through I18n as they are not linguistic content).
|
||||
- Plugin name/description in `plugin.json` and technical IDs ("tailscalectl") remain English.
|
||||
- This follows DMS `dms-plugin-dev` best practice for future-proofing even when only en is shipped.
|
||||
|
||||
Written by AI agent working for @jtmorris. Model: grok-build-0.1.
|
||||
15
tailscalectl/i18n/en.json
Normal file
15
tailscalectl/i18n/en.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"Tailscale": "Tailscale",
|
||||
"Connected": "Connected",
|
||||
"Disconnected": "Disconnected",
|
||||
"Exit node: ": "Exit node: ",
|
||||
"None": "None",
|
||||
"Copied %1 to clipboard": "Copied %1 to clipboard",
|
||||
"Invalid exit node hostname": "Invalid exit node hostname",
|
||||
"Failed to connect to Tailscale": "Failed to connect to Tailscale",
|
||||
"Failed to disconnect from Tailscale": "Failed to disconnect from Tailscale",
|
||||
"Failed to set exit node": "Failed to set exit node",
|
||||
"Failed to read Tailscale status": "Failed to read Tailscale status",
|
||||
"Error copying to clipboard": "Error copying to clipboard",
|
||||
"Tailscale command failed": "Tailscale command failed"
|
||||
}
|
||||
|
|
@ -52,9 +52,7 @@ function getStrings() {
|
|||
disconnected: "Disconnected",
|
||||
exitNodePrefix: "Exit node: ",
|
||||
none: "None",
|
||||
copied: function (text) { return "Copied " + text + " to clipboard"; },
|
||||
clearExitNode: "×",
|
||||
setExitNode: "↗",
|
||||
copied: "Copied %1 to clipboard",
|
||||
invalidExitNodeHostname: "Invalid exit node hostname"
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,10 +115,9 @@ test("getStrings returns canonical UI strings for the widget", () => {
|
|||
assert.ok(s.copied)
|
||||
})
|
||||
|
||||
test("getStrings.copied interpolates the text", () => {
|
||||
const s = getStrings()
|
||||
const msg = s.copied("100.64.0.5")
|
||||
assert.ok(msg.includes("100.64.0.5"))
|
||||
test("getStrings.copied is the I18n template key (interpolation happens at call site via .arg)", () => {
|
||||
const s = getStrings();
|
||||
assert.strictEqual(s.copied, "Copied %1 to clipboard");
|
||||
})
|
||||
|
||||
test("shouldShowClearExitNode returns true only when there is a current exit node", () => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue