Internationalize all messages without substitutions.

pull/106/head
whitequark 2017-01-07 06:41:13 +00:00
parent 4fda1e4361
commit 984f74d271
21 changed files with 3316 additions and 806 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -212,21 +212,20 @@ if(HAVE_GETTEXT)
set(output_pot ${CMAKE_CURRENT_SOURCE_DIR}/../res/messages.pot)
set(templ_po ${CMAKE_CURRENT_BINARY_DIR}/messages.po)
set(output_po ${CMAKE_CURRENT_SOURCE_DIR}/../res/locales/en_US.po)
set(inputs)
foreach(input ${solvespace_core_SOURCES})
list(APPEND inputs ${CMAKE_CURRENT_SOURCE_DIR}/${input})
endforeach()
set(inputs ${solvespace_core_SOURCES})
add_custom_command(
OUTPUT ${output_pot}
COMMAND ${XGETTEXT}
--keyword --keyword=_ --keyword=N_
--keyword --keyword=_ --keyword=N_ --keyword=C_:2,1c --keyword=CN_:2,1c
--force-po --width=100 --sort-by-file
--package-name=SolveSpace --package-version=3.0
--package-name=SolveSpace
--package-version=${solvespace_VERSION_MAJOR}.${solvespace_VERSION_MINOR}
"--copyright-holder=the PACKAGE authors"
--msgid-bugs-address=whitequark@whitequark.org
--from-code=utf-8 --output=${output_pot} ${inputs}
DEPENDS ${inputs}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Extracting translations"
VERBATIM)
add_custom_command(
@ -240,7 +239,7 @@ if(HAVE_GETTEXT)
DEPENDS ${output_pot}
COMMENT "Updating English translations"
VERBATIM)
add_custom_target(solvespace-translations ALL
add_custom_target(solvespace-translations
DEPENDS ${output_pot} ${output_po})
endif()

View File

@ -239,8 +239,8 @@ void GraphicsWindow::PasteClipboard(Vector trans, double theta, double scale) {
void GraphicsWindow::MenuClipboard(Command id) {
if(id != Command::DELETE && !SS.GW.LockedInWorkplane()) {
Error("Cut, paste, and copy work only in a workplane.\n\n"
"Activate one with Sketch -> In Workplane.");
Error(_("Cut, paste, and copy work only in a workplane.\n\n"
"Activate one with Sketch -> In Workplane."));
return;
}
@ -256,7 +256,7 @@ void GraphicsWindow::MenuClipboard(Command id) {
case Command::PASTE_TRANSFORM: {
if(SS.clipboard.r.n == 0) {
Error("Clipboard is empty; nothing to paste.");
Error(_("Clipboard is empty; nothing to paste."));
break;
}
@ -303,7 +303,7 @@ bool TextWindow::EditControlDoneForPaste(const char *s) {
if(v > 0) {
shown.paste.times = v;
} else {
Error("Number of copies to paste must be at least one.");
Error(_("Number of copies to paste must be at least one."));
}
break;
}
@ -319,7 +319,7 @@ bool TextWindow::EditControlDoneForPaste(const char *s) {
if(fabs(v) > 1e-6) {
shown.paste.scale = v;
} else {
Error("Scale cannot be zero.");
Error(_("Scale cannot be zero."));
}
break;
}
@ -357,7 +357,7 @@ void TextWindow::ScreenPasteTransformed(int link, uint32_t v) {
Entity *e = SK.GetEntity(SS.GW.gs.point[0]);
SS.TW.shown.paste.origin = e->PointGetNum();
} else {
Error("Select one point to define origin of rotation.");
Error(_("Select one point to define origin of rotation."));
}
SS.GW.ClearSelection();
break;
@ -369,7 +369,7 @@ void TextWindow::ScreenPasteTransformed(int link, uint32_t v) {
SS.TW.shown.paste.trans =
(pb->PointGetNum()).Minus(pa->PointGetNum());
} else {
Error("Select two points to define translation vector.");
Error(_("Select two points to define translation vector."));
}
SS.GW.ClearSelection();
break;
@ -379,16 +379,16 @@ void TextWindow::ScreenPasteTransformed(int link, uint32_t v) {
SS.TW.shown.paste.trans.Magnitude() < LENGTH_EPS &&
SS.TW.shown.paste.times != 1)
{
Message("Transformation is identity. So all copies will be "
"exactly on top of each other.");
Message(_("Transformation is identity. So all copies will be "
"exactly on top of each other."));
}
if(SS.TW.shown.paste.times*SS.clipboard.r.n > 100) {
Error("Too many items to paste; split this into smaller "
"pastes.");
Error(_("Too many items to paste; split this into smaller "
"pastes."));
break;
}
if(!SS.GW.LockedInWorkplane()) {
Error("No workplane active.");
Error(_("No workplane active."));
break;
}
Entity *wrkpl = SK.GetEntity(SS.GW.ActiveWorkplane());

View File

@ -325,7 +325,7 @@ bool TextWindow::EditControlDoneForConfiguration(const char *s) {
if(sscanf(s, "%lf, %lf, %lf", &x, &y, &z)==3) {
SS.lightDir[edit.i] = Vector::From(x, y, z);
} else {
Error("Bad format: specify coordinates as x, y, z");
Error(_("Bad format: specify coordinates as x, y, z"));
}
InvalidateGraphics();
break;
@ -336,7 +336,7 @@ bool TextWindow::EditControlDoneForConfiguration(const char *s) {
rgb = rgb.ClampWithin(0, 1);
SS.modelColor[edit.i] = RGBf(rgb.x, rgb.y, rgb.z);
} else {
Error("Bad format: specify color as r, g, b");
Error(_("Bad format: specify color as r, g, b"));
}
break;
}
@ -361,8 +361,8 @@ bool TextWindow::EditControlDoneForConfiguration(const char *s) {
case Edit::CAMERA_TANGENT: {
SS.cameraTangent = (min(2.0, max(0.0, atof(s))))/1000.0;
if(!SS.usePerspectiveProj) {
Message("The perspective factor will have no effect until you "
"enable View -> Use Perspective Projection.");
Message(_("The perspective factor will have no effect until you "
"enable View -> Use Perspective Projection."));
}
InvalidateGraphics();
break;
@ -375,7 +375,7 @@ bool TextWindow::EditControlDoneForConfiguration(const char *s) {
case Edit::DIGITS_AFTER_DECIMAL: {
int v = atoi(s);
if(v < 0 || v > 8) {
Error("Specify between 0 and 8 digits after the decimal.");
Error(_("Specify between 0 and 8 digits after the decimal."));
} else {
SS.SetUnitDigitsAfterDecimal(v);
}
@ -387,7 +387,7 @@ bool TextWindow::EditControlDoneForConfiguration(const char *s) {
if(e) {
double ev = e->Eval();
if(fabs(ev) < 0.001 || isnan(ev)) {
Error("Export scale must not be zero!");
Error(_("Export scale must not be zero!"));
} else {
SS.exportScale = (float)ev;
}
@ -399,7 +399,7 @@ bool TextWindow::EditControlDoneForConfiguration(const char *s) {
if(e) {
double ev = SS.ExprToMm(e);
if(isnan(ev) || ev < 0) {
Error("Cutter radius offset must not be negative!");
Error(_("Cutter radius offset must not be negative!"));
} else {
SS.exportOffset = (float)ev;
}
@ -453,10 +453,10 @@ bool TextWindow::EditControlDoneForConfiguration(const char *s) {
SS.autosaveInterval = interval;
SetAutosaveTimerFor(interval);
} else {
Error("Bad value: autosave interval should be positive");
Error(_("Bad value: autosave interval should be positive"));
}
} else {
Error("Bad format: specify interval in integral minutes");
Error(_("Bad format: specify interval in integral minutes"));
}
break;
}

View File

@ -7,47 +7,47 @@
#include "solvespace.h"
std::string Constraint::DescriptionString() const {
const char *s;
std::string s;
switch(type) {
case Type::POINTS_COINCIDENT: s = "pts-coincident"; break;
case Type::PT_PT_DISTANCE: s = "pt-pt-distance"; break;
case Type::PT_LINE_DISTANCE: s = "pt-line-distance"; break;
case Type::PT_PLANE_DISTANCE: s = "pt-plane-distance"; break;
case Type::PT_FACE_DISTANCE: s = "pt-face-distance"; break;
case Type::PROJ_PT_DISTANCE: s = "proj-pt-pt-distance"; break;
case Type::PT_IN_PLANE: s = "pt-in-plane"; break;
case Type::PT_ON_LINE: s = "pt-on-line"; break;
case Type::PT_ON_FACE: s = "pt-on-face"; break;
case Type::EQUAL_LENGTH_LINES: s = "eq-length"; break;
case Type::EQ_LEN_PT_LINE_D: s = "eq-length-and-pt-ln-dist"; break;
case Type::EQ_PT_LN_DISTANCES: s = "eq-pt-line-distances"; break;
case Type::LENGTH_RATIO: s = "length-ratio"; break;
case Type::LENGTH_DIFFERENCE: s = "length-difference"; break;
case Type::SYMMETRIC: s = "symmetric"; break;
case Type::SYMMETRIC_HORIZ: s = "symmetric-h"; break;
case Type::SYMMETRIC_VERT: s = "symmetric-v"; break;
case Type::SYMMETRIC_LINE: s = "symmetric-line"; break;
case Type::AT_MIDPOINT: s = "at-midpoint"; break;
case Type::HORIZONTAL: s = "horizontal"; break;
case Type::VERTICAL: s = "vertical"; break;
case Type::DIAMETER: s = "diameter"; break;
case Type::PT_ON_CIRCLE: s = "pt-on-circle"; break;
case Type::SAME_ORIENTATION: s = "same-orientation"; break;
case Type::ANGLE: s = "angle"; break;
case Type::PARALLEL: s = "parallel"; break;
case Type::ARC_LINE_TANGENT: s = "arc-line-tangent"; break;
case Type::CUBIC_LINE_TANGENT: s = "cubic-line-tangent"; break;
case Type::CURVE_CURVE_TANGENT: s = "curve-curve-tangent"; break;
case Type::PERPENDICULAR: s = "perpendicular"; break;
case Type::EQUAL_RADIUS: s = "eq-radius"; break;
case Type::EQUAL_ANGLE: s = "eq-angle"; break;
case Type::EQUAL_LINE_ARC_LEN: s = "eq-line-len-arc-len"; break;
case Type::WHERE_DRAGGED: s = "lock-where-dragged"; break;
case Type::COMMENT: s = "comment"; break;
default: s = "???"; break;
case Type::POINTS_COINCIDENT: s = C_("constr-name", "pts-coincident"); break;
case Type::PT_PT_DISTANCE: s = C_("constr-name", "pt-pt-distance"); break;
case Type::PT_LINE_DISTANCE: s = C_("constr-name", "pt-line-distance"); break;
case Type::PT_PLANE_DISTANCE: s = C_("constr-name", "pt-plane-distance"); break;
case Type::PT_FACE_DISTANCE: s = C_("constr-name", "pt-face-distance"); break;
case Type::PROJ_PT_DISTANCE: s = C_("constr-name", "proj-pt-pt-distance"); break;
case Type::PT_IN_PLANE: s = C_("constr-name", "pt-in-plane"); break;
case Type::PT_ON_LINE: s = C_("constr-name", "pt-on-line"); break;
case Type::PT_ON_FACE: s = C_("constr-name", "pt-on-face"); break;
case Type::EQUAL_LENGTH_LINES: s = C_("constr-name", "eq-length"); break;
case Type::EQ_LEN_PT_LINE_D: s = C_("constr-name", "eq-length-and-pt-ln-dist"); break;
case Type::EQ_PT_LN_DISTANCES: s = C_("constr-name", "eq-pt-line-distances"); break;
case Type::LENGTH_RATIO: s = C_("constr-name", "length-ratio"); break;
case Type::LENGTH_DIFFERENCE: s = C_("constr-name", "length-difference"); break;
case Type::SYMMETRIC: s = C_("constr-name", "symmetric"); break;
case Type::SYMMETRIC_HORIZ: s = C_("constr-name", "symmetric-h"); break;
case Type::SYMMETRIC_VERT: s = C_("constr-name", "symmetric-v"); break;
case Type::SYMMETRIC_LINE: s = C_("constr-name", "symmetric-line"); break;
case Type::AT_MIDPOINT: s = C_("constr-name", "at-midpoint"); break;
case Type::HORIZONTAL: s = C_("constr-name", "horizontal"); break;
case Type::VERTICAL: s = C_("constr-name", "vertical"); break;
case Type::DIAMETER: s = C_("constr-name", "diameter"); break;
case Type::PT_ON_CIRCLE: s = C_("constr-name", "pt-on-circle"); break;
case Type::SAME_ORIENTATION: s = C_("constr-name", "same-orientation"); break;
case Type::ANGLE: s = C_("constr-name", "angle"); break;
case Type::PARALLEL: s = C_("constr-name", "parallel"); break;
case Type::ARC_LINE_TANGENT: s = C_("constr-name", "arc-line-tangent"); break;
case Type::CUBIC_LINE_TANGENT: s = C_("constr-name", "cubic-line-tangent"); break;
case Type::CURVE_CURVE_TANGENT: s = C_("constr-name", "curve-curve-tangent"); break;
case Type::PERPENDICULAR: s = C_("constr-name", "perpendicular"); break;
case Type::EQUAL_RADIUS: s = C_("constr-name", "eq-radius"); break;
case Type::EQUAL_ANGLE: s = C_("constr-name", "eq-angle"); break;
case Type::EQUAL_LINE_ARC_LEN: s = C_("constr-name", "eq-line-len-arc-len"); break;
case Type::WHERE_DRAGGED: s = C_("constr-name", "lock-where-dragged"); break;
case Type::COMMENT: s = C_("constr-name", "comment"); break;
default: s = "???"; break;
}
return ssprintf("c%03x-%s", h.v, s);
return ssprintf("c%03x-%s", h.v, s.c_str());
}
#ifndef LIBRARY
@ -156,16 +156,15 @@ void Constraint::MenuConstrain(Command id) {
c.type = Type::DIAMETER;
c.entityA = gs.entity[0];
} else {
Error(
"Bad selection for distance / diameter constraint. This "
"constraint can apply to:\n\n"
" * two points (distance between points)\n"
" * a line segment (length)\n"
" * two points and a line segment or normal (projected distance)\n"
" * a workplane and a point (minimum distance)\n"
" * a line segment and a point (minimum distance)\n"
" * a plane face and a point (minimum distance)\n"
" * a circle or an arc (diameter)\n");
Error(_("Bad selection for distance / diameter constraint. This "
"constraint can apply to:\n\n"
" * two points (distance between points)\n"
" * a line segment (length)\n"
" * two points and a line segment or normal (projected distance)\n"
" * a workplane and a point (minimum distance)\n"
" * a line segment and a point (minimum distance)\n"
" * a plane face and a point (minimum distance)\n"
" * a circle or an arc (diameter)\n"));
return;
}
if(c.type == Type::PT_PT_DISTANCE || c.type == Type::PROJ_PT_DISTANCE) {
@ -210,13 +209,13 @@ void Constraint::MenuConstrain(Command id) {
c.ptA = gs.point[0];
c.entityA = gs.face[0];
} else {
Error("Bad selection for on point / curve / plane constraint. "
"This constraint can apply to:\n\n"
" * two points (points coincident)\n"
" * a point and a workplane (point in plane)\n"
" * a point and a line segment (point on line)\n"
" * a point and a circle or arc (point on curve)\n"
" * a point and a plane face (point on face)\n");
Error(_("Bad selection for on point / curve / plane constraint. "
"This constraint can apply to:\n\n"
" * two points (points coincident)\n"
" * a point and a workplane (point in plane)\n"
" * a point and a line segment (point on line)\n"
" * a point and a circle or arc (point on curve)\n"
" * a point and a plane face (point on face)\n"));
return;
}
AddConstraint(&c);
@ -272,22 +271,22 @@ void Constraint::MenuConstrain(Command id) {
c.entityB = gs.entity[1];
}
} else {
Error("Bad selection for equal length / radius constraint. "
"This constraint can apply to:\n\n"
" * two line segments (equal length)\n"
" * two line segments and two points "
"(equal point-line distances)\n"
" * a line segment and two points "
"(equal point-line distances)\n"
" * a line segment, and a point and line segment "
"(point-line distance equals length)\n"
" * four line segments or normals "
"(equal angle between A,B and C,D)\n"
" * three line segments or normals "
"(equal angle between A,B and B,C)\n"
" * two circles or arcs (equal radius)\n"
" * a line segment and an arc "
"(line segment length equals arc length)\n");
Error(_("Bad selection for equal length / radius constraint. "
"This constraint can apply to:\n\n"
" * two line segments (equal length)\n"
" * two line segments and two points "
"(equal point-line distances)\n"
" * a line segment and two points "
"(equal point-line distances)\n"
" * a line segment, and a point and line segment "
"(point-line distance equals length)\n"
" * four line segments or normals "
"(equal angle between A,B and C,D)\n"
" * three line segments or normals "
"(equal angle between A,B and B,C)\n"
" * two circles or arcs (equal radius)\n"
" * a line segment and an arc "
"(line segment length equals arc length)\n"));
return;
}
if(c.type == Type::EQUAL_ANGLE) {
@ -311,9 +310,9 @@ void Constraint::MenuConstrain(Command id) {
c.entityA = gs.entity[0];
c.entityB = gs.entity[1];
} else {
Error("Bad selection for length ratio constraint. This "
"constraint can apply to:\n\n"
" * two line segments\n");
Error(_("Bad selection for length ratio constraint. This "
"constraint can apply to:\n\n"
" * two line segments\n"));
return;
}
@ -328,9 +327,9 @@ void Constraint::MenuConstrain(Command id) {
c.entityA = gs.entity[0];
c.entityB = gs.entity[1];
} else {
Error("Bad selection for length difference constraint. This "
"constraint can apply to:\n\n"
" * two line segments\n");
Error(_("Bad selection for length difference constraint. This "
"constraint can apply to:\n\n"
" * two line segments\n"));
return;
}
@ -354,12 +353,12 @@ void Constraint::MenuConstrain(Command id) {
c.entityA = gs.entity[i];
c.entityB = gs.entity[1-i];
} else {
Error("Bad selection for at midpoint constraint. This "
"constraint can apply to:\n\n"
" * a line segment and a point "
"(point at midpoint)\n"
" * a line segment and a workplane "
"(line's midpoint on plane)\n");
Error(_("Bad selection for at midpoint constraint. This "
"constraint can apply to:\n\n"
" * a line segment and a point "
"(point at midpoint)\n"
" * a line segment and a workplane "
"(line's midpoint on plane)\n"));
return;
}
AddConstraint(&c);
@ -412,22 +411,22 @@ void Constraint::MenuConstrain(Command id) {
c.entityA = gs.entity[0];
c.type = Type::SYMMETRIC_LINE;
} else {
Error("Bad selection for symmetric constraint. This constraint "
"can apply to:\n\n"
" * two points or a line segment "
"(symmetric about workplane's coordinate axis)\n"
" * line segment, and two points or a line segment "
"(symmetric about line segment)\n"
" * workplane, and two points or a line segment "
"(symmetric about workplane)\n");
Error(_("Bad selection for symmetric constraint. This constraint "
"can apply to:\n\n"
" * two points or a line segment "
"(symmetric about workplane's coordinate axis)\n"
" * line segment, and two points or a line segment "
"(symmetric about line segment)\n"
" * workplane, and two points or a line segment "
"(symmetric about workplane)\n"));
return;
}
if(c.entityA.v == Entity::NO_ENTITY.v) {
// Horizontal / vertical symmetry, implicit symmetry plane
// normal to the workplane
if(c.workplane.v == Entity::FREE_IN_3D.v) {
Error("A workplane must be active when constraining "
"symmetric without an explicit symmetry plane.");
Error(_("A workplane must be active when constraining "
"symmetric without an explicit symmetry plane."));
return;
}
Vector pa = SK.GetEntity(c.ptA)->PointGetNum();
@ -456,8 +455,8 @@ void Constraint::MenuConstrain(Command id) {
case Command::HORIZONTAL: {
hEntity ha, hb;
if(c.workplane.v == Entity::FREE_IN_3D.v) {
Error("Activate a workplane (with Sketch -> In Workplane) before "
"applying a horizontal or vertical constraint.");
Error(_("Activate a workplane (with Sketch -> In Workplane) before "
"applying a horizontal or vertical constraint."));
return;
}
if(gs.lineSegments == 1 && gs.n == 1) {
@ -469,10 +468,10 @@ void Constraint::MenuConstrain(Command id) {
ha = c.ptA = gs.point[0];
hb = c.ptB = gs.point[1];
} else {
Error("Bad selection for horizontal / vertical constraint. "
"This constraint can apply to:\n\n"
" * two points\n"
" * a line segment\n");
Error(_("Bad selection for horizontal / vertical constraint. "
"This constraint can apply to:\n\n"
" * two points\n"
" * a line segment\n"));
return;
}
if(id == Command::HORIZONTAL) {
@ -490,9 +489,9 @@ void Constraint::MenuConstrain(Command id) {
c.entityA = gs.anyNormal[0];
c.entityB = gs.anyNormal[1];
} else {
Error("Bad selection for same orientation constraint. This "
"constraint can apply to:\n\n"
" * two normals\n");
Error(_("Bad selection for same orientation constraint. This "
"constraint can apply to:\n\n"
" * two normals\n"));
return;
}
SS.UndoRemember();
@ -542,7 +541,7 @@ void Constraint::MenuConstrain(Command id) {
break;
}
}
Error("Must select an angle constraint.");
Error(_("Must select an angle constraint."));
return;
case Command::REFERENCE:
@ -554,7 +553,7 @@ void Constraint::MenuConstrain(Command id) {
break;
}
}
Error("Must select a constraint with associated label.");
Error(_("Must select a constraint with associated label."));
return;
case Command::ANGLE:
@ -565,11 +564,11 @@ void Constraint::MenuConstrain(Command id) {
c.entityB = gs.vector[1];
c.valA = 0;
} else {
Error("Bad selection for angle constraint. This constraint "
"can apply to:\n\n"
" * two line segments\n"
" * a line segment and a normal\n"
" * two normals\n");
Error(_("Bad selection for angle constraint. This constraint "
"can apply to:\n\n"
" * two line segments\n"
" * a line segment and a normal\n"
" * two normals\n"));
return;
}
@ -622,9 +621,9 @@ void Constraint::MenuConstrain(Command id) {
} else if(l0.Equals(a2) || l1.Equals(a2)) {
c.other = true;
} else {
Error("The tangent arc and line segment must share an "
"endpoint. Constrain them with Constrain -> "
"On Point before constraining tangent.");
Error(_("The tangent arc and line segment must share an "
"endpoint. Constrain them with Constrain -> "
"On Point before constraining tangent."));
return;
}
c.type = Type::ARC_LINE_TANGENT;
@ -646,9 +645,9 @@ void Constraint::MenuConstrain(Command id) {
} else if(l0.Equals(af) || l1.Equals(af)) {
c.other = true;
} else {
Error("The tangent cubic and line segment must share an "
"endpoint. Constrain them with Constrain -> "
"On Point before constraining tangent.");
Error(_("The tangent cubic and line segment must share an "
"endpoint. Constrain them with Constrain -> "
"On Point before constraining tangent."));
return;
}
c.type = Type::CUBIC_LINE_TANGENT;
@ -656,7 +655,7 @@ void Constraint::MenuConstrain(Command id) {
c.entityB = line->h;
} else if(gs.cubics + gs.arcs == 2 && gs.n == 2) {
if(!SS.GW.LockedInWorkplane()) {
Error("Curve-curve tangency must apply in workplane.");
Error(_("Curve-curve tangency must apply in workplane."));
return;
}
Entity *eA = SK.GetEntity(gs.entity[0]),
@ -674,22 +673,22 @@ void Constraint::MenuConstrain(Command id) {
} else if(af.Equals(bf)) {
c.other = true; c.other2 = true;
} else {
Error("The curves must share an endpoint. Constrain them "
"with Constrain -> On Point before constraining "
"tangent.");
Error(_("The curves must share an endpoint. Constrain them "
"with Constrain -> On Point before constraining "
"tangent."));
return;
}
c.type = Type::CURVE_CURVE_TANGENT;
c.entityA = eA->h;
c.entityB = eB->h;
} else {
Error("Bad selection for parallel / tangent constraint. This "
"constraint can apply to:\n\n"
" * two line segments (parallel)\n"
" * a line segment and a normal (parallel)\n"
" * two normals (parallel)\n"
" * two line segments, arcs, or beziers, that share "
"an endpoint (tangent)\n");
Error(_("Bad selection for parallel / tangent constraint. This "
"constraint can apply to:\n\n"
" * two line segments (parallel)\n"
" * a line segment and a normal (parallel)\n"
" * two normals (parallel)\n"
" * two line segments, arcs, or beziers, that share "
"an endpoint (tangent)\n"));
return;
}
AddConstraint(&c);
@ -701,11 +700,11 @@ void Constraint::MenuConstrain(Command id) {
c.entityA = gs.vector[0];
c.entityB = gs.vector[1];
} else {
Error("Bad selection for perpendicular constraint. This "
"constraint can apply to:\n\n"
" * two line segments\n"
" * a line segment and a normal\n"
" * two normals\n");
Error(_("Bad selection for perpendicular constraint. This "
"constraint can apply to:\n\n"
" * two line segments\n"
" * a line segment and a normal\n"
" * two normals\n"));
return;
}
AddConstraint(&c);
@ -716,9 +715,9 @@ void Constraint::MenuConstrain(Command id) {
c.type = Type::WHERE_DRAGGED;
c.ptA = gs.point[0];
} else {
Error("Bad selection for lock point where dragged constraint. "
"This constraint can apply to:\n\n"
" * a point\n");
Error(_("Bad selection for lock point where dragged constraint. "
"This constraint can apply to:\n\n"
" * a point\n"));
return;
}
AddConstraint(&c);
@ -727,7 +726,7 @@ void Constraint::MenuConstrain(Command id) {
case Command::COMMENT:
SS.GW.pending.operation = GraphicsWindow::Pending::COMMAND;
SS.GW.pending.command = Command::COMMENT;
SS.GW.pending.description = "click center of comment text";
SS.GW.pending.description = _("click center of comment text");
SS.ScheduleShowTW();
break;

View File

@ -15,8 +15,8 @@ void SolveSpaceUI::ExportSectionTo(const std::string &filename) {
Group *g = SK.GetGroup(SS.GW.activeGroup);
g->GenerateDisplayItems();
if(g->displayMesh.IsEmpty()) {
Error("No solid model present; draw one with extrudes and revolves, "
"or use Export 2d View to export bare lines and curves.");
Error(_("No solid model present; draw one with extrudes and revolves, "
"or use Export 2d View to export bare lines and curves."));
return;
}
@ -57,12 +57,12 @@ void SolveSpaceUI::ExportSectionTo(const std::string &filename) {
u = ut.WithMagnitude(1);
v = (n.Cross(u)).WithMagnitude(1);
} else {
Error("Bad selection for export section. Please select:\n\n"
" * nothing, with an active workplane "
"(workplane is section plane)\n"
" * a face (section plane through face)\n"
" * a point and two line segments "
"(plane through point and parallel to lines)\n");
Error(_("Bad selection for export section. Please select:\n\n"
" * nothing, with an active workplane "
"(workplane is section plane)\n"
" * a face (section plane through face)\n"
" * a point and two line segments "
"(plane through point and parallel to lines)\n"));
return;
}
SS.GW.ClearSelection();
@ -802,7 +802,7 @@ void SolveSpaceUI::ExportMeshTo(const std::string &filename) {
SMesh *m = &(SK.GetGroup(SS.GW.activeGroup)->displayMesh);
if(m->IsEmpty()) {
Error("Active group mesh is empty; nothing to export.");
Error(_("Active group mesh is empty; nothing to export."));
return;
}

View File

@ -327,9 +327,9 @@ public:
entity->setWidthMm(Style::WidthMm(hs.v));
if(s->stippleType == StipplePattern::FREEHAND) {
messages.insert("freehand lines were replaced with continuous lines");
messages.insert(_("freehand lines were replaced with continuous lines"));
} else if(s->stippleType == StipplePattern::ZIGZAG) {
messages.insert("zigzag lines were replaced with continuous lines");
messages.insert(_("zigzag lines were replaced with continuous lines"));
}
}
@ -580,8 +580,8 @@ void DxfFileWriter::FinishAndCloseFile() {
}
if(!interface.messages.empty()) {
std::string text = "Some aspects of the drawing have no DXF equivalent and "
"were not exported:\n";
std::string text = _("Some aspects of the drawing have no DXF equivalent and "
"were not exported:\n");
for(const std::string &message : interface.messages) {
text += " * " + message + "\n";
}
@ -797,8 +797,8 @@ void PdfFileWriter::StartFile() {
if((ptMax.x - ptMin.x) > 200*25.4 ||
(ptMax.y - ptMin.y) > 200*25.4)
{
Message("PDF page size exceeds 200 by 200 inches; many viewers may "
"reject this file.");
Message(_("PDF page size exceeds 200 by 200 inches; many viewers may "
"reject this file."));
}
fprintf(f,

View File

@ -40,7 +40,7 @@ hGroup SolveSpaceUI::CreateDefaultDrawingGroup() {
// And an empty group, for the first stuff the user draws.
g.visible = true;
g.name = "sketch-in-plane";
g.name = C_("group-name", "sketch-in-plane");
g.type = Group::Type::DRAWING_WORKPLANE;
g.subtype = Group::Subtype::WORKPLANE_BY_POINT_ORTHO;
g.order = 1;
@ -58,7 +58,7 @@ void SolveSpaceUI::NewFile() {
// Our initial group, that contains the references.
Group g = {};
g.visible = true;
g.name = "#references";
g.name = C_("group-name", "#references");
g.type = Group::Type::DRAWING_3D;
g.order = 0;
g.h = Group::HGROUP_REFERENCES;
@ -505,8 +505,8 @@ bool SolveSpaceUI::LoadFromFile(const std::string &filename, bool canCancel) {
fclose(fh);
if(fileLoadError) {
Error("Unrecognized data in file. This file may be corrupt, or "
"from a new version of the program.");
Error(_("Unrecognized data in file. This file may be corrupt, or "
"from a newer version of the program."));
// At least leave the program in a non-crashing state.
if(SK.group.n == 0) {
NewFile();

View File

@ -489,8 +489,7 @@ void GraphicsWindow::MenuView(Command id) {
case Command::SHOW_GRID:
SS.GW.showSnapGrid = !SS.GW.showSnapGrid;
if(SS.GW.showSnapGrid && !SS.GW.LockedInWorkplane()) {
Message("No workplane is active, so the grid will not "
"appear.");
Message(_("No workplane is active, so the grid will not appear."));
}
SS.GW.EnsureValidActives();
InvalidateGraphics();
@ -499,11 +498,11 @@ void GraphicsWindow::MenuView(Command id) {
case Command::PERSPECTIVE_PROJ:
SS.usePerspectiveProj = !SS.usePerspectiveProj;
if(SS.cameraTangent < 1e-6) {
Error("The perspective factor is set to zero, so the view will "
"always be a parallel projection.\n\n"
"For a perspective projection, modify the perspective "
"factor in the configuration screen. A value around 0.3 "
"is typical.");
Error(_("The perspective factor is set to zero, so the view will "
"always be a parallel projection.\n\n"
"For a perspective projection, modify the perspective "
"factor in the configuration screen. A value around 0.3 "
"is typical."));
}
SS.GW.EnsureValidActives();
InvalidateGraphics();
@ -580,8 +579,8 @@ void GraphicsWindow::MenuView(Command id) {
SS.GW.AnimateOnto(quat0, pt.ScaledBy(-1));
SS.GW.ClearSelection();
} else {
Error("Select a point; this point will become the center "
"of the view on screen.");
Error(_("Select a point; this point will become the center "
"of the view on screen."));
}
break;
@ -862,8 +861,7 @@ void GraphicsWindow::MenuEdit(Command id) {
}
} while(didSomething);
if(newlySelected == 0) {
Error("No additional entities share endpoints with the "
"selected entities.");
Error(_("No additional entities share endpoints with the selected entities."));
}
InvalidateGraphics();
SS.ScheduleShowTW();
@ -883,9 +881,9 @@ void GraphicsWindow::MenuEdit(Command id) {
hGroup hg = e ? e->group : SS.GW.activeGroup;
Group *g = SK.GetGroup(hg);
if(g->type != Group::Type::LINKED) {
Error("To use this command, select a point or other "
"entity from an linked part, or make a link "
"group the active group.");
Error(_("To use this command, select a point or other "
"entity from an linked part, or make a link "
"group the active group."));
break;
}
@ -907,16 +905,16 @@ void GraphicsWindow::MenuEdit(Command id) {
case Command::SNAP_TO_GRID: {
if(!SS.GW.LockedInWorkplane()) {
Error("No workplane is active. Activate a workplane "
"(with Sketch -> In Workplane) to define the plane "
"for the snap grid.");
Error(_("No workplane is active. Activate a workplane "
"(with Sketch -> In Workplane) to define the plane "
"for the snap grid."));
break;
}
SS.GW.GroupSelection();
if(SS.GW.gs.points == 0 && SS.GW.gs.constraintLabels == 0) {
Error("Can't snap these items to grid; select points, "
"text comments, or constraints with a label. "
"To snap a line, select its endpoints.");
Error(_("Can't snap these items to grid; select points, "
"text comments, or constraints with a label. "
"To snap a line, select its endpoints."));
break;
}
SS.UndoRemember();
@ -979,15 +977,15 @@ void GraphicsWindow::MenuRequest(Command id) {
} else if(g->type == Group::Type::DRAWING_WORKPLANE) {
// The group's default workplane
g->activeWorkplane = g->h.entity(0);
Message("No workplane selected. Activating default workplane "
"for this group.");
Message(_("No workplane selected. Activating default workplane "
"for this group."));
}
if(!SS.GW.LockedInWorkplane()) {
Error("No workplane is selected, and the active group does "
"not have a default workplane. Try selecting a "
"workplane, or activating a sketch-in-new-workplane "
"group.");
Error(_("No workplane is selected, and the active group does "
"not have a default workplane. Try selecting a "
"workplane, or activating a sketch-in-new-workplane "
"group."));
break;
}
// Align the view with the selected workplane
@ -1008,9 +1006,9 @@ void GraphicsWindow::MenuRequest(Command id) {
if(SS.GW.gs.n == 1 && SS.GW.gs.points == 1) {
SS.GW.MakeTangentArc();
} else if(SS.GW.gs.n != 0) {
Error("Bad selection for tangent arc at point. Select a "
"single point, or select nothing to set up arc "
"parameters.");
Error(_("Bad selection for tangent arc at point. Select a "
"single point, or select nothing to set up arc "
"parameters."));
} else {
SS.TW.GoToScreen(TextWindow::Screen::TANGENT_ARC);
SS.GW.ForceTextWindowShown();
@ -1019,15 +1017,16 @@ void GraphicsWindow::MenuRequest(Command id) {
}
break;
case Command::ARC: s = "click point on arc (draws anti-clockwise)"; goto c;
case Command::DATUM_POINT: s = "click to place datum point"; goto c;
case Command::LINE_SEGMENT: s = "click first point of line segment"; goto c;
case Command::CONSTR_SEGMENT: s = "click first point of construction line segment"; goto c;
case Command::CUBIC: s = "click first point of cubic segment"; goto c;
case Command::CIRCLE: s = "click center of circle"; goto c;
case Command::WORKPLANE: s = "click origin of workplane"; goto c;
case Command::RECTANGLE: s = "click one corner of rectangle"; goto c;
case Command::TTF_TEXT: s = "click top left of text"; goto c;
case Command::ARC: s = _("click point on arc (draws anti-clockwise)"); goto c;
case Command::DATUM_POINT: s = _("click to place datum point"); goto c;
case Command::LINE_SEGMENT: s = _("click first point of line segment"); goto c;
case Command::CONSTR_SEGMENT:
s = _("click first point of construction line segment"); goto c;
case Command::CUBIC: s = _("click first point of cubic segment"); goto c;
case Command::CIRCLE: s = _("click center of circle"); goto c;
case Command::WORKPLANE: s = _("click origin of workplane"); goto c;
case Command::RECTANGLE: s = _("click one corner of rectangle"); goto c;
case Command::TTF_TEXT: s = _("click top left of text"); goto c;
c:
SS.GW.pending.operation = GraphicsWindow::Pending::COMMAND;
SS.GW.pending.command = id;
@ -1040,8 +1039,8 @@ c:
SS.UndoRemember();
SS.GW.GroupSelection();
if(SS.GW.gs.entities == 0) {
Error("No entities are selected. Select entities before "
"trying to toggle their construction state.");
Error(_("No entities are selected. Select entities before "
"trying to toggle their construction state."));
}
int i;
for(i = 0; i < SS.GW.gs.entities; i++) {

View File

@ -86,12 +86,12 @@ void Group::MenuGroup(Command id) {
switch(id) {
case Command::GROUP_3D:
g.type = Type::DRAWING_3D;
g.name = "sketch-in-3d";
g.name = C_("group-name", "sketch-in-3d");
break;
case Command::GROUP_WRKPL:
g.type = Type::DRAWING_WORKPLANE;
g.name = "sketch-in-plane";
g.name = C_("group-name", "sketch-in-plane");
if(gs.points == 1 && gs.n == 1) {
g.subtype = Subtype::WORKPLANE_BY_POINT_ORTHO;
@ -142,28 +142,28 @@ void Group::MenuGroup(Command id) {
} else ssassert(false, "Unexpected workplane subtype");
}
} else {
Error("Bad selection for new sketch in workplane. This "
"group can be created with:\n\n"
" * a point (through the point, orthogonal to coordinate axes)\n"
" * a point and two line segments (through the point, "
"parallel to the lines)\n"
" * a workplane (copy of the workplane)\n");
Error(_("Bad selection for new sketch in workplane. This "
"group can be created with:\n\n"
" * a point (through the point, orthogonal to coordinate axes)\n"
" * a point and two line segments (through the point, "
"parallel to the lines)\n"
" * a workplane (copy of the workplane)\n"));
return;
}
break;
case Command::GROUP_EXTRUDE:
if(!SS.GW.LockedInWorkplane()) {
Error("Activate a workplane (Sketch -> In Workplane) before "
"extruding. The sketch will be extruded normal to the "
"workplane.");
Error(_("Activate a workplane (Sketch -> In Workplane) before "
"extruding. The sketch will be extruded normal to the "
"workplane."));
return;
}
g.type = Type::EXTRUDE;
g.opA = SS.GW.activeGroup;
g.predef.entityB = SS.GW.ActiveWorkplane();
g.subtype = Subtype::ONE_SIDED;
g.name = "extrude";
g.name = C_("group-name", "extrude");
break;
case Command::GROUP_LATHE:
@ -175,17 +175,17 @@ void Group::MenuGroup(Command id) {
g.predef.entityB = gs.entity[0];
// since a line segment is a vector
} else {
Error("Bad selection for new lathe group. This group can "
"be created with:\n\n"
" * a point and a line segment or normal "
"(revolved about an axis parallel to line / "
"normal, through point)\n"
" * a line segment (revolved about line segment)\n");
Error(_("Bad selection for new lathe group. This group can "
"be created with:\n\n"
" * a point and a line segment or normal "
"(revolved about an axis parallel to line / "
"normal, through point)\n"
" * a line segment (revolved about line segment)\n"));
return;
}
g.type = Type::LATHE;
g.opA = SS.GW.activeGroup;
g.name = "lathe";
g.name = C_("group-name", "lathe");
break;
case Command::GROUP_ROT: {
@ -198,20 +198,20 @@ void Group::MenuGroup(Command id) {
g.predef.origin = gs.point[0];
g.predef.entityB = gs.vector[0];
} else {
Error("Bad selection for new rotation. This group can "
"be created with:\n\n"
" * a point, while locked in workplane (rotate "
"in plane, about that point)\n"
" * a point and a line or a normal (rotate about "
"an axis through the point, and parallel to "
"line / normal)\n");
Error(_("Bad selection for new rotation. This group can "
"be created with:\n\n"
" * a point, while locked in workplane (rotate "
"in plane, about that point)\n"
" * a point and a line or a normal (rotate about "
"an axis through the point, and parallel to "
"line / normal)\n"));
return;
}
g.type = Type::ROTATE;
g.opA = SS.GW.activeGroup;
g.valA = 3;
g.subtype = Subtype::ONE_SIDED;
g.name = "rotate";
g.name = C_("group-name", "rotate");
break;
}
@ -222,7 +222,7 @@ void Group::MenuGroup(Command id) {
g.subtype = Subtype::ONE_SIDED;
g.predef.entityB = SS.GW.ActiveWorkplane();
g.activeWorkplane = SS.GW.ActiveWorkplane();
g.name = "translate";
g.name = C_("group-name", "translate");
break;
case Command::GROUP_LINK: {
@ -254,7 +254,7 @@ void Group::MenuGroup(Command id) {
if(groupName.length() > 0) {
g.name = groupName;
} else {
g.name = "link";
g.name = C_("group-name", "link");
}
g.meshCombine = CombineAs::ASSEMBLE;
@ -336,7 +336,7 @@ void Group::TransformImportedBy(Vector t, Quaternion q) {
std::string Group::DescriptionString() {
if(name.empty()) {
return ssprintf("g%03x-(unnamed)", h.v);
return ssprintf("g%03x-%s", h.v, _("(unnamed)"));
} else {
return ssprintf("g%03x-%s", h.v, name.c_str());
}

View File

@ -604,7 +604,8 @@ void Group::DrawPolyError(Canvas *canvas) {
// Report this error only in sketch-in-workplane groups; otherwise
// it's just a nuisance.
if(type == Type::DRAWING_WORKPLANE) {
canvas->DrawVectorText("not closed contour, or not all same style!", textHeight,
canvas->DrawVectorText(_("not closed contour, or not all same style!"),
textHeight,
polyError.notClosedAt.b, camera.projRight, camera.projUp,
hcsError);
canvas->DrawLine(polyError.notClosedAt.a, polyError.notClosedAt.b, hcsUnclosed);
@ -616,11 +617,11 @@ void Group::DrawPolyError(Canvas *canvas) {
if(type == Type::DRAWING_WORKPLANE) {
const char *msg;
if(polyError.how == PolyError::NOT_COPLANAR) {
msg = "points not all coplanar!";
msg = _("points not all coplanar!");
} else if(polyError.how == PolyError::SELF_INTERSECTING) {
msg = "contour is self-intersecting!";
msg = _("contour is self-intersecting!");
} else {
msg = "zero-length edge!";
msg = _("zero-length edge!");
}
canvas->DrawVectorText(msg, textHeight,
polyError.errorPointAt, camera.projRight, camera.projUp,

View File

@ -234,8 +234,7 @@ void GraphicsWindow::ParametricCurve::ConstrainPointIfCoincident(hEntity hpt) {
//-----------------------------------------------------------------------------
void GraphicsWindow::MakeTangentArc() {
if(!LockedInWorkplane()) {
Error("Must be sketching in workplane to create tangent "
"arc.");
Error(_("Must be sketching in workplane to create tangent arc."));
return;
}
@ -282,9 +281,9 @@ void GraphicsWindow::MakeTangentArc() {
}
}
if(c != 2) {
Error("To create a tangent arc, select a point where two "
"non-construction lines or circles in this group and "
"workplane join.");
Error(_("To create a tangent arc, select a point where two "
"non-construction lines or circles in this group and "
"workplane join."));
return;
}
@ -369,9 +368,9 @@ void GraphicsWindow::MakeTangentArc() {
t[0] > 0.99 || t[1] > 0.99 ||
isnan(t[0]) || isnan(t[1]))
{
Error("Couldn't round this corner. Try a smaller radius, or try "
"creating the desired geometry by hand with tangency "
"constraints.");
Error(_("Couldn't round this corner. Try a smaller radius, or try "
"creating the desired geometry by hand with tangency "
"constraints."));
return;
}
@ -573,7 +572,7 @@ hEntity GraphicsWindow::SplitEntity(hEntity he, Vector pinter) {
} else if(e->type == Entity::Type::CUBIC || e->type == Entity::Type::CUBIC_PERIODIC) {
ret = SplitCubic(he, pinter);
} else {
Error("Couldn't split this entity; lines, circles, or cubics only.");
Error(_("Couldn't split this entity; lines, circles, or cubics only."));
return Entity::NO_ENTITY;
}
@ -599,7 +598,7 @@ hEntity GraphicsWindow::SplitEntity(hEntity he, Vector pinter) {
void GraphicsWindow::SplitLinesOrCurves() {
if(!LockedInWorkplane()) {
Error("Must be sketching in workplane to split.");
Error(_("Must be sketching in workplane to split."));
return;
}
@ -609,8 +608,8 @@ void GraphicsWindow::SplitLinesOrCurves() {
gs.cubics +
gs.periodicCubics) == 2))
{
Error("Select two entities that intersect each other (e.g. two lines "
"or two circles or a circle and a line).");
Error(_("Select two entities that intersect each other (e.g. two lines "
"or two circles or a circle and a line)."));
return;
}
@ -653,7 +652,7 @@ void GraphicsWindow::SplitLinesOrCurves() {
Constraint::ConstrainCoincident(hia, hib);
}
} else {
Error("Can't split; no intersection found.");
Error(_("Can't split; no intersection found."));
}
// All done, clean up and regenerate.

View File

@ -775,7 +775,7 @@ void GraphicsWindow::MouseRightUp(double x, double y) {
SS.MarkGroupDirtyByEntity(gs.entity[0]);
ClearSelection();
} else {
Error("Cannot add spline point: maximum number of points reached.");
Error(_("Cannot add spline point: maximum number of points reached."));
}
break;
}
@ -945,14 +945,14 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
pending.operation = Pending::DRAGGING_NEW_LINE_POINT;
pending.request = hr;
pending.point = hr.entity(2);
pending.description = "click next point of line, or press Esc";
pending.description = _("click next point of line, or press Esc");
SK.GetEntity(pending.point)->PointForceTo(v);
break;
case Command::RECTANGLE: {
if(!SS.GW.LockedInWorkplane()) {
Error("Can't draw rectangle in 3d; first, activate a workplane "
"with Sketch -> In Workplane.");
Error(_("Can't draw rectangle in 3d; first, activate a workplane "
"with Sketch -> In Workplane."));
ClearSuper();
break;
}
@ -978,7 +978,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
pending.operation = Pending::DRAGGING_NEW_POINT;
pending.point = lns[1].entity(2);
pending.description = "click to place other corner of rectangle";
pending.description = _("click to place other corner of rectangle");
hr = lns[0];
break;
}
@ -998,13 +998,13 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
pending.operation = Pending::DRAGGING_NEW_RADIUS;
pending.circle = hr.entity(0);
pending.description = "click to set radius";
pending.description = _("click to set radius");
break;
case Command::ARC: {
if(!SS.GW.LockedInWorkplane()) {
Error("Can't draw arc in 3d; first, activate a workplane "
"with Sketch -> In Workplane.");
Error(_("Can't draw arc in 3d; first, activate a workplane "
"with Sketch -> In Workplane."));
ClearPending();
break;
}
@ -1021,7 +1021,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
pending.operation = Pending::DRAGGING_NEW_ARC_POINT;
pending.point = hr.entity(3);
pending.description = "click to place point";
pending.description = _("click to place point");
break;
}
case Command::CUBIC:
@ -1036,13 +1036,13 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
pending.operation = Pending::DRAGGING_NEW_CUBIC_POINT;
pending.point = hr.entity(4);
pending.description = "click next point of cubic, or press Esc";
pending.description = _("click next point of cubic, or press Esc");
break;
case Command::WORKPLANE:
if(LockedInWorkplane()) {
Error("Sketching in a workplane already; sketch in 3d before "
"creating new workplane.");
Error(_("Sketching in a workplane already; sketch in 3d before "
"creating new workplane."));
ClearSuper();
break;
}
@ -1057,8 +1057,8 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
case Command::TTF_TEXT: {
if(!SS.GW.LockedInWorkplane()) {
Error("Can't draw text in 3d; first, activate a workplane "
"with Sketch -> In Workplane.");
Error(_("Can't draw text in 3d; first, activate a workplane "
"with Sketch -> In Workplane."));
ClearSuper();
break;
}
@ -1072,7 +1072,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
pending.operation = Pending::DRAGGING_NEW_POINT;
pending.point = hr.entity(2);
pending.description = "click to place bottom left of text";
pending.description = _("click to place bottom left of text");
break;
}
@ -1083,7 +1083,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
c.workplane = SS.GW.ActiveWorkplane();
c.type = Constraint::Type::COMMENT;
c.disp.offset = v;
c.comment = "NEW COMMENT -- DOUBLE-CLICK TO EDIT";
c.comment = _("NEW COMMENT -- DOUBLE-CLICK TO EDIT");
hc = Constraint::AddConstraint(&c);
break;
}
@ -1196,7 +1196,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
pending.operation = Pending::DRAGGING_NEW_LINE_POINT;
pending.request = hr;
pending.point = hr.entity(2);
pending.description = "click next point of line, or press Esc";
pending.description = _("click next point of line, or press Esc");
break;
}

View File

@ -1254,6 +1254,25 @@ unsigned PluralExpr::Eval(const std::string &s, unsigned n) {
return t.value;
}
//-----------------------------------------------------------------------------
// Gettext message keys
//-----------------------------------------------------------------------------
class TranslationKey {
public:
bool hasContext;
std::string context;
std::string ident;
};
struct TranslationKeyLess {
bool operator()(const TranslationKey &a, const TranslationKey &b) const {
return a.hasContext < b.hasContext ||
(a.hasContext == b.hasContext && a.context < b.context) ||
(a.hasContext == b.hasContext && a.context == b.context && a.ident < b.ident);
}
};
//-----------------------------------------------------------------------------
// Gettext .po file parsing
//-----------------------------------------------------------------------------
@ -1265,7 +1284,7 @@ public:
unsigned pluralCount;
std::string pluralExpr;
std::map<std::string, std::vector<std::string>> messages;
std::map<TranslationKey, std::vector<std::string>, TranslationKeyLess> messages;
void SkipSpace();
std::string ReadString();
@ -1342,11 +1361,18 @@ void GettextParser::Parse() {
SkipSpace();
while(!reader.AtEnd()) {
TranslationKey key = {};
if(reader.TryString("msgctxt")) {
key.hasContext = true;
key.context = ReadString();
}
reader.ExpectString("msgid");
std::string msgid = ReadString();
key.ident = ReadString();
if(reader.TryString("msgid_plural")) {
std::string _msgid_plural = ReadString();
// We don't need it.
ReadString(); // we don't need it
}
std::vector<std::string> msgstrs;
@ -1364,7 +1390,7 @@ void GettextParser::Parse() {
}
}
if(msgid == "") {
if(key.ident == "") {
ssassert(msgstrs.size() == 1,
"Expected exactly one header msgstr");
ParseHeader(msgstrs[0]);
@ -1372,7 +1398,7 @@ void GettextParser::Parse() {
ssassert(msgstrs.size() == 1 ||
msgstrs.size() == pluralCount,
"Expected msgstr count to match plural form count");
messages.emplace(msgid, msgstrs);
messages.emplace(key, msgstrs);
}
}
}
@ -1386,12 +1412,12 @@ public:
unsigned pluralCount;
std::string pluralExpr;
std::map<std::string, std::vector<std::string>> messages;
std::map<TranslationKey, std::vector<std::string>, TranslationKeyLess> messages;
static Translation From(const std::string &poData);
const std::string &Translate(const char *msgid);
const std::string &TranslatePlural(const char *msgid, unsigned n);
const std::string &Translate(const TranslationKey &key);
const std::string &TranslatePlural(const TranslationKey &key, unsigned n);
};
Translation Translation::From(const std::string &poData) {
@ -1406,28 +1432,28 @@ Translation Translation::From(const std::string &poData) {
return trans;
}
const std::string &Translation::Translate(const char *msgid) {
auto it = messages.find(msgid);
const std::string &Translation::Translate(const TranslationKey &key) {
auto it = messages.find(key);
if(it == messages.end()) {
dbp("Missing translation for '%s'", msgid);
messages[msgid].emplace_back(msgid);
it = messages.find(msgid);
dbp("Missing translation for %s'%s'", key.context.c_str(), key.ident.c_str());
messages[key].emplace_back(key.ident);
it = messages.find(key);
}
if(it->second.size() != 1) {
dbp("Incorrect use of translated message '%s'", msgid);
dbp("Incorrect use of translated message %s'%s'", key.context.c_str(), key.ident.c_str());
ssassert(false, "Using a message with a plural form without a number");
}
return it->second[0];
}
const std::string &Translation::TranslatePlural(const char *msgid, unsigned n) {
auto it = messages.find(msgid);
const std::string &Translation::TranslatePlural(const TranslationKey &key, unsigned n) {
auto it = messages.find(key);
if(it == messages.end()) {
dbp("Missing translation for '%s'", msgid);
dbp("Missing translation for %s'%s'", key.context.c_str(), key.ident.c_str());
for(unsigned i = 0; i < pluralCount; i++) {
messages[msgid].emplace_back(msgid);
messages[key].emplace_back(key.ident);
}
it = messages.find(msgid);
it = messages.find(key);
}
unsigned pluralForm = PluralExpr::Eval(pluralExpr, n);
return it->second[pluralForm];
@ -1501,11 +1527,31 @@ bool SetLocale(uint16_t lcid) {
}
const std::string &Translate(const char *msgid) {
return currentTranslation->Translate(msgid);
TranslationKey key = {};
key.ident = msgid;
return currentTranslation->Translate(key);
}
const std::string &Translate(const char *msgctxt, const char *msgid) {
TranslationKey key = {};
key.hasContext = true;
key.context = msgctxt;
key.ident = msgid;
return currentTranslation->Translate(key);
}
const std::string &TranslatePlural(const char *msgid, unsigned n) {
return currentTranslation->TranslatePlural(msgid, n);
TranslationKey key = {};
key.ident = msgid;
return currentTranslation->TranslatePlural(key, n);
}
const std::string &TranslatePlural(const char *msgctxt, const char *msgid, unsigned n) {
TranslationKey key = {};
key.hasContext = true;
key.context = msgctxt;
key.ident = msgid;
return currentTranslation->TranslatePlural(key, n);
}
}

View File

@ -476,10 +476,10 @@ void SolveSpaceUI::MenuFile(Command id) {
(FilenameHasExtension(exportFile, ".txt") ||
fabs(SS.exportOffset) > LENGTH_EPS))
{
Message("Constraints are currently shown, and will be exported "
"in the toolpath. This is probably not what you want; "
"hide them by clicking the link at the top of the "
"text window.");
Message(_("Constraints are currently shown, and will be exported "
"in the toolpath. This is probably not what you want; "
"hide them by clicking the link at the top of the "
"text window."));
}
SS.ExportViewOrWireframeTo(exportFile, /*exportWireframe*/false);
@ -583,11 +583,11 @@ void SolveSpaceUI::MenuAnalyze(Command id) {
SS.ScheduleShowTW();
SS.GW.ClearSelection();
} else {
Error("Constraint must have a label, and must not be "
"a reference dimension.");
Error(_("Constraint must have a label, and must not be "
"a reference dimension."));
}
} else {
Error("Bad selection for step dimension; select a constraint.");
Error(_("Bad selection for step dimension; select a constraint."));
}
break;
@ -611,7 +611,7 @@ void SolveSpaceUI::MenuAnalyze(Command id) {
Error("%d edges interfere with other triangles, bad.",
SS.nakedEdges.l.n);
} else {
Message("The assembly does not interfere, good.");
Message(_("The assembly does not interfere, good."));
}
break;
}
@ -688,9 +688,9 @@ void SolveSpaceUI::MenuAnalyze(Command id) {
case Command::AREA: {
Group *g = SK.GetGroup(SS.GW.activeGroup);
if(g->polyError.how != PolyError::GOOD) {
Error("This group does not contain a correctly-formed "
"2d closed area. It is open, not coplanar, or self-"
"intersecting.");
Error(_("This group does not contain a correctly-formed "
"2d closed area. It is open, not coplanar, or self-"
"intersecting."));
break;
}
SEdgeList sel = {};
@ -731,7 +731,7 @@ void SolveSpaceUI::MenuAnalyze(Command id) {
perimeter / scale,
SS.UnitName());
} else {
Error("Bad selection for perimeter; select line segments, arcs, and curves.");
Error(_("Bad selection for perimeter; select line segments, arcs, and curves."));
}
break;
}
@ -747,7 +747,7 @@ void SolveSpaceUI::MenuAnalyze(Command id) {
SS.traced.point = gs.point[0];
SS.GW.ClearSelection();
} else {
Error("Bad selection for trace; select a single point.");
Error(_("Bad selection for trace; select a single point."));
}
break;

View File

@ -158,8 +158,8 @@ void Style::AssignSelectionToStyle(uint32_t v) {
}
if(showError) {
Error("Can't assign style to an entity that's derived from another "
"entity; try assigning a style to this entity's parent.");
Error(_("Can't assign style to an entity that's derived from another "
"entity; try assigning a style to this entity's parent."));
}
SS.GW.ClearSelection();
@ -695,13 +695,13 @@ bool TextWindow::EditControlDoneForStyles(const char *str) {
SS.backgroundColor = RGBf(rgb.x, rgb.y, rgb.z);
}
} else {
Error("Bad format: specify color as r, g, b");
Error(_("Bad format: specify color as r, g, b"));
}
break;
}
case Edit::STYLE_NAME:
if(!*str) {
Error("Style name cannot be empty");
Error(_("Style name cannot be empty"));
} else {
SS.UndoRemember();
s = Style::Get(edit.style);
@ -714,7 +714,7 @@ bool TextWindow::EditControlDoneForStyles(const char *str) {
if(e) {
double ev = e->Eval();
if(ev < 0.001 || isnan(ev)) {
Error("Scale must not be zero or negative!");
Error(_("Scale must not be zero or negative!"));
} else {
SS.bgImage.scale = ev / SS.MmPerUnit();
}

View File

@ -654,11 +654,11 @@ void TextWindow::EditControlDone(const char *s) {
double ev = e->Eval();
if((int)ev < 1) {
Error("Can't repeat fewer than 1 time.");
Error(_("Can't repeat fewer than 1 time."));
break;
}
if((int)ev > 999) {
Error("Can't repeat more than 999 times.");
Error(_("Can't repeat more than 999 times."));
break;
}
@ -687,7 +687,7 @@ void TextWindow::EditControlDone(const char *s) {
}
case Edit::GROUP_NAME: {
if(!*s) {
Error("Group name cannot be empty");
Error(_("Group name cannot be empty"));
} else {
SS.UndoRemember();
@ -701,7 +701,7 @@ void TextWindow::EditControlDone(const char *s) {
if(e) {
double ev = e->Eval();
if(fabs(ev) < 1e-6) {
Error("Scale cannot be zero.");
Error(_("Scale cannot be zero."));
} else {
Group *g = SK.GetGroup(edit.group);
g->scale = ev;
@ -722,7 +722,7 @@ void TextWindow::EditControlDone(const char *s) {
SS.MarkGroupDirty(g->h);
SS.GW.ClearSuper();
} else {
Error("Bad format: specify color as r, g, b");
Error(_("Bad format: specify color as r, g, b"));
}
break;
}
@ -731,7 +731,7 @@ void TextWindow::EditControlDone(const char *s) {
if(e) {
double alpha = e->Eval();
if(alpha < 0 || alpha > 1) {
Error("Opacity must be between zero and one.");
Error(_("Opacity must be between zero and one."));
} else {
Group *g = SK.GetGroup(edit.group);
g->color.alpha = (int)(255.1f * alpha);
@ -770,7 +770,7 @@ void TextWindow::EditControlDone(const char *s) {
Expr *e = Expr::From(s, /*popUpError=*/true);
if(!e) break;
if(e->Eval() < LENGTH_EPS) {
Error("Radius cannot be zero or negative.");
Error(_("Radius cannot be zero or negative."));
break;
}
SS.tangentArcRadius = SS.ExprToMm(e);

View File

@ -32,10 +32,31 @@ bool SetLocale(const std::string &name);
bool SetLocale(uint16_t lcid);
const std::string &Translate(const char *msgid);
const std::string &Translate(const char *msgctxt, const char *msgid);
const std::string &TranslatePlural(const char *msgid, unsigned n);
const std::string &TranslatePlural(const char *msgctxt, const char *msgid, unsigned n);
inline const char *N_(const char *msgid) { return msgid; }
inline const char *_(const char *msgid) { return Translate(msgid).c_str(); }
inline const char *N_(const char *msgid) {
return msgid;
}
inline const char *CN_(const char *msgctxt, const char *msgid) {
return msgid;
}
#if defined(LIBRARY)
inline const char *_(const char *msgid) {
return msgid;
}
inline const char *C_(const char *msgctxt, const char *msgid) {
return msgid;
}
#else
inline const char *_(const char *msgid) {
return Translate(msgid).c_str();
}
inline const char *C_(const char *msgctxt, const char *msgid) {
return Translate(msgctxt, msgid).c_str();
}
#endif
// This table describes the top-level menus in the graphics winodw.
enum class Command : uint32_t {

View File

@ -75,7 +75,7 @@ bool TextWindow::EditControlDoneForView(const char *s) {
if(v > LENGTH_EPS) {
SS.GW.scale = v;
} else {
Error("Scale cannot be zero or negative.");
Error(_("Scale cannot be zero or negative."));
}
}
break;
@ -87,7 +87,7 @@ bool TextWindow::EditControlDoneForView(const char *s) {
pt = pt.ScaledBy(SS.MmPerUnit());
SS.GW.offset = pt.ScaledBy(-1);
} else {
Error("Bad format: specify x, y, z");
Error(_("Bad format: specify x, y, z"));
}
break;
}
@ -96,7 +96,7 @@ bool TextWindow::EditControlDoneForView(const char *s) {
case Edit::VIEW_PROJ_UP: {
Vector pt;
if(sscanf(s, "%lf, %lf, %lf", &pt.x, &pt.y, &pt.z) != 3) {
Error("Bad format: specify x, y, z");
Error(_("Bad format: specify x, y, z"));
break;
}
if(edit.meaning == Edit::VIEW_PROJ_RIGHT) {