Skip to content

OpenConceptLab/ocl_issues#3031 | FHIR: send OCL locales as BCP-47 language tags - #994

Open
paynejd wants to merge 1 commit into
masterfrom
fhir-bcp47-3031
Open

paynejd wants to merge 1 commit into
masterfrom
fhir-bcp47-3031

Conversation

@paynejd

@paynejd paynejd commented Nov 13, 2026

Copy link
Copy Markdown
Member

closes OpenConceptLab/ocl_issues#3031 (part of OpenConceptLab/ocl_issues#3029)

OCL stores locales such as pt_BR, following CIEL, and FHIR output copied them unchanged. FHIR needs BCP-47 tags. FHIR output now sends pt-BR, and displayLanguage=pt-BR finds a name stored as pt_BR. Stored data and OCL's REST output don't change.

Independent of oclapi2#993 (OpenConceptLab/ocl_issues#3030): both change core/code_systems/serializers.py and core/fhir/search.py, but the two branches merge cleanly in either order.

Changes

  • core/common/fhir_helpers.py: bcp47(locale) swaps _ for -. language_key(locale) compares languages in either spelling, ignoring case.
  • core/common/serializers.py: LanguageTagField, a CharField that shows a locale as a BCP-47 tag and writes what it's given. It's used for the CodeSystem language, the CodeSystem designation language and the ConceptMap language.
  • core/fhir/ops/concepts.py: designations() ($lookup, $expand) sends BCP-47 tags. display_of() ($lookup, $expand, $validate-code) matches displayLanguage with language_key.
  • core/fhir/search.py: the CodeSystem language search parameter matches a default locale in either spelling, ignoring case, so searching for what the read shows finds it.

Tests

  • New tests for $lookup and $expand (pt-BR, pt_BR and PT-br all pick the pt_BR name; designations say pt-BR), the CodeSystem read (language and designations are pt-BR, while the REST source and concept still say pt_BR), the ConceptMap language, and the language search parameter.
  • core.fhir, core.code_systems and core.concept_maps pass locally (804 tests). Full-suite result: see the comment below. pylint -j0 core/ 10.00.

Decisions to confirm

  1. Only the separator changes. Case is kept as stored. ISO 639-2 codes (eng, por) and free-text locales go out as stored. Some production sources have those as their default locale. Normalizing them belongs to OCL-wide locale handling, Locale string representation compliance ocl_issues#2795.
  2. The ConceptMap language changes too. The ticket names CodeSystem, but it's the same FHIR element. OCL's ValueSet output has no language.
  3. The CodeSystem language search parameter takes either spelling. Otherwise, searching for the language a read shows would find nothing.
  4. FHIR writes store locales as sent. A pt-BR designation written through FHIR is stored as pt-BR, not changed to pt_BR. Choosing one stored spelling belongs to Locale string representation compliance ocl_issues#2795.
  5. A tag matches only the same tag. displayLanguage=pt doesn't pick a pt_BR name, as before.
  6. Accept-Language: no FHIR operation reads it today, so nothing changes there.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AaZ4qTHAarCyLb2cuys8Yd

…guage tags

- FHIR output shows a locale as a BCP-47 tag, pt_BR as pt-BR: designation language in CodeSystem,
  $lookup and $expand, and the CodeSystem and ConceptMap language (LanguageTagField, bcp47). Only
  the separator changes.
- displayLanguage ($lookup, $expand, $validate-code) and the CodeSystem language search match a
  stored locale in either spelling, ignoring case (language_key).
- Stored data, FHIR writes and OCL's REST output are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AaZ4qTHAarCyLb2cuys8Yd
@paynejd

paynejd commented Nov 13, 2026

Copy link
Copy Markdown
Member Author

Full suite locally at 795a169, run as CI runs it (PYTHONHASHSEED=2):

  • TEST_ES=off --exclude-tag es --parallel=4: 3,219 tests; one failure, core.capacity CapacityGateTest.test_the_renewer_thread_renews_until_stopped (renew.call_count not above 1). That test counts renewals within a time window, and the machine was also running a review at the time. Alone, core.capacity passes (80 tests). The change doesn't touch it.
  • --tag es --parallel=1: 629 tests, OK.

@paynejd

paynejd commented Nov 13, 2026

Copy link
Copy Markdown
Member Author

Codex review, pass 1 (codex-cli 0.169.0, commit 795a169)

Verdict: clean. No findings.

findings.json
{
  "reviewer": "codex-cli 0.169.0",
  "perspective": "defects",
  "mode": "full",
  "commit": "795a169c",
  "verdict": "clean",
  "prior": [],
  "findings": []
}

@paynejd

paynejd commented Nov 13, 2026

Copy link
Copy Markdown
Member Author

Simplification review (fresh Claude subagent, commit 795a169)

Verdict: findings (1 shrink).

  • S1 (shrink) core/common/fhir_helpers.py:14: language_key repeats bcp47's falsy guard. bcp47 already returns a falsy locale unchanged, so the second if locale else locale only exists to avoid calling .lower() on None or ''. The same job fits in one expression.

Responses

  • S1: declined. It wouldn't save a line, and it would make a missing locale '' instead of None. The explicit guard is clearer.

No commits after 795a169, so no further Codex check is needed.

findings.json
{
  "reviewer": "claude subagent",
  "perspective": "simplify",
  "mode": "full",
  "commit": "795a169c",
  "verdict": "findings",
  "prior": [],
  "findings": [
    {
      "id": "S1",
      "severity": null,
      "tag": "shrink",
      "file": "core/common/fhir_helpers.py",
      "line": 14,
      "claim": "language_key repeats bcp47's falsy guard. bcp47 already returns a falsy locale unchanged, so the second `if locale else locale` only exists to avoid calling .lower() on None or ''. The same job fits in one expression.",
      "scenario": null,
      "action": "def language_key(locale):\n    return (bcp47(locale) or '').lower()  # only if callers can accept '' instead of None for a missing locale; otherwise keep as is",
      "lines_delta": -1,
      "confidence": "low"
    }
  ]
}

@paynejd

paynejd commented Nov 13, 2026

Copy link
Copy Markdown
Member Author

@snyaggarwal this is ready for review. Jon asks you to merge it if you approve; he knows you're working this weekend.

  • Merge order: none needed. It's independent of oclapi2#993 (Sources: store and publish which code system a supplement supplements ocl_issues#3030), and the two branches merge cleanly in either order. A trial merge of both passed core.fhir, core.code_systems, core.concept_maps and the source tests locally (962 tests).
  • No migration in this PR. FHIR output changes only; stored data and REST output don't change.
  • Review: one Codex pass, clean. The simplification review's one suggestion was declined (reason above). CI is green.
  • Decisions to confirm are in the PR description.

This branch has not been deployed

No deployments
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.

FHIR: send OCL locales as BCP-47 language tags

2 participants