Legal Analysis: full language follow-through (UI + LLM)
The tool now respects the chosen UI language end-to-end — even if the source document is Norwegian, a user on EN/UK/PL gets the analysis in their language. Norwegian statute references (barnevernsloven § 4-25, EMK Art. 8) and case names (Strand Lobben mot Norge 37283/13) are kept verbatim because they are proper nouns. LLM (LegalAnalysisAgent.php): - extractIssues: prompt asks for question + brief_context in user's language; statute refs preserved - answerIssue: Norwegian core system prompt (keeps fine-tune precision) + language-coercion line for non-NO; localised context/source labels - synthesise: overall_assessment, next_steps, disclaimer in user's language; explicit per-language disclaimer text - runFullAnalysis empty-case fallback also localised - what_to_check translated per language UI: - 40 new la_* translation keys in i18n.php × 4 languages (NO/EN/UK/PL) - legal-analysis.php: 4-way lang switcher, dbnToolsT() for every label, emits window.DBN_LA_I18N for runtime JS strings - legal-analysis.js: t() helper reads from window.DBN_LA_I18N - layout_footer.php: emits window.DBN_CURRENT_LANG + window.DBN_ADDON_I18N so the legal-analysis add-on button works in the page's language no matter which tool it's invoked from - tools.js add-on: reads from DBN_ADDON_I18N, passes DBN_CURRENT_LANG to /api/legal-analysis.php so server responds in same language Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -48,15 +48,18 @@ process law). Each issue must be answerable as a SINGLE focused legal question
|
||||
(≤ 25 words), not a multi-part essay.
|
||||
|
||||
Document type hint: {$docType}
|
||||
Document language: {$locale}
|
||||
User's response language: {$locale}
|
||||
|
||||
Return JSON only:
|
||||
Return JSON only — every human-readable string ("question", "brief_context") MUST be
|
||||
written in {$locale}. Keep Norwegian statute references (barnevernsloven § 4-25,
|
||||
forvaltningsloven § 17, EMK Art. 8) and Norwegian/EMD case names (Strand Lobben mot
|
||||
Norge 37283/13) in their original form even when the surrounding text is in {$locale}.
|
||||
{
|
||||
"issues": [
|
||||
{
|
||||
"id": 1,
|
||||
"question": "<short Norwegian legal question, single issue>",
|
||||
"brief_context": "<≤2 sentences from the document that triggered this question>",
|
||||
"question": "<short legal question in {$locale}, single issue, statute refs kept in original Norwegian/Latin>",
|
||||
"brief_context": "<≤2 sentences in {$locale} summarising what in the document triggered this question — paraphrase, do not quote in Norwegian unless quoting a statute>",
|
||||
"doc_type": "<barnevernet|adopsjon|emergency|samvær|other>",
|
||||
"severity_hint": "<high|medium|low>"
|
||||
}
|
||||
@@ -69,6 +72,7 @@ Rules:
|
||||
named Høyesterett/EMD cases — NOT general advice.
|
||||
- If the document has fewer than 5 real legal issues, return fewer entries.
|
||||
- If NO real legal issue exists, return {"issues": []}.
|
||||
- The source document may be in Norwegian — that is fine; still write your output in {$locale}.
|
||||
|
||||
DOCUMENT:
|
||||
---
|
||||
@@ -119,19 +123,48 @@ PROMPT;
|
||||
*/
|
||||
public function answerIssue(array $issue, string $corpusContext, string $language): array
|
||||
{
|
||||
$locale = dbnToolsLanguageName($language);
|
||||
|
||||
// The fine-tune was trained primarily in Norwegian; the Norwegian system
|
||||
// prompt keeps its precision on barnevernsloven / EMD. We then add a
|
||||
// language-coercion line so the prose comes back in the user's chosen
|
||||
// language. Statute and case names stay in their original Norwegian form.
|
||||
$sysMsg = 'Du er en ekspert på norsk barnevernsloven og EMD-praksis. '
|
||||
. 'Svar alltid på norsk med korrekt juridisk terminologi. '
|
||||
. 'Bruk korrekt juridisk terminologi. '
|
||||
. 'Bruk terskler fra barnevernsloven 2021: § 4-25 krever «klar nødvendighet». '
|
||||
. 'Strand Lobben mot Norge (37283/13) setter krav om rehabiliteringsplan før adopsjon. '
|
||||
. 'Aldri oppfinn paragrafnumre, saksnumre eller dommernavn. '
|
||||
. 'Avslutt med en «Kilder:»-seksjon som lister lovparagrafer og dommer du har sitert.';
|
||||
. 'Avslutt med en «Kilder:»-seksjon som lister lovparagrafer og dommer du har sitert. ';
|
||||
|
||||
if ($language === 'no') {
|
||||
$sysMsg .= 'Svar på norsk.';
|
||||
} else {
|
||||
$sysMsg .= 'IMPORTANT: Write your answer in ' . $locale
|
||||
. '. Keep all Norwegian statute references (e.g. "barnevernsloven § 4-25", '
|
||||
. '"forvaltningsloven § 17", "EMK Art. 8") and case names (e.g. "Strand Lobben '
|
||||
. 'mot Norge 37283/13") in their original Norwegian/Latin form. The "Kilder:" '
|
||||
. 'section heading stays as "Kilder:" but its contents (the cited authorities) '
|
||||
. 'are listed in their original Norwegian form.';
|
||||
}
|
||||
|
||||
$userMsg = $issue['question'];
|
||||
if ($issue['brief_context'] !== '') {
|
||||
$userMsg .= "\n\nKontekst fra saken: " . $issue['brief_context'];
|
||||
$ctxLabel = match ($language) {
|
||||
'no' => 'Kontekst fra saken',
|
||||
'pl' => 'Kontekst sprawy',
|
||||
'uk' => 'Контекст справи',
|
||||
default => 'Case context',
|
||||
};
|
||||
$userMsg .= "\n\n" . $ctxLabel . ': ' . $issue['brief_context'];
|
||||
}
|
||||
if ($corpusContext !== '') {
|
||||
$userMsg .= "\n\nRelevante kilder fra Do Better Norge-korpuset:\n" . $corpusContext;
|
||||
$srcLabel = match ($language) {
|
||||
'no' => 'Relevante kilder fra Do Better Norge-korpuset',
|
||||
'pl' => 'Istotne źródła z korpusu Do Better Norge',
|
||||
'uk' => 'Релевантні джерела з корпусу Do Better Norge',
|
||||
default => 'Relevant sources from the Do Better Norge corpus',
|
||||
};
|
||||
$userMsg .= "\n\n" . $srcLabel . ":\n" . $corpusContext;
|
||||
}
|
||||
|
||||
$answer = '';
|
||||
@@ -164,6 +197,13 @@ PROMPT;
|
||||
$severity = $clean !== '' ? dbnToolsInferCheckSeverity($clean) : $issue['severity_hint'];
|
||||
$legalBasis = dbnToolsExtractCheckLegalBasis($clean);
|
||||
|
||||
$whatToCheck = match ($language) {
|
||||
'no' => 'Verifiser med norsk familieretsadvokat før handling.',
|
||||
'pl' => 'Zweryfikuj z norweskim adwokatem ds. rodzinnych przed podjęciem działań.',
|
||||
'uk' => 'Перевірте з норвезьким адвокатом із сімейного права перед діями.',
|
||||
default => 'Verify with a qualified Norwegian family-law lawyer before acting.',
|
||||
};
|
||||
|
||||
return [
|
||||
'id' => $issue['id'],
|
||||
'question' => $issue['question'],
|
||||
@@ -171,8 +211,8 @@ PROMPT;
|
||||
'answer' => $clean,
|
||||
'severity' => $severity,
|
||||
'legal_basis' => $legalBasis,
|
||||
'citations_from_corpus' => [], // populated by orchestrator if it kept the chunks
|
||||
'what_to_check' => 'Verifiser med norsk familieretsadvokat før handling.',
|
||||
'citations_from_corpus' => [],
|
||||
'what_to_check' => $whatToCheck,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -194,18 +234,29 @@ PROMPT;
|
||||
}
|
||||
$issuesBlock = implode("\n", $bullets);
|
||||
|
||||
$disclaimerText = match ($language) {
|
||||
'no' => 'Dette er automatisert juridisk analyse, ikke juridisk rådgivning. Verifiser med en kvalifisert norsk advokat før du handler.',
|
||||
'pl' => 'To jest zautomatyzowana analiza prawna, a nie porada prawna. Zweryfikuj z wykwalifikowanym norweskim prawnikiem przed podjęciem działań.',
|
||||
'uk' => 'Це автоматизований юридичний аналіз, а не юридична консультація. Перевірте з кваліфікованим норвезьким юристом перед діями.',
|
||||
default => 'This is automated legal analysis, not legal advice. Verify with a qualified Norwegian lawyer before acting.',
|
||||
};
|
||||
|
||||
$prompt = <<<PROMPT
|
||||
Below are 1-5 legal questions raised about a {$docType} document, each with an answer
|
||||
from a Norwegian-law specialist model. Write a concise overall assessment in {$locale}.
|
||||
from a Norwegian-law specialist model. Write a concise overall assessment.
|
||||
|
||||
Output language: {$locale}. Every human-readable string ("overall_assessment",
|
||||
"next_steps[]", "disclaimer") MUST be written in {$locale}. Keep Norwegian statute
|
||||
references and case names in their original form.
|
||||
|
||||
ISSUES + ANSWERS:
|
||||
{$issuesBlock}
|
||||
|
||||
Return JSON only:
|
||||
{
|
||||
"overall_assessment": "<3-5 sentences summarising the legal picture across all issues>",
|
||||
"next_steps": ["<concrete action 1>", "<concrete action 2>", "<concrete action 3>"],
|
||||
"disclaimer": "This is automated legal analysis, not legal advice. Verify with a qualified Norwegian lawyer before acting."
|
||||
"overall_assessment": "<3-5 sentences in {$locale} summarising the legal picture across all issues>",
|
||||
"next_steps": ["<concrete action 1 in {$locale}>", "<concrete action 2>", "<concrete action 3>"],
|
||||
"disclaimer": "{$disclaimerText}"
|
||||
}
|
||||
PROMPT;
|
||||
|
||||
@@ -250,12 +301,24 @@ PROMPT;
|
||||
$issues = $this->extractIssues($text, $language, $docType);
|
||||
|
||||
if (empty($issues)) {
|
||||
$emptyAssessment = match ($language) {
|
||||
'no' => 'Ingen distinkte juridiske spørsmål identifisert i dette dokumentet.',
|
||||
'pl' => 'Nie zidentyfikowano odrębnych kwestii prawnych w tym dokumencie.',
|
||||
'uk' => 'У цьому документі не виявлено окремих юридичних питань.',
|
||||
default => 'No discrete legal issues identified in this document.',
|
||||
};
|
||||
$emptyDisclaimer = match ($language) {
|
||||
'no' => 'Automatisert analyse — ikke juridisk rådgivning.',
|
||||
'pl' => 'Analiza zautomatyzowana — nie stanowi porady prawnej.',
|
||||
'uk' => 'Автоматизований аналіз — не є юридичною консультацією.',
|
||||
default => 'Automated analysis — not legal advice.',
|
||||
};
|
||||
return [
|
||||
'ok' => true,
|
||||
'issues' => [],
|
||||
'overall_assessment' => 'No discrete legal issues identified in this document.',
|
||||
'overall_assessment' => $emptyAssessment,
|
||||
'next_steps' => [],
|
||||
'disclaimer' => 'Automated analysis — not legal advice.',
|
||||
'disclaimer' => $emptyDisclaimer,
|
||||
'model' => self::LEGAL_MODEL,
|
||||
'latency_ms' => (int)round(microtime(true) * 1000) - $startMs,
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user