Merge pull request #1232 from hapifhir/gg-202304-validator-translations

Gg 202304 validator translations
This commit is contained in:
Grahame Grieve 2023-04-26 06:38:50 +10:00 committed by GitHub
commit 10150841dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 503 additions and 124 deletions

View File

@ -45,6 +45,7 @@ import org.apache.commons.lang3.Validate;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.context.ContextUtilities;
import org.hl7.fhir.r5.extensions.ExtensionsUtils;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.DataType;
import org.hl7.fhir.r5.model.ElementDefinition;
@ -1443,7 +1444,7 @@ public class Element extends Base {
}
}
}
if (lang.equals(l)) {
if (LanguageUtils.langsMatch(lang, l)) {
return v;
}
}
@ -1451,4 +1452,58 @@ public class Element extends Base {
}
return null;
}
public String getBasePath() {
if (property.getStructure().hasExtension(ToolingExtensions.EXT_RESOURCE_IMPLEMENTS)) {
StructureDefinition sd = property.getContext().fetchResource(StructureDefinition.class, ExtensionsUtils.getExtensionString(property.getStructure(), ToolingExtensions.EXT_RESOURCE_IMPLEMENTS));
if (sd != null) {
ElementDefinition ed = sd.getSnapshot().getElementByPath(property.getDefinition().getPath().replace(property.getStructure().getType(), sd.getType()));
if (ed != null) {
return ed.getBase().getPath();
}
}
}
return property.getDefinition().getBase().getPath();
}
public void setTranslation(String lang, String translation) {
for (Element e : getChildren()) {
if (e.fhirType().equals("Extension")) {
String url = e.getNamedChildValue("url");
if (ToolingExtensions.EXT_TRANSLATION.equals(url)) {
String l = null;
Element v = null;
for (Element g : e.getChildren()) {
if (g.fhirType().equals("Extension")) {
String u = g.getNamedChildValue("url");
if ("lang".equals(u)) {
l = g.getNamedChildValue("value");
} else if ("value".equals(u)) {
v = g.getNamedChild("value");
}
}
}
if (LanguageUtils.langsMatch(lang, l)) {
if (v == null) {
Element ext = e.addElement("extension");
ext.addElement("url").setValue("value");
ext.addElement("valueString").setValue(translation);
} else {
v.setValue(translation);
}
}
}
}
}
Element t = addElement("extension");
t.addElement("url").setValue(ToolingExtensions.EXT_TRANSLATION);
Element ext = t.addElement("extension");
ext.addElement("url").setValue("lang");
ext.addElement("valueCode").setValue(lang);
ext = t.addElement("extension");
ext.addElement("url").setValue("value");
ext.addElement("valueString").setValue(translation);
}
}

View File

