@walkinissue/angy 0.2.17 → 0.2.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -189
- package/dist/client/Angy.svelte +751 -546
- package/dist/client/RotationWarningDialog.svelte +177 -0
- package/dist/client/TranslationHelperForm.svelte +111 -61
- package/dist/client/VibeTooltip.svelte +18 -14
- package/dist/client/dragItem.ts +65 -39
- package/dist/client/toggleQA.shared.ts +23 -15
- package/dist/client/translationDrafts.ts +59 -0
- package/dist/plugin.js +102 -10
- package/dist/server/types.ts +30 -8
- package/dist/server.d.ts +30 -5
- package/dist/server.js +519 -142
- package/dist/server.js.map +3 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Angy
|
|
2
2
|
|
|
3
|
-
Dev-only SvelteKit translation helper for in-app PO
|
|
3
|
+
Dev-only SvelteKit translation helper for in-app PO workflows.
|
|
4
|
+
|
|
5
|
+
<video src="./docs/images/Backdrop_And_Caching.webm" controls muted playsinline width="100%"></video>
|
|
4
6
|
|
|
5
7
|
## Install
|
|
6
8
|
|
|
@@ -8,69 +10,36 @@ Dev-only SvelteKit translation helper for in-app PO workflow.
|
|
|
8
10
|
npm install @walkinissue/angy
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
## What it
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
Load `angy.config.ts` in dev and server contexts
|
|
32
|
-
- OpenAI API
|
|
33
|
-
Optional translation suggestions
|
|
34
|
-
|
|
35
|
-
## What problem it solves
|
|
36
|
-
|
|
37
|
-
- Large apps are painful to internationalize late
|
|
38
|
-
- Many strings have weak or missing context
|
|
39
|
-
- Repeated copy appears in many components
|
|
40
|
-
- PO workflows are slow when you must search manually
|
|
41
|
-
- Existing i18n libraries solve extraction/runtime, not translator workflow
|
|
42
|
-
- Teams need a way to select text in the app, inspect context, and commit safely
|
|
43
|
-
|
|
44
|
-
## Why it exists
|
|
45
|
-
|
|
46
|
-
- Plain catalog editing was too slow
|
|
47
|
-
- Context from extraction alone was not enough
|
|
48
|
-
- Similar strings caused ambiguity
|
|
49
|
-
- Repeated strings needed reference-aware lookup
|
|
50
|
-
- Suggestion workflows needed to stay inside the app
|
|
51
|
-
- A dev-only helper reduced friction enough to keep the migration moving
|
|
52
|
-
|
|
53
|
-
## Workflow
|
|
54
|
-
|
|
55
|
-
- Developer runs app in dev
|
|
56
|
-
- Developer mounts `<Angy />` in layout
|
|
57
|
-
- App exports `POST` from the package handler
|
|
58
|
-
- User selects text or uses the helper trigger in the UI
|
|
59
|
-
- Client asks server for PO context and alternatives
|
|
60
|
-
- Server matches best key, expands related entries, and returns alternatives
|
|
61
|
-
- User edits, stages, tabs through unresolved strings, and commits
|
|
62
|
-
- Suggestions can be requested for untranslated strings
|
|
63
|
-
- Commits are written to the working catalog
|
|
13
|
+
## What it does
|
|
14
|
+
|
|
15
|
+
- select copy directly in the app
|
|
16
|
+
- resolve the best PO key with nearby alternatives
|
|
17
|
+
- stage and commit translations without leaving the page
|
|
18
|
+
- request AI suggestions for untranslated strings
|
|
19
|
+
- rotate locales for visual QA
|
|
20
|
+
|
|
21
|
+
## Quick flow
|
|
22
|
+
|
|
23
|
+
1. Select text or `Alt`+click an interactive element.
|
|
24
|
+
2. Review the matched key and alternatives.
|
|
25
|
+
3. Edit or accept a suggestion.
|
|
26
|
+
4. Stage and commit.
|
|
27
|
+
5. Rotate locales and verify the page visually.
|
|
28
|
+
|
|
29
|
+
## Docs site
|
|
30
|
+
|
|
31
|
+
- [Showcase and docs](https://walkingissue.github.io/Angy/)
|
|
32
|
+
- [Release notes](./docs/changelog/0.2.19.md)
|
|
64
33
|
|
|
65
34
|
## Integration
|
|
66
35
|
|
|
67
|
-
Use the plugin for
|
|
36
|
+
Use the plugin for dev glue, mount the component, and expose the server handler.
|
|
68
37
|
|
|
69
38
|
```ts
|
|
70
39
|
// vite.config.ts
|
|
71
40
|
import { defineConfig } from "vite";
|
|
72
41
|
import { sveltekit } from "@sveltejs/kit/vite";
|
|
73
|
-
import { angy } from "@
|
|
42
|
+
import { angy } from "@walkinissue/angy/plugin";
|
|
74
43
|
|
|
75
44
|
export default defineConfig({
|
|
76
45
|
plugins: [angy(), sveltekit()]
|
|
@@ -79,7 +48,7 @@ export default defineConfig({
|
|
|
79
48
|
|
|
80
49
|
```ts
|
|
81
50
|
// angy.config.ts
|
|
82
|
-
import { defineAngyConfig } from "@
|
|
51
|
+
import { defineAngyConfig } from "@walkinissue/angy/server";
|
|
83
52
|
|
|
84
53
|
export default defineAngyConfig({
|
|
85
54
|
basePoPath: "./src/locales/en.po",
|
|
@@ -88,7 +57,7 @@ export default defineAngyConfig({
|
|
|
88
57
|
targetLocale: "en",
|
|
89
58
|
routePath: "/api/translations",
|
|
90
59
|
apiKey: "",
|
|
91
|
-
|
|
60
|
+
suggestionModel: { model: "gpt-4.1-mini" }
|
|
92
61
|
});
|
|
93
62
|
```
|
|
94
63
|
|
|
@@ -96,151 +65,65 @@ export default defineAngyConfig({
|
|
|
96
65
|
<!-- src/routes/+layout.svelte -->
|
|
97
66
|
<script lang="ts">
|
|
98
67
|
import { dev } from "$app/environment";
|
|
99
|
-
import { Angy } from "@
|
|
68
|
+
import { Angy } from "@walkinissue/angy";
|
|
69
|
+
|
|
70
|
+
let { children } = $props();
|
|
100
71
|
</script>
|
|
101
72
|
|
|
102
73
|
{#if dev}
|
|
103
74
|
<Angy />
|
|
104
75
|
{/if}
|
|
105
76
|
|
|
106
|
-
|
|
77
|
+
{@render children?.()}
|
|
107
78
|
```
|
|
108
79
|
|
|
109
80
|
```ts
|
|
110
81
|
// src/routes/api/translations/+server.ts
|
|
111
|
-
export { handler as POST } from "@
|
|
82
|
+
export { handler as POST } from "@walkinissue/angy/server";
|
|
112
83
|
```
|
|
113
84
|
|
|
114
85
|
## Catalog model
|
|
115
86
|
|
|
116
|
-
- `en.po` is
|
|
117
|
-
- `en-working.po` is
|
|
118
|
-
-
|
|
119
|
-
-
|
|
120
|
-
-
|
|
121
|
-
- Commit validates against base, then writes to working
|
|
122
|
-
|
|
123
|
-
## Discovery algorithm
|
|
124
|
-
|
|
125
|
-
- User sends selected text and current route path
|
|
126
|
-
- Server creates lookup variants from the selected text
|
|
127
|
-
- Fuzzy search runs against the effective working view of the catalog
|
|
128
|
-
- Best match must clear a score threshold
|
|
129
|
-
- Top 4 similar direct matches are kept
|
|
130
|
-
- Server infers a page reference like `src/routes/.../+page.svelte`
|
|
131
|
-
- It then pulls entries that share PO references with the best match
|
|
132
|
-
- It then pulls entries whose references look similar to the current route
|
|
133
|
-
- If space remains, it fills with similar unresolved strings
|
|
134
|
-
- It also keeps a smaller translated slice for cohesion
|
|
135
|
-
|
|
136
|
-
## Why the lookup works like this
|
|
137
|
-
|
|
138
|
-
- Direct fuzzy match alone is not enough
|
|
139
|
-
- Repeated UI copy often exists in several components
|
|
140
|
-
- Shared PO references are strong local context
|
|
141
|
-
- Route similarity helps reconstruct page-level context
|
|
142
|
-
- A translated slice helps keep wording consistent
|
|
143
|
-
- An untranslated-heavy pool focuses effort where work remains
|
|
144
|
-
|
|
145
|
-
## Retrieval targets
|
|
146
|
-
|
|
147
|
-
- Up to 300 alternatives
|
|
148
|
-
- Roughly 80% untranslated
|
|
149
|
-
- Roughly 20% already translated
|
|
150
|
-
- Enough translated context for tone and syntax
|
|
151
|
-
- Enough untranslated context for efficient batch work
|
|
152
|
-
|
|
153
|
-
## Suggestions
|
|
154
|
-
|
|
155
|
-
- Suggestions are dev-only
|
|
156
|
-
- Server-side request to OpenAI
|
|
157
|
-
- Prompt aims to preserve placeholders, markup, casing, and product terminology
|
|
158
|
-
- Existing translations are used as style anchors
|
|
159
|
-
- Suggestions are cached client-side to avoid repeat requests
|
|
160
|
-
- Built-in suggestions are disabled when `apiKey` is empty
|
|
161
|
-
- Consumers can replace the suggestion pipeline with `suggestionProvider`
|
|
87
|
+
- `en.po` is base
|
|
88
|
+
- `en-working.po` is runtime working state
|
|
89
|
+
- `en-working.angy-draft.po` is the draft write target
|
|
90
|
+
- commits write to draft first
|
|
91
|
+
- entering `*-working` preview promotes draft into runtime working
|
|
162
92
|
|
|
163
93
|
## Config
|
|
164
94
|
|
|
165
|
-
| Key | Required |
|
|
166
|
-
| --- | --- | --- |
|
|
167
|
-
| `basePoPath` | Yes |
|
|
168
|
-
| `workingPoPath` | Yes |
|
|
169
|
-
| `sourceLocale` | Yes |
|
|
170
|
-
| `targetLocale` | Yes |
|
|
171
|
-
| `routePath` | No | `/api/translations` |
|
|
172
|
-
| `apiKey` |
|
|
173
|
-
| `systemMessage` | No |
|
|
174
|
-
| `suggestionModel` | No | `gpt-4.1-mini` |
|
|
175
|
-
| `watchIgnore` | No |
|
|
176
|
-
| `suggestionProvider` | No |
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
-
|
|
183
|
-
-
|
|
184
|
-
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
-
|
|
194
|
-
-
|
|
195
|
-
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
Return:
|
|
201
|
-
|
|
202
|
-
- `Array<{ msgid: string; msgctxt: string | null; suggestion: string }>`
|
|
203
|
-
|
|
204
|
-
Example:
|
|
205
|
-
|
|
206
|
-
```ts
|
|
207
|
-
import { defineAngyConfig, type SuggestionProvider } from "@walkingissue/angy/server";
|
|
208
|
-
|
|
209
|
-
const suggestionProvider: SuggestionProvider = async ({ items }) => {
|
|
210
|
-
return items.map((item) => ({
|
|
211
|
-
msgid: item.msgid,
|
|
212
|
-
msgctxt: item.msgctxt,
|
|
213
|
-
suggestion: `TODO: ${item.msgid}`
|
|
214
|
-
}));
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
export default defineAngyConfig({
|
|
218
|
-
basePoPath: "./src/locales/en.po",
|
|
219
|
-
workingPoPath: "./src/locales/en-working.po",
|
|
220
|
-
sourceLocale: "sv",
|
|
221
|
-
targetLocale: "en",
|
|
222
|
-
routePath: "/api/translations",
|
|
223
|
-
apiKey: "",
|
|
224
|
-
suggestionProvider
|
|
225
|
-
});
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
## Exports
|
|
229
|
-
|
|
230
|
-
- `Angy` from `@walkingissue/angy`
|
|
231
|
-
- `handler` and `defineAngyConfig` from `@walkingissue/angy/server`
|
|
232
|
-
- `angy` from `@walkingissue/angy/plugin`
|
|
233
|
-
|
|
234
|
-
## Notes
|
|
235
|
-
|
|
236
|
-
- The default `handler` returns a `404` outside dev.
|
|
237
|
-
- The package still has fallback internal paths, but consumers should define their own explicit catalog paths.
|
|
238
|
-
- Override paths, locales, `routePath`, `apiKey`, `systemMessage`, `suggestionModel`, `watchIgnore`, and `suggestionProvider` through `angy.config.ts`.
|
|
239
|
-
- The default export surface is intentionally small: plugin, component, config helper, and server handler.
|
|
240
|
-
|
|
241
|
-
## Future work
|
|
242
|
-
|
|
243
|
-
- Handle server paths for single config and single app
|
|
244
|
-
- Support multiple catalogs
|
|
245
|
-
- Support multiple translations from a single source locale
|
|
246
|
-
- This seems trivially implemented with the current setup
|
|
95
|
+
| Key | Required | Notes |
|
|
96
|
+
| --- | --- | --- |
|
|
97
|
+
| `basePoPath` | Yes | Base catalog path |
|
|
98
|
+
| `workingPoPath` | Yes | Working catalog path |
|
|
99
|
+
| `sourceLocale` | Yes | Source language for suggestions |
|
|
100
|
+
| `targetLocale` | Yes | Target language for suggestions |
|
|
101
|
+
| `routePath` | No | Defaults to `/api/translations` |
|
|
102
|
+
| `apiKey` | No | Empty string disables built-in suggestions |
|
|
103
|
+
| `systemMessage` | No | Custom suggestion prompt |
|
|
104
|
+
| `suggestionModel` | No | Object config, defaults to `{ model: "gpt-4.1-mini" }` |
|
|
105
|
+
| `watchIgnore` | No | Extra Vite watch ignore patterns |
|
|
106
|
+
| `suggestionProvider` | No | Custom suggestion pipeline |
|
|
107
|
+
|
|
108
|
+
Reasoning is validated per model. Non-reasoning models like `gpt-4.1-mini` do not accept it.
|
|
109
|
+
|
|
110
|
+
## Frequent issues
|
|
111
|
+
|
|
112
|
+
- Locale changes in Angy, but the page does not rerender
|
|
113
|
+
- Wuchale usually is not fully bootstrapped in the host app.
|
|
114
|
+
- `*-working` is visible, but commit is disabled
|
|
115
|
+
- Working locale is preview-only by design.
|
|
116
|
+
- Rotation shows a warning modal
|
|
117
|
+
- That is a preview of what rotation will promote into base.
|
|
118
|
+
- Angy refuses to operate with a catalog integrity error
|
|
119
|
+
- Regenerate or replace the working catalog.
|
|
120
|
+
|
|
121
|
+
## Docs
|
|
122
|
+
|
|
123
|
+
- [Release notes](./docs/changelog/0.2.19.md)
|
|
124
|
+
- [Roadmap](./docs/roadmap.md)
|
|
125
|
+
- [Wuchale runtime wiring](./docs/wuchale-runtime.md)
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
MIT
|