forked from GitHub/gf-core
Visualization for parse trees on Android
This commit is contained in:
@@ -12,16 +12,18 @@
|
|||||||
android:paddingRight="5dp" />
|
android:paddingRight="5dp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/lexical_desc"
|
android:id="@+id/alternative_desc"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_toRightOf="@id/arrow"
|
android:layout_toRightOf="@id/arrow"
|
||||||
android:paddingLeft="10dp"
|
android:paddingLeft="10dp"
|
||||||
android:textSize="25sp"/>
|
android:textSize="25sp"/>
|
||||||
|
|
||||||
<WebView
|
<org.grammaticalframework.ui.android.ParseTreeView
|
||||||
android:id="@+id/lexical_inflection"
|
android:id="@+id/desc_details"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@id/lexical_desc"/>
|
android:layout_below="@id/alternative_desc"
|
||||||
|
android:textSize="25sp"
|
||||||
|
/>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
27
src/ui/android/res/layout/lexical_item.xml
Normal file
27
src/ui/android/res/layout/lexical_item.xml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent" >
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/arrow"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:contentDescription="@string/open_image"
|
||||||
|
android:src="@drawable/open_arrow"
|
||||||
|
android:paddingLeft="10dp"
|
||||||
|
android:paddingRight="5dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/lexical_desc"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_toRightOf="@id/arrow"
|
||||||
|
android:paddingLeft="10dp"
|
||||||
|
android:textSize="25sp"/>
|
||||||
|
|
||||||
|
<WebView
|
||||||
|
android:id="@+id/desc_details"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/lexical_desc"/>
|
||||||
|
</RelativeLayout>
|
||||||
@@ -103,8 +103,8 @@ public class AlternativesActivity extends ListActivity {
|
|||||||
ImageView arrow = (ImageView) expandedView.findViewById(R.id.arrow);
|
ImageView arrow = (ImageView) expandedView.findViewById(R.id.arrow);
|
||||||
arrow.setImageResource(R.drawable.open_arrow);
|
arrow.setImageResource(R.drawable.open_arrow);
|
||||||
|
|
||||||
WebView inflectionView = (WebView) expandedView.findViewById(R.id.lexical_inflection);
|
View view = (View) expandedView.findViewById(R.id.desc_details);
|
||||||
((RelativeLayout) expandedView).removeView(inflectionView);
|
((RelativeLayout) expandedView).removeView(view);
|
||||||
|
|
||||||
expandedView = null;
|
expandedView = null;
|
||||||
}
|
}
|
||||||
@@ -117,10 +117,10 @@ public class AlternativesActivity extends ListActivity {
|
|||||||
ImageView arrow = (ImageView) view.findViewById(R.id.arrow);
|
ImageView arrow = (ImageView) view.findViewById(R.id.arrow);
|
||||||
arrow.setImageResource(R.drawable.close_arrow);
|
arrow.setImageResource(R.drawable.close_arrow);
|
||||||
|
|
||||||
WebView inflectionView = (WebView) view.findViewById(R.id.lexical_inflection);
|
WebView inflectionView = (WebView) view.findViewById(R.id.desc_details);
|
||||||
if (inflectionView == null) {
|
if (inflectionView == null) {
|
||||||
inflectionView = new WebView(this);
|
inflectionView = new WebView(this);
|
||||||
inflectionView.setId(R.id.lexical_inflection);
|
inflectionView.setId(R.id.desc_details);
|
||||||
RelativeLayout.LayoutParams params =
|
RelativeLayout.LayoutParams params =
|
||||||
new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
||||||
params.addRule(RelativeLayout.BELOW, R.id.lexical_desc);
|
params.addRule(RelativeLayout.BELOW, R.id.lexical_desc);
|
||||||
@@ -136,18 +136,18 @@ public class AlternativesActivity extends ListActivity {
|
|||||||
ImageView arrow = (ImageView) view.findViewById(R.id.arrow);
|
ImageView arrow = (ImageView) view.findViewById(R.id.arrow);
|
||||||
arrow.setImageResource(R.drawable.close_arrow);
|
arrow.setImageResource(R.drawable.close_arrow);
|
||||||
|
|
||||||
WebView inflectionView = (WebView) view.findViewById(R.id.lexical_inflection);
|
ParseTreeView parseView = (ParseTreeView) view.findViewById(R.id.desc_details);
|
||||||
if (inflectionView == null) {
|
if (parseView == null) {
|
||||||
inflectionView = new WebView(this);
|
parseView = new ParseTreeView(this);
|
||||||
inflectionView.setId(R.id.lexical_inflection);
|
parseView.setId(R.id.desc_details);
|
||||||
RelativeLayout.LayoutParams params =
|
RelativeLayout.LayoutParams params =
|
||||||
new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
||||||
params.addRule(RelativeLayout.BELOW, R.id.lexical_desc);
|
params.addRule(RelativeLayout.BELOW, R.id.alternative_desc);
|
||||||
((RelativeLayout) view).addView(inflectionView, params);
|
((RelativeLayout) view).addView(parseView, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
String content = String.format("[%.4f] %s", ep.getProb(), ep.getExpr());
|
Object[] brackets = mTranslator.bracketedLinearize(ep.getExpr());
|
||||||
inflectionView.loadData(content, "text/plain; charset=UTF-8", null);
|
parseView.setBrackets(brackets);
|
||||||
|
|
||||||
expandedView = view;
|
expandedView = view;
|
||||||
}
|
}
|
||||||
@@ -160,16 +160,16 @@ public class AlternativesActivity extends ListActivity {
|
|||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
Object item = getItem(position);
|
Object item = getItem(position);
|
||||||
|
|
||||||
if (convertView == null) {
|
|
||||||
LayoutInflater inflater = (LayoutInflater)
|
|
||||||
getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
|
|
||||||
convertView = inflater.inflate(R.layout.alternative_item, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextView descView = (TextView)
|
|
||||||
convertView.findViewById(R.id.lexical_desc);
|
|
||||||
|
|
||||||
if (item instanceof MorphoAnalysis) {
|
if (item instanceof MorphoAnalysis) {
|
||||||
|
if (convertView == null) {
|
||||||
|
LayoutInflater inflater = (LayoutInflater)
|
||||||
|
getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
|
||||||
|
convertView = inflater.inflate(R.layout.lexical_item, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextView descView = (TextView)
|
||||||
|
convertView.findViewById(R.id.lexical_desc);
|
||||||
|
|
||||||
final String lemma = ((MorphoAnalysis) item).getLemma();
|
final String lemma = ((MorphoAnalysis) item).getLemma();
|
||||||
|
|
||||||
String phrase = mTranslator.generateLexiconEntry(lemma);
|
String phrase = mTranslator.generateLexiconEntry(lemma);
|
||||||
@@ -188,55 +188,62 @@ public class AlternativesActivity extends ListActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else if (item instanceof ExprProb) {
|
||||||
if (item instanceof ExprProb) {
|
final ExprProb ep = (ExprProb) item;
|
||||||
final ExprProb ep = (ExprProb) item;
|
|
||||||
|
if (convertView == null) {
|
||||||
String phrase = mTranslator.linearize(ep.getExpr());
|
LayoutInflater inflater = (LayoutInflater)
|
||||||
|
getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
|
||||||
|
convertView = inflater.inflate(R.layout.alternative_item, null);
|
||||||
|
}
|
||||||
|
|
||||||
// parse by words, marked by %, darkest red color
|
TextView descView = (TextView)
|
||||||
if (phrase.charAt(0) == '%') {
|
convertView.findViewById(R.id.alternative_desc);
|
||||||
descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_worst_utterance_bg));
|
|
||||||
phrase = phrase.substring(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse by chunks, marked by *, red color
|
String phrase = mTranslator.linearize(ep.getExpr());
|
||||||
else if (phrase.charAt(0) == '*') {
|
|
||||||
descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_chunk_utterance_bg));
|
|
||||||
phrase = phrase.substring(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse error or unknown translations (in []) present, darkest red color
|
// parse by words, marked by %, darkest red color
|
||||||
else if (phrase.contains("parse error:") || phrase.contains("[")) {
|
if (phrase.charAt(0) == '%') {
|
||||||
descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_worst_utterance_bg));
|
descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_worst_utterance_bg));
|
||||||
}
|
phrase = phrase.substring(2);
|
||||||
|
}
|
||||||
|
|
||||||
// parse by domain grammar, marked by +, green color
|
// parse by chunks, marked by *, red color
|
||||||
else if (phrase.charAt(0) == '+') {
|
else if (phrase.charAt(0) == '*') {
|
||||||
descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_best_utterance_bg));
|
descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_chunk_utterance_bg));
|
||||||
phrase = phrase.substring(2);
|
phrase = phrase.substring(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
|
||||||
descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_utterance_bg));
|
|
||||||
}
|
|
||||||
|
|
||||||
descView.setText(phrase);
|
// parse error or unknown translations (in []) present, darkest red color
|
||||||
|
else if (phrase.contains("parse error:") || phrase.contains("[")) {
|
||||||
|
descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_worst_utterance_bg));
|
||||||
|
}
|
||||||
|
|
||||||
convertView.setOnClickListener(new OnClickListener() {
|
// parse by domain grammar, marked by +, green color
|
||||||
@Override
|
else if (phrase.charAt(0) == '+') {
|
||||||
public void onClick(View view) {
|
descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_best_utterance_bg));
|
||||||
if (expandedView == view)
|
phrase = phrase.substring(2);
|
||||||
collapse();
|
}
|
||||||
else if (expandedView == null)
|
|
||||||
expandExpr(view, ep);
|
else {
|
||||||
else {
|
descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_utterance_bg));
|
||||||
collapse();
|
}
|
||||||
expandExpr(view, ep);
|
|
||||||
}
|
descView.setText(phrase);
|
||||||
|
|
||||||
|
convertView.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
if (expandedView == view)
|
||||||
|
collapse();
|
||||||
|
else if (expandedView == null)
|
||||||
|
expandExpr(view, ep);
|
||||||
|
else {
|
||||||
|
collapse();
|
||||||
|
expandExpr(view, ep);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return convertView;
|
return convertView;
|
||||||
|
|||||||
@@ -0,0 +1,221 @@
|
|||||||
|
package org.grammaticalframework.ui.android;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.PointF;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.util.Pair;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
import android.view.View;
|
||||||
|
import org.grammaticalframework.pgf.Bracket;
|
||||||
|
|
||||||
|
|
||||||
|
public class ParseTreeView extends View {
|
||||||
|
private static final float SISTER_SKIP = 25;
|
||||||
|
private static final float PARENT_SKIP = 0.5f;
|
||||||
|
private static final float ABOVE_LINE_SKIP = 0.1f;
|
||||||
|
private static final float BELOW_LINE_SKIP = 0.1f;
|
||||||
|
|
||||||
|
private Paint paint;
|
||||||
|
private Object[] brackets;
|
||||||
|
|
||||||
|
public ParseTreeView(Context context) {
|
||||||
|
super(context);
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParseTreeView(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize() {
|
||||||
|
paint = new Paint();
|
||||||
|
paint.setTextSize(60);
|
||||||
|
brackets = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] getBrackets() {
|
||||||
|
return brackets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBrackets(Object[] brackets) {
|
||||||
|
this.brackets = brackets;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class MeasureResult {
|
||||||
|
float width = 0.0f;
|
||||||
|
float height = 0.0f;
|
||||||
|
float nodeTab = 0.0f;
|
||||||
|
float nodeCenter = 0.0f;
|
||||||
|
float childTab = 0.0f;
|
||||||
|
float localWidth = 0.0f;
|
||||||
|
float localHeight = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MeasureResult mr = new MeasureResult();
|
||||||
|
private SparseArray<PointF> coords = new SparseArray<PointF>();
|
||||||
|
|
||||||
|
private void measureTree(Object o, PointF zeroPoint) {
|
||||||
|
if (o instanceof Bracket) {
|
||||||
|
Bracket bracket = (Bracket) o;
|
||||||
|
|
||||||
|
Rect bounds = new Rect();
|
||||||
|
paint.getTextBounds(bracket.cat,0,bracket.cat.length(),bounds);
|
||||||
|
float localWidth = bounds.width();
|
||||||
|
float localHeight = bounds.height();
|
||||||
|
float layerHeight = localHeight * (1.0f + BELOW_LINE_SKIP + ABOVE_LINE_SKIP + PARENT_SKIP);
|
||||||
|
|
||||||
|
PointF local = coords.get(bracket.fid);
|
||||||
|
if (local == null) {
|
||||||
|
if (zeroPoint != null)
|
||||||
|
coords.put(bracket.fid, zeroPoint);
|
||||||
|
} else {
|
||||||
|
localWidth = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float subWidth = 0.0f;
|
||||||
|
float subHeight = 0.0f;
|
||||||
|
float nodeCenter = 0.0f;
|
||||||
|
for (int i = 0; i < bracket.children.length; i++) {
|
||||||
|
measureTree(bracket.children[i], zeroPoint);
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
nodeCenter += (subWidth + mr.nodeCenter) / 2.0;
|
||||||
|
}
|
||||||
|
if (i == bracket.children.length - 1) {
|
||||||
|
nodeCenter += (subWidth + mr.nodeCenter) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
subWidth += mr.width;
|
||||||
|
if (i < bracket.children.length - 1) {
|
||||||
|
subWidth += SISTER_SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subHeight < mr.height)
|
||||||
|
subHeight = mr.height;
|
||||||
|
}
|
||||||
|
float localLeft = localWidth / 2.0f;
|
||||||
|
float subLeft = nodeCenter;
|
||||||
|
float totalLeft = Math.max(localLeft, subLeft);
|
||||||
|
float localRight = localWidth / 2.0f;
|
||||||
|
float subRight = subWidth - nodeCenter;
|
||||||
|
float totalRight = Math.max(localRight, subRight);
|
||||||
|
mr.width = totalLeft + totalRight;
|
||||||
|
mr.height = layerHeight + subHeight;
|
||||||
|
mr.childTab = totalLeft - subLeft;
|
||||||
|
mr.nodeTab = totalLeft - localLeft;
|
||||||
|
mr.nodeCenter = nodeCenter + mr.childTab;
|
||||||
|
mr.localWidth = localWidth;
|
||||||
|
mr.localHeight = localHeight;
|
||||||
|
} else {
|
||||||
|
String word = o.toString();
|
||||||
|
|
||||||
|
Rect bounds = new Rect();
|
||||||
|
paint.getTextBounds(word,0,word.length(),bounds);
|
||||||
|
mr.width = bounds.width();
|
||||||
|
mr.height = bounds.height();
|
||||||
|
mr.nodeTab = 0.0f;
|
||||||
|
mr.nodeCenter = bounds.width() / 2.0f;
|
||||||
|
mr.childTab = 0.0f;
|
||||||
|
mr.localWidth = bounds.width();
|
||||||
|
mr.localHeight = bounds.height();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
if (brackets == null) {
|
||||||
|
setMeasuredDimension(0, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float width = 0.0f;
|
||||||
|
float height = 0.0f;
|
||||||
|
PointF zeroPoint = new PointF();
|
||||||
|
for (int i = 0; i < brackets.length; i++) {
|
||||||
|
measureTree(brackets[i], zeroPoint);
|
||||||
|
|
||||||
|
width += mr.width;
|
||||||
|
if (i < brackets.length - 1) {
|
||||||
|
width += SISTER_SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (height < mr.height)
|
||||||
|
height = mr.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
width += 10;
|
||||||
|
height += 10;
|
||||||
|
|
||||||
|
int w = getPaddingLeft() + (int) width + getPaddingRight();
|
||||||
|
int h = getPaddingTop() + (int) height + getPaddingBottom();
|
||||||
|
|
||||||
|
setMeasuredDimension(w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawTree(Canvas canvas,
|
||||||
|
float x, float y, float bottom, PointF parentPoint,
|
||||||
|
Object o) {
|
||||||
|
if (o instanceof Bracket) {
|
||||||
|
Bracket bracket = (Bracket) o;
|
||||||
|
|
||||||
|
PointF lineStart = coords.get(bracket.fid);
|
||||||
|
if (lineStart == null) {
|
||||||
|
lineStart = new PointF(x + mr.nodeCenter, y + mr.localHeight * (1.0f + BELOW_LINE_SKIP));
|
||||||
|
coords.put(bracket.fid, lineStart);
|
||||||
|
|
||||||
|
if (parentPoint != null) {
|
||||||
|
float lineEndX = x + mr.nodeCenter;
|
||||||
|
float lineEndY = y;
|
||||||
|
canvas.drawLine(parentPoint.x, parentPoint.y, lineEndX, lineEndY, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.drawText(bracket.cat, x+mr.nodeTab, y+mr.localHeight, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
float layerMultiplier = (1.0f + BELOW_LINE_SKIP + ABOVE_LINE_SKIP + PARENT_SKIP);
|
||||||
|
float layerHeight = mr.localHeight * layerMultiplier;
|
||||||
|
float childStartX = x + mr.childTab;
|
||||||
|
float childStartY = y + layerHeight;
|
||||||
|
for (int i = 0; i < bracket.children.length; i++) {
|
||||||
|
Object child = bracket.children[i];
|
||||||
|
measureTree(child, null);
|
||||||
|
float w = mr.width;
|
||||||
|
drawTree(canvas, childStartX, childStartY, bottom, lineStart, child);
|
||||||
|
childStartX += w + SISTER_SKIP;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
float lineEndX = x + mr.nodeCenter;
|
||||||
|
float lineEndY = bottom - mr.height;
|
||||||
|
canvas.drawLine(parentPoint.x, parentPoint.y, lineEndX, lineEndY, paint);
|
||||||
|
canvas.drawText(o.toString(), x, bottom, paint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw (Canvas canvas) {
|
||||||
|
super.onDraw(canvas);
|
||||||
|
|
||||||
|
if (brackets == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
coords.clear();
|
||||||
|
|
||||||
|
float startX = getPaddingLeft();
|
||||||
|
for (int i = 0; i < brackets.length; i++) {
|
||||||
|
Object child = brackets[i];
|
||||||
|
|
||||||
|
measureTree(child, null);
|
||||||
|
float w = mr.width;
|
||||||
|
drawTree(canvas, startX, getPaddingTop(), getPaddingTop()+mr.height, null, child);
|
||||||
|
startX += w + SISTER_SKIP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -340,6 +340,11 @@ public class Translator {
|
|||||||
return targetLang.linearize(expr);
|
return targetLang.linearize(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Object[] bracketedLinearize(Expr expr) {
|
||||||
|
Concr targetLang = getTargetConcr();
|
||||||
|
return targetLang.bracketedLinearize(expr);
|
||||||
|
}
|
||||||
|
|
||||||
public String generateLexiconEntry(String lemma) {
|
public String generateLexiconEntry(String lemma) {
|
||||||
Concr sourceLang = getSourceConcr();
|
Concr sourceLang = getSourceConcr();
|
||||||
Concr targetLang = getTargetConcr();
|
Concr targetLang = getTargetConcr();
|
||||||
|
|||||||
Reference in New Issue
Block a user