Language improvements for Lang Packs

This commit is contained in:
Grahame Grieve 2023-05-01 18:09:15 +10:00
parent 89c1c8608c
commit 7b5aceb722
6 changed files with 288 additions and 2 deletions

View File

@ -1,12 +1,19 @@
package org.hl7.fhir.r5.elementmodel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.checkerframework.checker.units.qual.cd;
import org.hl7.fhir.r5.context.ContextUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionDesignationComponent;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer;
@ -29,6 +36,12 @@ import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TranslationUnit;
*/
public class LanguageUtils {
public static final List<String> TRANSLATION_SUPPLEMENT_RESOURCE_TYPES = Arrays.asList("CodeSystem", "StructureDefinition");
private static final String ORPHAN_TRANSLATIONS_NAME = "translations.orphans";
private static final String SUPPLEMENT_NAME = "translations.supplement";
IWorkerContext context;
private List<String> crlist;
@ -185,4 +198,84 @@ public class LanguageUtils {
public static boolean langsMatch(String dstLang, String srcLang) {
return dstLang == null ? false : dstLang.equals(srcLang);
}
public static void fillSupplement(CodeSystem cs, List<TranslationUnit> list) {
cs.setUserData(SUPPLEMENT_NAME, "true");
for (TranslationUnit tu : list) {
ConceptDefinitionComponent cd = CodeSystemUtilities.getCode(cs, tu.getContext());
if (cd != null && cd.hasDisplay() && cd.getDisplay().equals(tu.getSrcText())) {
cd.addDesignation().setLanguage(tu.getLanguage()).setValue(tu.getTgtText());
} else {
addOrphanTranslation(cs, tu);
}
}
}
private static void addOrphanTranslation(CodeSystem cs, TranslationUnit tu) {
List<TranslationUnit> list = (List<TranslationUnit>) cs.getUserData(ORPHAN_TRANSLATIONS_NAME);
if (list == null) {
list = new ArrayList<>();
cs.setUserData(ORPHAN_TRANSLATIONS_NAME, list);
}
list.add(tu);
}
public static String nameForLang(String lang) {
// todo: replace with structures from loading languages properly
switch (lang) {
case "en" : return "English";
case "de" : return "German";
case "es" : return "Spanish";
case "nl" : return "Dutch";
}
return Utilities.capitalize(lang);
}
public static String titleForLang(String lang) {
// todo: replace with structures from loading languages properly
switch (lang) {
case "en" : return "English";
case "de" : return "German";
case "es" : return "Spanish";
case "nl" : return "Dutch";
}
return Utilities.capitalize(lang);
}
public static boolean handlesAsResource(Resource resource) {
return (resource instanceof CodeSystem && resource.hasUserData(SUPPLEMENT_NAME));
}
public static boolean handlesAsElement(Element element) {
return false; // for now...
}
public static List<TranslationUnit> generateTranslations(Resource res, String lang) {
List<TranslationUnit> list = new ArrayList<>();
CodeSystem cs = (CodeSystem) res;
for (ConceptDefinitionComponent cd : cs.getConcept()) {
generateTranslations(list, cd, lang);
}
return list;
}
private static void generateTranslations(List<TranslationUnit> list, ConceptDefinitionComponent cd, String lang) {
String code = cd.getCode();
String display = cd.getDisplay();
String target = null;
for (ConceptDefinitionDesignationComponent d : cd.getDesignation()) {
if (target == null && !d.hasUse() && d.hasLanguage() && lang.equals(d.getLanguage())) {
target = d.getValue();
}
}
for (ConceptDefinitionDesignationComponent d : cd.getDesignation()) {
if (target == null && d.hasLanguage() && lang.equals(d.getLanguage())) {
target = d.getValue();
}
}
list.add(new TranslationUnit(lang, code, display, target));
for (ConceptDefinitionComponent cd1 : cd.getConcept()) {
generateTranslations(list, cd1, lang);
}
}
}

View File

@ -40,7 +40,7 @@ import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import javax.annotation.Nonnull;
public class QuestionnaireRenderer extends TerminologyRenderer {
public static final String EXT_QUESTIONNAIRE_ITEM_TYPE_ORIGINAL = "http://hl7.org/fhir/tools/StructureDefinition/original-item-type";
public static final String EXT_QUESTIONNAIRE_ITEM_TYPE_ORIGINAL = "http://hl7.org/fhir/4.0/StructureDefinition/extension-Questionnaire.item.type";
public QuestionnaireRenderer(RenderingContext context) {
super(context);

View File

@ -0,0 +1,128 @@
package org.hl7.fhir.utilities.i18n;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TranslationUnit;
import org.hl7.fhir.utilities.json.model.JsonObject;
import org.hl7.fhir.utilities.json.parser.JsonParser;
public class JsonLangFileProducer extends LanguageFileProducer {
public JsonLangFileProducer(String folder) {
super(folder);
}
public JsonLangFileProducer() {
super();
}
@Override
public LanguageProducerSession startSession(String id, String baseLang) throws IOException {
return new JsonLangProducerSession(id, baseLang);
}
@Override
public void finish() {
// nothing
}
public class JsonLangProducerSession extends LanguageProducerSession {
JsonObject json = new JsonObject();
public JsonLangProducerSession(String id, String baseLang) {
super (id, baseLang);
json.add("id", id);
json.add("baseLang", baseLang);
}
@Override
public LanguageProducerLanguageSession forLang(String targetLang) {
return new JsonLangLanguageProducerLanguageSession(id, baseLang, targetLang, json);
}
@Override
public void finish() throws IOException {
JsonParser.compose(json, new FileOutputStream(getFileName(id, baseLang)));
}
}
public class JsonLangLanguageProducerLanguageSession extends LanguageProducerLanguageSession {
private JsonObject json;
public JsonLangLanguageProducerLanguageSession(String id, String baseLang, String targetLang, JsonObject parent) {
super(id, baseLang, targetLang);
json = new JsonObject();
parent.forceArray("languages").add(json);
json.add("targetLang", targetLang);
}
@Override
public void finish() throws IOException {
}
@Override
public void entry(TextUnit unit) {
JsonObject entry = new JsonObject();
json.forceArray("entries").add(entry);
entry.add("context", unit.getContext());
entry.add("source", unit.getSrcText());
entry.add("target", unit.getTgtText());
}
}
@Override
public List<TranslationUnit> loadSource(InputStream source) throws IOException {
List<TranslationUnit> list = new ArrayList<>();
JsonObject json = JsonParser.parseObject(source);
for (JsonObject lang : json.forceArray("languages").asJsonObjects()) {
for (JsonObject entry : lang.forceArray("entries").asJsonObjects()) {
list.add(new TranslationUnit(lang.asString("targetLang"), entry.asString("context"), entry.asString("source"), entry.asString("target")));
}
}
return list;
}
private String getFileName(String id, String baseLang) throws IOException {
return Utilities.path(getFolder(), id+"-"+baseLang+".json");
}
@Override
public int fileCount() {
return 1;
}
@Override
public void produce(String id, String baseLang, String targetLang, List<TranslationUnit> translations, String filename) throws IOException {
JsonObject json = new JsonObject();
json.add("id", id);
json.add("baseLang", baseLang);
JsonObject lj = new JsonObject();
json.forceArray("languages").add(lj);
lj.add("targetLang", targetLang);
for (TranslationUnit tu : translations) {
JsonObject entry = new JsonObject();
lj.forceArray("entries").add(entry);
entry.add("context", tu.getContext());
entry.add("source", tu.getSrcText());
entry.add("target", tu.getTgtText());
}
TextFile.stringToFile(JsonParser.compose(json, true), Utilities.path(getFolder(), filename));
}
}

View File

@ -9,6 +9,7 @@ import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TextUnit;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TranslationUnit;
import org.xml.sax.SAXException;
import java.util.HashMap;
@ -143,4 +144,6 @@ public abstract class LanguageFileProducer {
public abstract List<TranslationUnit> loadSource(InputStream source) throws IOException, ParserConfigurationException, SAXException;
public abstract int fileCount();
public abstract void produce(String id, String baseLang, String targetLang, List<TranslationUnit> translations, String filename) throws IOException;
}

View File

@ -20,6 +20,7 @@ import org.hl7.fhir.utilities.i18n.XLIFFProducer.XLiffLanguageProducerLanguageSe
public class PoGetTextProducer extends LanguageFileProducer {
private int filecount;
private boolean incLangInFilename;
public PoGetTextProducer(String folder) {
super(folder);
@ -144,8 +145,38 @@ public class PoGetTextProducer extends LanguageFileProducer {
}
private String getFileName(String id, String baseLang, String targetLang) throws IOException {
return Utilities.path(getFolder(), id+"-"+baseLang+"-"+targetLang+".po");
return Utilities.path(getFolder(), id+(incLangInFilename ? "-"+baseLang+"-"+targetLang+".po" : ""));
}
public boolean isIncLangInFilename() {
return incLangInFilename;
}
public void setIncLangInFilename(boolean incLangInFilename) {
this.incLangInFilename = incLangInFilename;
}
protected void ln(StringBuilder po, String line) {
po.append(line+"\r\n");
}
@Override
public void produce(String id, String baseLang, String targetLang, List<TranslationUnit> translations, String filename) throws IOException {
StringBuilder po = new StringBuilder();
ln(po, "# "+baseLang+" -> "+targetLang);
ln(po, "");
for (TranslationUnit tu : translations) {
ln(po, "#: "+tu.getContext());
// if (context != null) {
// ln("#. "+context);
// }
ln(po, "msgid \""+tu.getSrcText()+"\"");
ln(po, "msgstr \""+(tu.getTgtText() == null ? "" : tu.getTgtText())+"\"");
ln(po, "");
}
TextFile.stringToFile(po.toString(), Utilities.path(getFolder(), filename));
}
}

View File

@ -11,6 +11,8 @@ 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.json.model.JsonObject;
import org.hl7.fhir.utilities.json.parser.JsonParser;
import org.hl7.fhir.utilities.xml.XMLUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@ -132,4 +134,33 @@ public class XLIFFProducer extends LanguageFileProducer {
public int fileCount() {
return filecount;
}
protected void ln(StringBuilder xml, String line) {
xml.append(line+"\r\n");
}
@Override
public void produce(String id, String baseLang, String targetLang, List<TranslationUnit> translations, String filename) throws IOException {
StringBuilder xml = new StringBuilder();
ln(xml, "<?xml version=\"1.0\" ?>\r\n");
ln(xml, "<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\">");
ln(xml, " <file source-language=\""+baseLang+"\" target-language=\""+targetLang+"\" id=\""+id+"\" original=\"Resource "+id+"\" datatype=\"KEYVALUEJSON\">");
ln(xml, " <body>");
for (TranslationUnit tu : translations) {
ln(xml, " <trans-unit id=\""+id+"\" resname=\""+tu.getContext()+"\">");
ln(xml, " <source>"+Utilities.escapeXml(tu.getSrcText())+"</source>");
ln(xml, " <target>"+Utilities.escapeXml(tu.getTgtText())+"</target>");
ln(xml, " </trans-unit>");
}
ln(xml, " </body>");
ln(xml, " </file>");
ln(xml, "</xliff>");
TextFile.stringToFile(xml.toString(), Utilities.path(getFolder(), filename));
}
}