@ -1,9 +1,18 @@
package org.hl7.fhir.r5.elementmodel;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hl7.fhir.r5.context.ContextUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.LanguageProducerLanguageSession;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TextUnit;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TranslationUnit;
/**
* in here:
@ -21,6 +30,7 @@ import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TextUnit;
public class LanguageUtils {
IWorkerContext context;
private List<String> crlist;
public LanguageUtils(IWorkerContext context) {
@ -29,27 +39,150 @@ public class LanguageUtils {
}
public void generateTranslations(Element resource, LanguageProducerLanguageSession session) {
translate(resource, session);
translate(null, resource, session);
}
private void translate(Element element, LanguageProducerLanguageSession langSession) {
private void translate(Element parent, Element element, LanguageProducerLanguageSession langSession) {
if (element.isPrimitive() && isTranslatable(element)) {
String base = element.primitiveValue();
if (base != null) {
String translation = element.getTranslation(langSession.getTargetLang());
langSession.entry(new TextUnit(element.getPath(), base, translation));
String translation = getSpecialTranslation(parent, element, langSession.getTargetLang());
if (translation == null) {
translation = element.getTranslation(langSession.getTargetLang());
}
langSession.entry(new TextUnit(pathForElement(element), base, translation));
}
}
for (Element c: element.getChildren()) {
translate(c, langSession);
if (!c.getName().equals("designation")) {
translate(element, c, langSession);
}
}
}
private String getSpecialTranslation(Element parent, Element element, String targetLang) {
if (parent == null) {
return null;
}
if (Utilities.existsInList(pathForElement(parent), "CodeSystem.concept", "CodeSystem.concept.concept") && "CodeSystem.concept.display".equals(pathForElement(element))) {
return getDesignationTranslation(parent, targetLang);
}
if (Utilities.existsInList(pathForElement(parent), "ValueSet.compose.include.concept") && "ValueSet.compose.include.concept.display".equals(pathForElement(element))) {
return getDesignationTranslation(parent, targetLang);
}
if (Utilities.existsInList(pathForElement(parent), "ValueSet.expansion.contains", "ValueSet.expansion.contains.contains") && "ValueSet.expansion.contains.display".equals(pathForElement(element))) {
return getDesignationTranslation(parent, targetLang);
}
return null;
}
private String getDesignationTranslation(Element parent, String targetLang) {
for (Element e : parent.getChildren("designation")) {
String lang = e.getNamedChildValue("language");
if (langsMatch(targetLang, lang)) {
return e.getNamedChildValue("value");
}
}
return null;
}
private boolean isTranslatable(Element element) {
return element.getProperty().isTranslatable();
return element.getProperty().isTranslatable() && !Utilities.existsInList(pathForElement(element), "CanonicalResource.version");
}
public static boolean matches(String dstLang, String srcLang) {
private String pathForElement(Element element) {
// special case support for metadata elements prior to R5:
if (crlist == null) {
crlist = new ContextUtilities(context).getCanonicalResourceNames();
}
String bp = element.getBasePath();
if (crlist.contains(element.getProperty().getStructure().getType())) {
String fp = bp.replace(element.getProperty().getStructure().getType()+".", "CanonicalResource.");
if (Utilities.existsInList(fp,
"CanonicalResource.url", "CanonicalResource.identifier", "CanonicalResource.version", "CanonicalResource.name",
"CanonicalResource.title", "CanonicalResource.status", "CanonicalResource.experimental", "CanonicalResource.date",
"CanonicalResource.publisher", "CanonicalResource.contact", "CanonicalResource.description", "CanonicalResource.useContext",
"CanonicalResource.jurisdiction")) {
return fp;
}
}
return bp;
}
public int importFromTranslations(Element resource, Set<TranslationUnit> translations) {
return importFromTranslations(null, resource, translations);
}
private int importFromTranslations(Element parent, Element element, Set<TranslationUnit> translations) {
int t = 0;
if (element.isPrimitive() && isTranslatable(element)) {
String base = element.primitiveValue();
if (base != null) {
Set<TranslationUnit> tlist = findTranslations(pathForElement(element), base, translations);
for (TranslationUnit translation : tlist) {
t++;
if (!handleAsSpecial(parent, element, translation)) {
element.setTranslation(translation.getLanguage(), translation.getTgtText());
}
}
}
}
for (Element c: element.getChildren()) {
if (!c.getName().equals("designation")) {
t = t + importFromTranslations(element, c, translations);
}
}
return t;
}
private boolean handleAsSpecial(Element parent, Element element, TranslationUnit translation) {
if (parent == null) {
return false;
}
if (Utilities.existsInList(pathForElement(parent), "CodeSystem.concept", "CodeSystem.concept.concept") && "CodeSystem.concept.display".equals(pathForElement(element))) {
return setDesignationTranslation(parent, translation.getLanguage(), translation.getTgtText());
}
if (Utilities.existsInList(pathForElement(parent), "ValueSet.compose.include.concept") && "ValueSet.compose.include.concept.display".equals(pathForElement(element))) {
return setDesignationTranslation(parent, translation.getLanguage(), translation.getTgtText());
}
if (Utilities.existsInList(pathForElement(parent), "ValueSet.expansion.contains", "ValueSet.expansion.contains.contains") && "ValueSet.expansion.contains.display".equals(pathForElement(element))) {
return setDesignationTranslation(parent, translation.getLanguage(), translation.getTgtText());
}
return false;
}
private boolean setDesignationTranslation(Element parent, String targetLang, String translation) {
for (Element e : parent.getChildren("designation")) {
String lang = e.getNamedChildValue("language");
if (langsMatch(targetLang, lang)) {
Element value = e.getNamedChild("value");
if (value != null) {
value.setValue(translation);
} else {
e.addElement("value").setValue(translation);
}
return true;
}
}
Element d = parent.addElement("designation");
d.addElement("language").setValue(targetLang);
d.addElement("value").setValue(translation);
return true;
}
private Set<TranslationUnit> findTranslations(String path, String src, Set<TranslationUnit> translations) {
Set<TranslationUnit> res = new HashSet<>();
for (TranslationUnit translation : translations) {
if (path.equals(translation.getContext()) && src.equals(translation.getSrcText())) {
res.add(translation);
}
}
return res;
}
public static boolean langsMatch(String dstLang, String srcLang) {
return dstLang == null ? false : dstLang.equals(srcLang);
}
}

View File

@ -139,13 +139,26 @@ public class CodeSystemRenderer extends TerminologyRenderer {
}
}
private String sentenceForContent(CodeSystemContentMode mode) {
private String sentenceForContent(CodeSystemContentMode mode, CodeSystem cs) {
switch (mode) {
case COMPLETE: return "This code system <param name='cs'/> defines the following code<if test='code-count != 1'>s</if>:";
case EXAMPLE: return "This code system <param name='cs'/> provides some example code<if test='code-count != 1'>s</if>:";
case FRAGMENT: return "This code system <param name='cs'/> provides a fragment that includes following code<if test='code-count != 1'>s</if>:";
case NOTPRESENT: return "This code system <param name='cs'/> defines codes, but no codes are represented here";
case SUPPLEMENT: return "This code system <param name='cs'/> defines properties on the following code<if test='code-count != 1'>s</if>:";
case SUPPLEMENT:
boolean properties = CodeSystemUtilities.hasProperties(cs);
boolean designations = CodeSystemUtilities.hasDesignations(cs);
String features;
if (properties && designations) {
features = "displays and properties";
} else if (properties) {
features = "properties";
} else if (designations) {
features = "displays";
} else {
features = "features"; // ?
}
return "This code system <param name='cs'/> defines "+features+" on the following code<if test='code-count != 1'>s</if>:";
}
throw new FHIRException("Unknown CodeSystemContentMode mode");
}
@ -157,7 +170,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
XhtmlNode p = x.para();
p.param("cs").code().tx(cs.getUrl());
p.paramValue("code-count", CodeSystemUtilities.countCodes(cs));
p.sentenceForParams(sentenceForContent(cs.getContent()));
p.sentenceForParams(sentenceForContent(cs.getContent(), cs));
if (cs.getContent() == CodeSystemContentMode.NOTPRESENT) {
return false;
}
@ -186,6 +199,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
}
}
}
List<String> langs = new ArrayList<>();
for (ConceptDefinitionComponent c : cs.getConcept()) {
commentS = commentS || conceptsHaveComments(c);
deprecated = deprecated || conceptsHaveDeprecated(cs, c, ignoreStatus);
@ -193,16 +207,20 @@ public class CodeSystemRenderer extends TerminologyRenderer {
version = version || conceptsHaveVersion(c);
hierarchy = hierarchy || c.hasConcept();
definitions = definitions || conceptsHaveDefinition(c);
listConceptLanguages(cs, c, langs);
}
CodeSystemNavigator csNav = new CodeSystemNavigator(cs);
hierarchy = hierarchy || csNav.isRestructure();
List<String> langs = new ArrayList<>();
if (langs.size() < 2) {
addCopyColumn(addMapHeaders(addTableHeaderRowStandard(t, hierarchy, display, definitions, commentS, version, deprecated, properties, langs, null, true), maps));
} else {
addCopyColumn(addMapHeaders(addTableHeaderRowStandard(t, hierarchy, display, definitions, commentS, version, deprecated, properties, null, null, false), maps));
for (ConceptDefinitionComponent c : csNav.getConcepts(null)) {
hasExtensions = addDefineRowToTable(t, c, 0, hierarchy, display, definitions, commentS, version, deprecated, maps, cs.getUrl(), cs, properties, csNav, langs, isSupplement) || hasExtensions;
}
if (langs.size() > 0) {
for (ConceptDefinitionComponent c : csNav.getConcepts(null)) {
hasExtensions = addDefineRowToTable(t, c, 0, hierarchy, display, definitions, commentS, version, deprecated, maps, cs.getUrl(), cs, properties, csNav, langs.size() < 2 ? langs : null, isSupplement) || hasExtensions;
}
if (langs.size() >= 2) {
Collections.sort(langs);
x.para().b().tx("Additional Language Displays");
t = x.table("codes");
@ -217,6 +235,18 @@ public class CodeSystemRenderer extends TerminologyRenderer {
return hasExtensions;
}
private void listConceptLanguages(CodeSystem cs, ConceptDefinitionComponent c, List<String> langs) {
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
if (cd.hasLanguage() && !langs.contains(cd.getLanguage()) && (!cs.hasLanguage() || !cs.getLanguage().equals(cd.getLanguage()))) {
langs.add(cd.getLanguage());
}
}
for (ConceptDefinitionComponent g : c.getConcept()) {
listConceptLanguages(cs, g, langs);
}
}
private void addCopyColumn(XhtmlNode tr) {
if (context.isCopyButton()) {
tr.td().b().tx("Copy");
@ -353,13 +383,6 @@ public class CodeSystemRenderer extends TerminologyRenderer {
td.an(cs.getId()+"-" + Utilities.nmtokenize(c.getCode()));
}
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
if (cd.hasLanguage() && !langs.contains(cd.getLanguage()) && (!cs.hasLanguage() || !cs.getLanguage().equals(cd.getLanguage()))) {
langs.add(cd.getLanguage());
}
}
if (hasDisplay) {
td = tr.td();
renderDisplayName(c, cs, td);
@ -491,6 +514,11 @@ public class CodeSystemRenderer extends TerminologyRenderer {
}
}
if (langs != null) {
for (String lang : langs) {
td = tr.td().tx(getDisplay(lang, c));
}
}
for (UsedConceptMap m : maps) {
td = tr.td();
List<TargetElementComponentWrapper> mappings = findMappingsForCode(c.getCode(), m.getMap());
@ -540,6 +568,20 @@ public class CodeSystemRenderer extends TerminologyRenderer {
return hasExtensions;
}
private String getDisplay(String lang, ConceptDefinitionComponent c) {
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "display") && cd.hasLanguage() && cd.getLanguage().equals(lang)) {
return cd.getValue();
}
}
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
if (cd.hasLanguage() && cd.getLanguage().equals(lang)) {
return cd.getValue();
}
}
return null;
}
private boolean hasMarkdownInDefinitions(CodeSystem cs) {
return ToolingExtensions.readBoolExtension(cs, "http://hl7.org/fhir/StructureDefinition/codesystem-use-markdown");
}

View File

@ -240,13 +240,17 @@ public abstract class TerminologyRenderer extends ResourceRenderer {
}
}
if (doDesignations) {
if (designations != null) {
for (String url : designations.keySet()) {
tr.td().b().addText(designations.get(url));
}
}
if (langs != null) {
for (String lang : langs) {
tr.td().b().addText(describeLang(lang));
}
}
}
return tr;
}

View File

@ -818,5 +818,31 @@ public class CodeSystemUtilities {
}
return null;
}
public static boolean hasProperties(CodeSystem cs) {
return hasProperties(cs.getConcept());
}
private static boolean hasProperties(List<ConceptDefinitionComponent> list) {
for (ConceptDefinitionComponent c : list) {
if (c.hasProperty() || hasProperties(c.getConcept())) {
return true;
}
}
return false;
}
public static boolean hasDesignations(CodeSystem cs) {
return hasDesignations(cs.getConcept());
}
private static boolean hasDesignations(List<ConceptDefinitionComponent> list) {
for (ConceptDefinitionComponent c : list) {
if (c.hasDesignation() || hasDesignations(c.getConcept())) {
return true;
}
}
return false;
}
}

View File

@ -299,7 +299,7 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx
ConceptDefinitionDesignationComponent tu = expParams.hasParameter("displayLanguage") ? getMatchingLang(designations, expParams.getParameterString("displayLanguage")) : null;
if (tu != null) {
n.setDisplay(tu.getValue());
} else if (display != null && (srcLang == null || dstLang == null || LanguageUtils.matches(dstLang, srcLang))) {
} else if (display != null && (srcLang == null || dstLang == null || LanguageUtils.langsMatch(dstLang, srcLang))) {
n.setDisplay(display);
usedDisplay = true;
} else {

View File

@ -1,10 +1,15 @@
package org.hl7.fhir.utilities.i18n;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TextUnit;
import org.xml.sax.SAXException;
import java.util.HashMap;
@ -12,9 +17,9 @@ import java.util.HashMap;
public abstract class LanguageFileProducer {
public static class TextUnit {
private String context;
private String srcText;
private String tgtText;
protected String context;
protected String srcText;
protected String tgtText;
public TextUnit(String context, String srcText, String tgtText) {
super();
this.context = context;
@ -33,6 +38,32 @@ public abstract class LanguageFileProducer {
return tgtText;
}
}
public static class TranslationUnit extends TextUnit {
private String language;
public TranslationUnit(String language, String context, String srcText, String tgtText) {
super(context, srcText, tgtText);
this.language = language;
}
public String getLanguage() {
return language;
}
public void setContext(String context) {
this.context = context;
}
public void setSrcText(String srcText) {
this.srcText = srcText;
}
public void setTgtText(String tgtText) {
this.tgtText = tgtText;
}
}
public class Translations {
@ -98,6 +129,10 @@ public abstract class LanguageFileProducer {
this.folder = folder;
}
public LanguageFileProducer() {
super();
}
public String getFolder() {
return folder;
}
@ -105,7 +140,7 @@ public abstract class LanguageFileProducer {
public abstract LanguageProducerSession startSession(String id, String baseLang) throws IOException;
public abstract void finish();
public abstract List<TextUnit> loadTranslations(String id, String baseLang, String targetLang) throws IOException;
public abstract List<TranslationUnit> loadSource(InputStream source) throws IOException, ParserConfigurationException, SAXException;
public abstract int fileCount();
}

View File

@ -1,7 +1,10 @@
package org.hl7.fhir.utilities.i18n;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.ArrayList;
@ -9,6 +12,7 @@ import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.LanguageProducerLanguageSession;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.LanguageProducerSession;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TranslationUnit;
import org.hl7.fhir.utilities.i18n.PoGetTextProducer.POGetTextLanguageProducerLanguageSession;
import org.hl7.fhir.utilities.i18n.PoGetTextProducer.POGetTextProducerSession;
import org.hl7.fhir.utilities.i18n.XLIFFProducer.XLiffLanguageProducerLanguageSession;
@ -21,6 +25,10 @@ public class PoGetTextProducer extends LanguageFileProducer {
super(folder);
}
public PoGetTextProducer() {
super();
}
@Override
public LanguageProducerSession startSession(String id, String baseLang) throws IOException {
return new POGetTextProducerSession(id, baseLang);
@ -90,13 +98,49 @@ public class PoGetTextProducer extends LanguageFileProducer {
}
@Override
public List<TextUnit> loadTranslations(String id, String baseLang, String targetLang) throws IOException {
List<TextUnit> res = new ArrayList<>();
File f = new File(getFileName(id, baseLang, targetLang));
if (f.exists()) {
public List<TranslationUnit> loadSource(InputStream source) throws IOException {
List<TranslationUnit> list = new ArrayList<>();
InputStreamReader r = new InputStreamReader(source, "UTF-8"); // leave charset out for default
BufferedReader br = new BufferedReader(r);
String lang = null;
String s;
TranslationUnit tu = null;
while ((s = Utilities.stripBOM(br.readLine())) != null) {
if (!Utilities.noString(s)) {
if (s.trim().startsWith("#")) {
if (lang == null) {
String[] p = s.substring(1).trim().split("\\-\\>");
if (p.length != 2) {
throw new IOException("Encountered unexpected starting line '"+s+"'");
} else {
lang = p[1].trim();
}
return res;
} else if (s.startsWith("#:")) {
tu = new TranslationUnit(lang, s.substring(2).trim(), null, null);
} else {
throw new IOException("Encountered unexpected line '"+s+"'");
}
} else if (tu != null && s.startsWith("msgid ")) {
tu.setSrcText(stripQuotes(s.substring(5).trim()));
} else if (tu != null && s.startsWith("msgstr ")) {
tu.setTgtText(stripQuotes(s.substring(6).trim()));
if (tu.getTgtText() != null) {
list.add(tu);
}
tu = null;
} else {
throw new IOException("Encountered unexpected line '"+s+"'");
}
}
}
return list;
}
private String stripQuotes(String s) {
if (s.length() <= 2) {
return null;
}
return s.substring(1, s.length()-1);
}
private String getFileName(String id, String baseLang, String targetLang) throws IOException {

View File

@ -1,11 +1,20 @@
package org.hl7.fhir.utilities.i18n;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TextUnit;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TranslationUnit;
import org.hl7.fhir.utilities.xml.XMLUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
public class XLIFFProducer extends LanguageFileProducer {
@ -77,6 +86,10 @@ public class XLIFFProducer extends LanguageFileProducer {
super(folder);
}
public XLIFFProducer() {
super();
}
@Override
public LanguageProducerSession startSession(String id, String baseLang) throws IOException {
return new XLiffLanguageProducerSession(id, baseLang);
@ -88,8 +101,31 @@ public class XLIFFProducer extends LanguageFileProducer {
}
@Override
public List<TextUnit> loadTranslations(String id, String baseLang, String tgtLang) {
return null;
public List<TranslationUnit> loadSource(InputStream source) throws IOException, ParserConfigurationException, SAXException {
List<TranslationUnit> list = new ArrayList<>();
Document dom = XMLUtil.parseToDom(TextFile.streamToBytes(source));
Element xliff = dom.getDocumentElement();
if (!xliff.getNodeName().equals("xliff")) {
throw new IOException("Not an XLIFF document");
}
for (Element file : XMLUtil.getNamedChildren(xliff, "file")) {
Element body = XMLUtil.getNamedChild(file, "body");
for (Element transUnit : XMLUtil.getNamedChildren(body, "trans-unit")) {
TranslationUnit tu = new TranslationUnit(file.getAttribute("target-language"), transUnit.getAttribute("id"),
XMLUtil.getNamedChildText(transUnit, "source"), XMLUtil.getNamedChildText(transUnit, "target"));
if (!Utilities.noString(tu.getSrcText()) && !Utilities.noString(tu.getTgtText())) {
list.add(tu);
}
}
}
return list;
}
private void check(String string, boolean equals) {
// TODO Auto-generated method stub
}
@Override

View File

@ -94,6 +94,8 @@ public class CliContext {
private List<String> profiles = new ArrayList<String>();
@JsonProperty("sources")
private List<String> sources = new ArrayList<String>();
@JsonProperty("inputs")
private List<String> inputs = new ArrayList<String>();
@JsonProperty("mode")
private EngineMode mode = EngineMode.VALIDATION;
@ -389,6 +391,11 @@ public class CliContext {
return sources;
}
@JsonProperty("inputs")
public List<String> getInputs() {
return inputs;
}
@JsonProperty("sources")
public CliContext setSources(List<String> sources) {
this.sources = sources;
@ -721,7 +728,7 @@ public class CliContext {
public int hashCode() {
return Objects.hash(doNative, extensions, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching,
noExtensibleBindingMessages, noInvariants, wantInvariantsInMessages, map, output, outputSuffix, htmlOutput, txServer, sv, txLog, txCache, mapLog, lang, srcLang, tgtLang, fhirpath, snomedCT,
targetVer, igs, questionnaireMode, level, profiles, sources, mode, locale, locations, crumbTrails, forPublication, showTimes, allowExampleUrls, outputStyle, jurisdiction, noUnicodeBiDiControlChars);
targetVer, igs, questionnaireMode, level, profiles, sources, inputs, mode, locale, locations, crumbTrails, forPublication, showTimes, allowExampleUrls, outputStyle, jurisdiction, noUnicodeBiDiControlChars);
}
@Override
@ -759,6 +766,7 @@ public class CliContext {
", level=" + level +
", profiles=" + profiles +
", sources=" + sources +
", inputs=" + inputs +
", mode=" + mode +
", securityChecks=" + securityChecks +
", crumbTrails=" + crumbTrails +

View File

@ -12,10 +12,13 @@ import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r4b.model.AdministrableProductDefinition;
import org.hl7.fhir.r5.conformance.R5ExtensionsLoader;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.context.ContextUtilities;
@ -27,6 +30,7 @@ import org.hl7.fhir.r5.elementmodel.LanguageUtils;
import org.hl7.fhir.r5.elementmodel.Manager;
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.r5.formats.IParser;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CodeSystem;
@ -50,6 +54,7 @@ import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.LanguageProducerLanguageSession;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.LanguageProducerSession;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TranslationUnit;
import org.hl7.fhir.utilities.i18n.PoGetTextProducer;
import org.hl7.fhir.utilities.i18n.XLIFFProducer;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
@ -530,6 +535,9 @@ public class ValidationService {
case "extract":
transformLangExtract(cliContext, validator);
break;
case "inject":
transformLangInject(cliContext, validator);
break;
default:
System.out.println(" ...Unknown lang transform mode "+cliContext.getLangTransform());
}
@ -560,86 +568,67 @@ public class ValidationService {
}
System.out.println("Done - produced "+(po.fileCount()+xliff.fileCount()) + " files in "+dst);
}
//
// try {
// OperationOutcome outcome = validate(ref, cnt.focus, cnt.cntType, profiles, record);
// ToolingExtensions.addStringExtension(outcome, ToolingExtensions.EXT_OO_FILE, ref);
// System.out.println(" " + context.clock().milestone());
// results.addEntry().setResource(outcome);
// tts.end();
// } catch (Exception e) {
// System.out.println("Validation Infrastructure fail validating " + ref + ": " + e.getMessage());
// tts.end();
// throw new FHIRException(e);
// }
// }
// if (asBundle)
// return results;
// else
// return results.getEntryFirstRep().getResource();
//
// List<ValidationRecord> records = new ArrayList<>();
// Resource r = validator.validate(cliContext.getSources(), cliContext.getProfiles(), records);
// MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();
// System.out.println("Done. " + validator.getContext().clock().report()+". Memory = "+Utilities.describeSize(mbean.getHeapMemoryUsage().getUsed()+mbean.getNonHeapMemoryUsage().getUsed()));
// System.out.println();
//
// PrintStream dst = null;
// ValidationOutputRenderer renderer = makeValidationOutputRenderer(cliContext);
// renderer.setCrumbTrails(validator.isCrumbTrails());
// renderer.setRunDate(runDate);
// if (renderer.isSingleFile()) {
// if (cliContext.getOutput() == null) {
// dst = System.out;
// } else {
// dst = new PrintStream(new FileOutputStream(cliContext.getOutput()));
// }
// renderer.setOutput(dst);
// } else {
// File dir = new File(cliContext.getOutput());
// if (!dir.isDirectory()) {
// throw new Error("The output location "+dir.getAbsolutePath()+" must be an existing directory for the output style "+renderer.getStyleCode());
// }
// renderer.setFolder(dir);
// }
//
// int ec = 0;
//
// if (r instanceof Bundle) {
// if (renderer.handlesBundleDirectly()) {
// renderer.render((Bundle) r);
// } else {
// renderer.start(((Bundle) r).getEntry().size() > 1);
// for (Bundle.BundleEntryComponent e : ((Bundle) r).getEntry()) {
// OperationOutcome op = (OperationOutcome) e.getResource();
// ec = ec + countErrors(op);
// renderer.render(op);
// }
// renderer.finish();
// }
// } else if (r == null) {
// ec = ec + 1;
// System.out.println("No output from validation - nothing to validate");
// } else {
// renderer.start(false);
// OperationOutcome op = (OperationOutcome) r;
// ec = countErrors(op);
// renderer.render((OperationOutcome) r);
// renderer.finish();
// }
//
// if (cliContext.getOutput() != null && dst != null) {
// dst.close();
// }
//
// if (cliContext.getHtmlOutput() != null) {
// String html = new HTMLOutputGenerator(records).generate(System.currentTimeMillis() - start);
// TextFile.stringToFile(html, cliContext.getHtmlOutput());
// System.out.println("HTML Summary in " + cliContext.getHtmlOutput());
// }
// System.exit(ec > 0 ? 1 : 0);
//
// }
private void transformLangInject(CliContext cliContext, ValidationEngine validator) throws IOException {
String dst = cliContext.getOutput();
Utilities.createDirectory(dst);
Set<TranslationUnit> translations = new HashSet<>();
for (String input : cliContext.getInputs()) {
loadTranslationSource(translations, input);
}
List<String> refs = new ArrayList<String>();
ValidatorUtils.parseSources(cliContext.getSources(), refs, validator.getContext());
int t = 0;
for (String ref : refs) {
System.out.println(" Inject Translations into " + ref);
org.hl7.fhir.validation.Content cnt = validator.getIgLoader().loadContent(ref, "translate", false);
Element e = Manager.parseSingle(validator.getContext(), new ByteArrayInputStream(cnt.getFocus()), cnt.getCntType());
t = t + new LanguageUtils(validator.getContext()).importFromTranslations(e, translations);
Manager.compose(validator.getContext(), e, new FileOutputStream(Utilities.path(dst, new File(ref).getName())), cnt.getCntType(),
OutputStyle.PRETTY, null);
}
System.out.println("Done - imported "+t+" translations into "+refs.size()+ " in "+dst);
}
private void loadTranslationSource(Set<TranslationUnit> translations, String input) {
File f = new File(input);
if (f.exists()) {
if (f.isDirectory()) {
for (File fd : f.listFiles()) {
loadTranslationSource(translations, fd.getAbsolutePath());
}
} else {
if (f.getName().endsWith(".po")) {
try {
translations.addAll(new PoGetTextProducer().loadSource(new FileInputStream(f)));
} catch (Exception e) {
System.out.println("Error reading PO File "+f.getAbsolutePath()+": "+e.getMessage());
}
} else if (f.getName().endsWith(".xliff")) {
try {
translations.addAll(new XLIFFProducer().loadSource(new FileInputStream(f)));
} catch (Exception e) {
System.out.println("Error reading XLIFF File "+f.getAbsolutePath()+": "+e.getMessage());
}
} else {
try {
translations.addAll(new PoGetTextProducer().loadSource(new FileInputStream(f)));
} catch (Exception e) {
try {
translations.addAll(new XLIFFProducer().loadSource(new FileInputStream(f)));
} catch (Exception e2) {
System.out.println("Error reading File "+f.getAbsolutePath()+" as XLIFF: "+e2.getMessage());
System.out.println("Error reading File "+f.getAbsolutePath()+" as PO: "+e.getMessage());
}
}
}
}
} else {
System.out.println("Input not found: "+input);
}
}
private int cp;
private int cs;

View File

@ -92,6 +92,7 @@ public class Params {
public static final String SPECIAL = "-special";
public static final String TARGET = "-target";
public static final String SOURCE = "-source";
public static final String INPUT = "-input";
public static final String FILTER = "-filter";
private static final String FHIR_SETTINGS_PARAM = "-fhir-settings";
@ -158,8 +159,7 @@ public class Params {
i++;
} else if (args[i].equals(HTTPS_PROXY)) {
i++;
}
else if (args[i].equals(PROFILE)) {
} else if (args[i].equals(PROFILE)) {
String p = null;
if (i + 1 == args.length) {
throw new Error("Specified -profile without indicating profile source");
@ -195,6 +195,13 @@ public class Params {
String q = args[++i];
cliContext.setLevel(ValidationLevel.fromCode(q));
}
} else if (args[i].equals(INPUT)) {
if (i + 1 == args.length)
throw new Error("Specified -input without providing value");
else {
String inp = args[++i];
cliContext.getInputs().add(inp);
}
} else if (args[i].equals(NATIVE)) {
cliContext.setDoNative(true);
} else if (args[i].equals(ASSUME_VALID_REST_REF)) {