Phase 19: the copy stops being hardcoded Mandarin
Every `中文 · English` string moves out of ~29 components into web/src/i18n: one Pack type, a verbatim zh pack, and two ways to read it — usePack() for components, pack() for the modules that build a line when something happens rather than when something renders. Anything with a value in it is a function on the pack rather than a template at the call site, English pluralisation included: word order isn't universal, and a pack author has to be able to move the number. The roster constants (tones, rewrite styles, export formats, companions) keep only value + emoji, so a label can't drift from its key. On the server, internal/llm/lang.go replaces "Simplified Chinese" in the three prompts that actually name her language. pt-PT is spelled "European Portuguese (pt-PT, never Brazilian Portuguese)" in the prompt itself, and each Lang carries her word for "why" so the tutor prompt still recognises the question when she asks it her way. pair_lang reaches the model through the row-scoped query each handler already ran — the one that proves she owns the document — rather than a second lookup that could disagree with it. Also records Phase 18's deploy: migration 0011 rehearsed against a copy of the live VPS database, then applied for real.
This commit is contained in:
+30
-27
@@ -97,8 +97,8 @@ func VoiceMessages(contentText string) []Message {
|
||||
// just non-native ("do a decision" → "make a decision", "strong rain" → "heavy
|
||||
// rain"), and explicitly DEFERS real grammar/spelling errors to the grammar
|
||||
// checkpoint so the two families don't overlap. Every explanation is framed as a
|
||||
// warm "natives usually say…" note with a short Mandarin gloss — never
|
||||
// "error/wrong" — because these are stylistic, not mistakes. It is a distinct
|
||||
// warm "natives usually say…" note with a short gloss in the writer's own
|
||||
// language — never "error/wrong" — because these are stylistic, not mistakes. It is a distinct
|
||||
// pass from the grammar checkpoint (do not bundle them). `replacement` carries
|
||||
// the natural pairing the writer can accept in one tap.
|
||||
const collocationSystemPrompt = `You are a warm, encouraging writing assistant helping someone who speaks English as a second language. ` +
|
||||
@@ -113,7 +113,7 @@ Identify up to 5 such non-native word pairings. For each, give the natural pairi
|
||||
`Be gentle and specific. Do NOT flag grammar errors, spelling mistakes, or unclear sentences — those are handled ` +
|
||||
`elsewhere. Only flag word pairings that are correct but sound non-native.%s
|
||||
|
||||
Phrase every explanation warmly as "Natives usually say…" and include a brief Simplified Chinese gloss in parentheses. ` +
|
||||
Phrase every explanation warmly as "Natives usually say…" and include a brief %s gloss in parentheses. ` +
|
||||
`Never use the words "error", "wrong", or "mistake" — these are friendly polish, not corrections.
|
||||
|
||||
Respond ONLY with valid JSON. No preamble, no markdown fences. Format:
|
||||
@@ -132,10 +132,11 @@ If every pairing already sounds natural, return: {"suggestions": []}`
|
||||
|
||||
// CollocationMessages builds the message array for a collocation pass over the
|
||||
// WHOLE document (no truncation), gently steered toward the document's tone so a
|
||||
// hint can prefer a register-appropriate pairing.
|
||||
func CollocationMessages(contentText, tone string) []Message {
|
||||
// hint can prefer a register-appropriate pairing. The parenthetical gloss is
|
||||
// written in the writer's own language.
|
||||
func CollocationMessages(contentText, tone string, lang Lang) []Message {
|
||||
return []Message{
|
||||
{Role: "system", Content: fmt.Sprintf(collocationSystemPrompt, toneGuidance(tone))},
|
||||
{Role: "system", Content: fmt.Sprintf(collocationSystemPrompt, toneGuidance(tone), lang.Name)},
|
||||
{Role: "user", Content: contentText},
|
||||
}
|
||||
}
|
||||
@@ -147,26 +148,27 @@ const askPetalSystemTemplate = `You are Petal, a warm and patient English writin
|
||||
`as a second language. You are currently discussing a specific writing suggestion.
|
||||
|
||||
Suggestion context:
|
||||
- Original text: "%s"
|
||||
- Suggested replacement: "%s"
|
||||
- Issue type: %s
|
||||
- Initial explanation: "%s"
|
||||
- Surrounding paragraph: "%s"
|
||||
- Original text: "%[1]s"
|
||||
- Suggested replacement: "%[2]s"
|
||||
- Issue type: %[3]s
|
||||
- Initial explanation: "%[4]s"
|
||||
- Surrounding paragraph: "%[5]s"
|
||||
|
||||
The user wants to understand this suggestion better. Detect the language of the user's message ` +
|
||||
`and respond in that same language. If they write in Mandarin Chinese, respond entirely in ` +
|
||||
`Mandarin. If they write in English, respond in English. Never mix languages in a single response.
|
||||
`and respond in that same language. If they write in %[6]s, respond entirely in ` +
|
||||
`%[6]s. If they write in English, respond in English. Never mix languages in a single response.
|
||||
|
||||
Explain clearly and kindly. Use simple language appropriate to the user's message. Give examples ` +
|
||||
`when helpful. If they ask "why" (or "为什么"), explain the grammar rule or idiom behind it. ` +
|
||||
`when helpful. If they ask "why" (or "%[7]s"), explain the grammar rule or idiom behind it. ` +
|
||||
`If they suggest an alternative phrasing, evaluate it honestly.
|
||||
|
||||
Keep responses concise (2-4 sentences). This is a chat, not an essay. Be encouraging — ` +
|
||||
`learning a language is hard and they're doing great.`
|
||||
|
||||
// AskPetalSystemPrompt fills the tutor prompt with one suggestion's context.
|
||||
func AskPetalSystemPrompt(original, replacement, suggestionType, explanation, paragraph string) string {
|
||||
return fmt.Sprintf(askPetalSystemTemplate, original, replacement, suggestionType, explanation, paragraph)
|
||||
// AskPetalSystemPrompt fills the tutor prompt with one suggestion's context and
|
||||
// the writer's pair language, which is the one she may ask her question in.
|
||||
func AskPetalSystemPrompt(original, replacement, suggestionType, explanation, paragraph string, lang Lang) string {
|
||||
return fmt.Sprintf(askPetalSystemTemplate, original, replacement, suggestionType, explanation, paragraph, lang.Name, lang.Why)
|
||||
}
|
||||
|
||||
// rewriteSystemTemplate drives the "say it more naturally" / tone-rewrite tool.
|
||||
@@ -215,22 +217,23 @@ func RewriteMessages(text, style string) []Message {
|
||||
}
|
||||
|
||||
// translateSystemPrompt drives the explanation translator: it renders a
|
||||
// suggestion's English explanation into Simplified Chinese so an ESL reader sees
|
||||
// the "why" in her first language. Strict about returning ONLY the translation
|
||||
// (no quotes, no pinyin, no English echo) so it can drop straight into the chat
|
||||
// bubble. Kept warm and plain — these are short, friendly one-liners.
|
||||
// suggestion's English explanation into the writer's own language so an ESL
|
||||
// reader sees the "why" in her first language. Strict about returning ONLY the
|
||||
// translation (no quotes, no romanisation, no English echo) so it can drop
|
||||
// straight into the chat bubble. Kept warm and plain — these are short, friendly
|
||||
// one-liners.
|
||||
const translateSystemPrompt = `You are Petal, a warm writing assistant. Translate the English text the user ` +
|
||||
`sends into natural, friendly Simplified Chinese (Mandarin). It is a short explanation of a writing ` +
|
||||
`suggestion, written for a native Chinese speaker learning English.
|
||||
`sends into natural, friendly %[1]s. It is a short explanation of a writing ` +
|
||||
`suggestion, written for a native %[1]s speaker learning English.
|
||||
|
||||
Respond with ONLY the Simplified Chinese translation. No quotation marks, no pinyin, no English, no preamble — ` +
|
||||
Respond with ONLY the %[1]s translation. No quotation marks, no romanisation, no English, no preamble — ` +
|
||||
`just the translated sentence.`
|
||||
|
||||
// TranslateMessages builds the message array for translating one short English
|
||||
// explanation into Simplified Chinese.
|
||||
func TranslateMessages(text string) []Message {
|
||||
// explanation into the writer's own language.
|
||||
func TranslateMessages(text string, lang Lang) []Message {
|
||||
return []Message{
|
||||
{Role: "system", Content: translateSystemPrompt},
|
||||
{Role: "system", Content: fmt.Sprintf(translateSystemPrompt, lang.Name)},
|
||||
{Role: "user", Content: text},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user